init: add workspace files

This commit is contained in:
2026-05-26 16:41:20 +08:00
commit f4f2393f72
1041 changed files with 67405 additions and 0 deletions

234
os/char/chara_comm.js Normal file
View File

@@ -0,0 +1,234 @@
require("./character");
var level_descs = ["普通百姓", "武士", "武师", "宗师", "武圣", "武帝", "武神"];
var level_color = ["", "wht", "hig", "hiy", "hiz", "hio", "ord"];
CHARACTER.prototype.get_level_desc = function () {
if (!this.level) return level_descs[this.level];
var cc = level_color[this.level];
return "<" + cc + ">" + level_descs[this.level] + "</" + cc + ">";
}
CHARACTER.prototype.get_level_color = function () {
return level_color[this.level];
}
//发送给当前对象的消息
CHARACTER.prototype.long_name = function () {
if (this.title) return this.title + " " + this.name;
return this.name;
}
CHARACTER.prototype.query_title = function () {
return this.title;
}
CHARACTER.prototype.query_age = function () {
return this.age;
}
CHARACTER.prototype.call = function (isbad) {
return this.family.call(this, isbad);
}
CHARACTER.prototype.callme = function (isbad) {
return this.family.call_me(this);
}
CHARACTER.prototype.fam_call = function (target) {
let age1 = target.query_age();
let age2 = this.query_age();
if (age1 < age2) {
return this.gender === 1 ? "师兄" : "师姐";
}
return this.gender === 1 ? "师弟" : "师妹";
}
CHARACTER.prototype.call3 = function () {
return this.gender == 1 ? "他" : "她";
}
CHARACTER.prototype.is_hidden = function () {
return this.hp <= 0 || this.query_temp('hidden');
}
CHARACTER.prototype.is_team = function (p) {
if (!p) return false;
if (p.team)
return this.team == p.team;
return this.family == p.family;
}
CHARACTER.prototype.send_team = function (msg, nome) {
if (!this.team) return this.send(msg);
for (var i = 0; i < this.team.length; i++) {
if (nome && this.team[i] == this) continue;
this.team[i].send(msg);
}
}
CHARACTER.prototype.query_teamid = function () {
if (this.follow_target) return this.follow_target.query_teamid();
return null;
}
CHARACTER.prototype.query_status = function () {
var ary = ["{type:\"status\",hp:"];
ary.push(this.hp);
ary.push(",max_hp:");
ary.push(this.max_hp);
ary.push(",mp:");
ary.push(this.mp);
ary.push(",max_mp:");
ary.push(this.max_mp);
ary.push(",name:\"");
ary.push(this.name);
ary.push("\",id:\"");
ary.push(this.id);
ary.push("\"}");
return ary.join("");
}
CHARACTER.prototype.query_commands = function () {
}
CHARACTER.prototype.query_desc = function (me, eqcmd) {
var str = [];
str.push(this.long_name());
str.push("\n");
var call3 = this == me ? "你" : this.call3();
str.push(call3, "看起来约", get_agestr(this.query_age()), "岁。\n");
str.push(call3, "长得", get_perdesc(this), "。\n");
str.push(call3, get_skill_desc(this.query_skill(this.attack_skill.id)), "。\n");
str.push(call3, get_status(this), "\n");
this.format_equipments(call3, str, eqcmd);
return str.join("");
}
CHARACTER.prototype.format_equipments = function (call3, str, eqcmd) {
if (this.query_setting("hide_equip")) {
return str.push("看样子", call3, "不想让别人看自己的装备。");
} else if (this.equipment && this.equipment.length) {
var eqstr = [];
for (var i = 0; i < this.equipment.length; i++) {
var item = this.equipment[i];
if (!item) continue;
eqstr.push("<span cmd='", eqcmd || "look", " ", (i),
" of ", this.id, "'>◆", item.color_name, "</span>\n");
}
if (eqstr.length) {
return str.push(call3, "装备着:\n", eqstr.join(""));
}
}
str.push(call3, "光着身子,什么都没穿。\n");
}
function get_perdesc(obj) {
var ary = obj.gender === 1 ? boy_pers : girl_pers;
var per = obj.per + obj.query_prop("per");
var index = parseInt(per / 2);
if (index < 0) index = 0;
if (index >= ary.length) index = ary.length - 1;
return ary[index];
}
function get_agestr(age) {
var index = parseInt((age || 10) / 10);
if (index >= age_strs.length) index = age_strs.length - 1;
return age_strs[index];
}
function get_skill_desc(level) {
if (!level) return "看上去似乎不会任何武功。";
if (level < 1000)
return "的武功看上去似乎" + skill_levels[parseInt(level / 50)];
var v = parseInt((level - 1000) / 500);
if (v > 6) v = 6;
return "的武功看上去似乎" + skill_levels[v + 20];
}
function get_status(obj) {
var p = parseInt(obj.hp * 10 / obj.max_hp);
if (p < 0) p = 0;
if (p >= Look_status.length) p = Look_status.length - 1;
return Look_status[p];
}
var boy_pers = [
"<BLU>眉歪眼斜,瘌头癣脚,不象人样</BLU>",
"<BLU>呲牙咧嘴,黑如锅底,奇丑无比</BLU>",
"<BLU>面如桔皮,头肿如猪,让人不想再看第二眼</BLU>",
"<HIB>贼眉鼠眼,身高三尺,宛若猴状</HIB>",
"<HIB>肥头大耳,腹圆如鼓,手脚短粗,令人发笑</HIB>",
"<NOR>面颊凹陷,瘦骨伶仃,可怜可叹</NOR>",
"<NOR>傻头傻脑,痴痴憨憨,看来倒也老实</NOR>",
"<NOR>相貌平平,不会给人留下什么印象</NOR>",
"<YEL>膀大腰圆,满脸横肉,恶形恶相</YEL>",
"<YEL>腰圆背厚,面阔口方,骨格不凡</YEL>",
"<RED>眉目清秀,端正大方,一表人才</RED>",
"<RED>双眼光华莹润,透出摄人心魄的光芒</RED>",
"<HIY>举动如行云游水,独蕴风情,吸引所有异性目光</HIY>",
"<HIY>双目如星,眉梢传情,所见者无不为之心动</HIY>",
"<HIR>粉面朱唇,身姿俊俏,举止风流无限</HIR>",
"<HIR>丰神如玉,目似朗星,令人过目难忘</HIR>",
"<MAG>面如美玉,粉妆玉琢,俊美不凡</MAG>",
"<MAG>飘逸出尘,潇洒绝伦</MAG>",
"<MAG>丰神俊朗,长身玉立,宛如玉树临风</MAG>",
"<HIM>神清气爽,骨格清奇,宛若仙人</HIM>",
"<HIM>一派神人气度,仙风道骨,举止出尘</HIM>"
];
var girl_pers = [
"<BLU>丑如无盐,状如夜叉</BLU>",
"<BLU>歪鼻斜眼,脸色灰败,直如鬼怪一般</BLU>",
"<BLU>八字眉,三角眼,鸡皮黄发,让人一见就想吐</BLU>",
"<HIB>眼小如豆,眉毛稀疏,手如猴爪,不成人样</HIB>",
"<HIB>一嘴大暴牙,让人一看就没好感</HIB>",
"<NOR>满脸疙瘩,皮色粗黑,丑陋不堪</NOR>",
"<NOR>干黄枯瘦,脸色腊黄,毫无女人味</NOR>",
"<YEL>身材瘦小,肌肤无光,两眼无神</YEL>",
"<YEL>虽不标致,倒也白净,有些动人之处</YEL>",
"<RED>肌肤微丰,雅淡温宛,清新可人</RED>",
"<RED>鲜艳妍媚,肌肤莹透,引人遐思</RED>",
"<HIR>娇小玲珑,宛如飞燕再世,楚楚动人</HIR>",
"<HIR>腮凝新荔,肌肤胜雪,目若秋水</HIR>",
"<HIW>粉嫩白至,如芍药笼烟,雾里看花</HIW>",
"<HIW>丰胸细腰,妖娆多姿,让人一看就心跳不已</HIW>",
"<MAG>娇若春花,媚如秋月,真的能沉鱼落雁</MAG>",
"<MAG>眉目如画,肌肤胜雪,真可谓闭月羞花</MAG>",
"<MAG>气质美如兰,才华馥比山,令人见之忘俗</MAG>",
"<HIM>灿若明霞,宝润如玉,恍如神妃仙子</HIM>",
"<HIM>美若天仙,不沾一丝烟尘</HIM>",
"<HIM>宛如<HIW>玉雕冰塑</HIW>,似梦似幻,已不再是凡间人物</HIM>"
];
var Look_status = [
"<HIR>受伤过重,已经有如风中残烛,随时都可能断气。</HIR>",
"<HIR>受伤过重,已经奄奄一息,命在旦夕了。</HIR>",
"<HIR>伤重之下已经难以支撑,眼看就要倒在地上。</HIR>",
"<RED>受了相当重的伤,只怕会有生命危险。</RED>",
"<RED>已经伤痕累累,正在勉力支撑著不倒下去。</RED>",
"<RED>气息粗重,动作开始散乱,看来所受的伤著实不轻。</RED>",
"<HIY>受伤不轻,看起来状况并不太好。</HIY>",
"<HIY>受了几处伤,不过似乎并不碍事。</HIY>",
"<HIY>看起来可能受了点轻伤。</HIY>",
"<HIG>似乎受了点轻伤,不过光从外表看不大出来。</HIG>",
"<HIG>看起来气血充盈,并没有受伤。</HIG>"
];
var age_strs = ["几", "十多", "二十多", "三十多", "四十多", "五十多", "六十多", "七十多", "八十多", "九十多"
, "一百多"];
var skill_levels = [
"<BLU>初学乍练</BLU>",
"<BLU>不知所以</BLU>",
"<HIB>粗通皮毛</HIB>",
"<HIB>渐有所悟</HIB>",
"<YEL>半生不熟</YEL>",
"<YEL>马马虎虎</YEL>",
"<HIY>平淡无奇</HIY>",
"<HIY>触类旁通</HIY>",
"<HIG>心领神会</HIG>",
"<HIG>挥洒自如</HIG>",
"<HIC>驾轻就熟</HIC>",
"<HIC>出类拔萃</HIC>",
"<CYN>初入佳境</CYN>",
"<CYN>神乎其技</CYN>",
"<MAG>威不可当</MAG>",
"<HIW>豁然贯通</HIW>",
"<HIW>超群绝伦</HIW>",
"<RED>登峰造极</RED>",
"<WHT>登堂入室</WHT>",
"<HIM>一代宗师</HIM>",
"<WHT>超凡入圣</WHT>",
"<HIO>出神入化</HIO>",
"<HIO>独步天下</HIO>",
"<HIR>空前绝后</HIR>",
"<HIR>旷古绝伦</HIR>",
"<HIW>深不可测</HIW>",
"<HIW>返璞归真</HIW>"];

175
os/char/chara_equip.js Normal file
View File

@@ -0,0 +1,175 @@
require("./character.js");
CHARACTER.prototype.set_objects = function () {
if (!arguments.length) return;
if (!this.items) this.items = [];
for (var i = 0; i < arguments.length; i++) {
var item = arguments[i];
var obj = OBJ.CREATE(item[0], item[1]);
if (!obj) continue;
if (item[2] && obj.is_equipment) {
if (!this.equipment) this.equipment = []
this.equipment[obj.eq_type] = obj;
} else {
this.items.push(obj);
}
}
}
CHARACTER.prototype.unequip = function (obj, notsend, recover_time = 0) {
if (!obj || !obj.is_equipment || !this.equipment) return;
if (obj.uneq(this, notsend) == false) {
return false;
}
if (obj != this.equipment[obj.eq_type]) return;
if (!this.items) this.items = [];
this.items.push(obj);
this.equipment[obj.eq_type] = null;
if (obj.eq_type == EQUIP_TYPE.WEAPON) {
this.remove_status('weapon', true);
if (obj.is_shortcut) {
this.send("{type:'addAction',id:'" + obj.id + "',name:'" + obj.name + "'}");
}
}
if (obj.eq_type === EQUIP_TYPE.WEAPON)
this.weapon_changed(false);
this.recount();
if (recover_time > 0 && this.is_player) {
this.set_temp('eq_wea', obj.id, 60000);
}
}
CHARACTER.prototype.equip = function (obj) {
if (!obj || !obj.is_equipment) return;
if (!this.equipment) this.equipment = []
var equiped = this.equipment[obj.eq_type];
if (equiped == obj) {
return;
}
if (equiped) {
equiped.uneq(this);
this.equipment[equiped.eq_type] = null;
this.items.push(equiped);
if (equiped.eq_type == EQUIP_TYPE.WEAPON) {
this.remove_status('weapon', true);
}
if (equiped.on_use) {
equiped.notify_action(this, false);
}
if (equiped.is_shortcut) {
this.send("{type:'addAction',id:'" + equiped.id + "',name:'" + equiped.name + "'}");
}
}
if (obj.eq(this) == false) {
if (equiped) {
if (obj.eq_type === EQUIP_TYPE.WEAPON)
this.weapon_changed(false);
this.recount();
}
return false;
}
this.items.remove(obj);
this.equipment[obj.eq_type] = obj;
if (obj.eq_type === EQUIP_TYPE.WEAPON)
this.weapon_changed(true);
this.recount();
if (obj.is_shortcut) {
this.send("{type:'removeAction',id:'" + obj.id + "'}");
}
if (obj.eq_type == EQUIP_TYPE.WEAPON) {
if (this.fight_type) {
this.release_time = 3000 + Date.now();
this.send('{type:"dispfm",rtime:3000}');
}
if (this.query_temp('jxtm')) {
this.remove_status('force');
}
}
}
const WEAPON_TYPES = {
"sword": true,
"blade": true,
"staff": true,
"club": true,
"whip": true
}
CHARACTER.prototype.weapon_changed = function (iseq) {
this.attack_skill = this.query_used_skill(this.query_weapon_type());
this.on_skillchanged && this.on_skillchanged();
if (!this.auto_skills) return;
for (let item of this.auto_skills) {
if (WEAPON_TYPES[item.type]) {
item.ban_use = !iseq;
}
}
}
CHARACTER.prototype.add_obj = function (obj, count) {
if (!obj) return;
if (typeof obj == "string") {
obj = OBJ.clone_to(obj, this, count);
if (!obj) return;
} else {
obj = this.push_item(obj);
}
return obj;
}
CHARACTER.prototype.remove_obj = function (obj, count) {
if (typeof obj == "string") {
obj = this.find_obj(obj);
}
if (!obj) return;
count = count || obj.count || 1;
this.remove_item(obj, count);
return obj;
}
CHARACTER.prototype.query_weapon = function () {
if (this.equipment) {
return this.equipment[EQUIP_TYPE.WEAPON];
}
}
CHARACTER.prototype.query_weapon_type = function () {
if (this.equipment) {
var eq = this.equipment[EQUIP_TYPE.WEAPON];
if (eq) return eq.weapon_type;
}
return WEAPON_TYPE.NONE;
}
CHARACTER.prototype.weapon_name = function () {
if (this.equipment && this.equipment[EQUIP_TYPE.WEAPON]) {
return this.equipment[EQUIP_TYPE.WEAPON].color_name;
}
return "";
}
CHARACTER.prototype.throwing_name = function () {
if (this.equipment && this.equipment[EQUIP_TYPE.THROWING]) {
return this.equipment[EQUIP_TYPE.THROWING].color_name;
}
return "";
}
CHARACTER.prototype.can_throwing = function () {
if (this.equipment) {
var th = this.equipment[EQUIP_TYPE.THROWING];
if (!th) return false;
return true;
}
return false;
}
CHARACTER.prototype.get_equipment = function (type) {
return this.equipment && this.equipment[type];
}
CHARACTER.prototype.set_drop = function () {
this.drop_list = this.drop_list || [];
for (var i = 0; i < arguments.length; i++) {
this.drop_list.push(arguments[i]);
}
}
CHARACTER.prototype.query_drop = function () {
if (!this.drop_list) return;
return OBJ.create_by_odds(this.drop_list);
}

169
os/char/chara_move.js Normal file
View File

@@ -0,0 +1,169 @@
CHARACTER.prototype.moveto = function (rm, leave_msg, in_msg, dir) {
var cur_room = this.environment;
var next_room = rm;
if (typeof rm === "string") {
next_room = ROOM.Get(rm);
if (!next_room) return false;
if (next_room.parent === cur_room.parent) {
if (cur_room.owner) {
next_room = next_room.query_copy(cur_room.owner);
}
} else {
var my_room = next_room.query_copy2(this);
if (my_room) {
next_room = my_room;
}
}
}
if (!next_room) return false;
if (next_room.is_full()) {
//如果房间人数过多,创建投影
next_room = next_room.create_shadow();
if (!next_room) {
//如果创建失败就返回,房间设置不允许投影,或别的原因
return this.notify("那里人太多了,你过不去。");
}
}
if (cur_room) {
if (cur_room.do_leave(this, dir, leave_msg) === false) {
return false;
}
}
next_room.do_enter(this, true, in_msg);
this.notify_follower(dir);
if (cur_room && next_room.parent !== cur_room.parent) {
cur_room.parent.on_leaved(this);
}
}
CHARACTER.prototype.do_follow = function (target) {
if (target) {
if (target.query_setting("no_follow")) {
return this.notify(target.name + "不允许别人跟随。");
}
if (this.follow_target) {
this.follow_target.follow_targets.remove(this);
this.send_room("$N不再跟随$n一起行动。", this.follow_target);
}
this.follow_target = target;
if (!target.follow_targets) {
target.follow_targets = [];
}
target.follow_targets.push(this);
this.send_room("<hig>$N决定跟随$n一起行动。</hig>", target);
} else {
if (!this.follow_target) return this.notify("你目前没有跟随别人一起行动。");
this.follow_target.follow_targets.remove(this);
this.send_room("$N不再跟随$n一起行动。", this.follow_target);
this.follow_target = null;
}
}
CHARACTER.prototype.clear_follow = function () {
if (this.follow_target) {
this.follow_target.follow_targets.remove(this);
this.follow_target = null;
}
if (this.follow_targets) {
for (let item of this.follow_targets) {
item.follow_target = null;
}
this.follow_targets = null;
}
}
CHARACTER.prototype.notify_follower = function (dir) {
if (this.follow_targets) {
for (var i = 0; i < this.follow_targets.length; i++) {
var item = this.follow_targets[i];
if (!item.environment) continue;
if (!item.is_player) {
if (item.on_master_leave) {
if (item.on_master_leave(this, this.environment) == false) {
continue;
}
} else {
if (item.environment.is_fb() != this.environment.is_fb()) {
continue;
}
}
//if (item.state && item.set_state) {
// item.set_state(null);
//}
item.moveto(this.environment,
sendOutMessage(item, dir), sendInMessage(item));
} else {
item.moveto(this.environment,
sendOutMessage(item, dir), sendInMessage(item));
}
}
}
}
CHARACTER.prototype.do_escape = function () {
var eny = this.query_enemy();
if (!eny) return true;
if (eny.on_escape) return eny.on_escape(this);
var is_esc = this.random(this.ds / 2) + this.ds > eny.mz;
if (eny.is_faint) is_esc = true;
if (!is_esc) {
this.send_room("<cyn>$N转身想跑$n一把拦住$P想跑没门\n</cyn>", eny);
this.add_status({
id: "busy",
name: "忙乱",
duration: this.gjsd,
is_busy: true
});
}
return is_esc;
}
CHARACTER.prototype.team_out = function (msg) {
var tm = this.team;
if (!tm) return;
for (var i = 0; i < tm.length; i++) {
if (!tm[i].is_player && tm[i].master == this.id) {
tm[i].on_teamout && tm[i].on_teamout();
this.notify(tm[i].name + "退出了队伍。");
tm[i].team = null;
tm.splice(i, 1);
i--;
}
}
this.team = null;
var iscap = this == tm[0];
tm.remove(this);
checkTeamfb(this);
if (!tm.length) {
this.send("你的队伍解散了。");
this.send('{"type":"dialog","dialog":"team",dismiss:true}');
} else {
var first = tm[0];
var dissmsg = '{"type":"dialog","dialog":"team",dismiss:true}';
this.send("<hic>你退出了队伍。</hic>");
if (tm.length > 1) {
if (iscap) {
first.send_team("<hic>" + this.name + msg + "" + first.name + "现在是队长。</hic>");
} else {
first.send_team("<hic>" + this.name + msg + "。</hic>");
}
first.send_team('{"type":"dialog","dialog":"team",remove:"' + this.id + '"}');
this.send(dissmsg);
} else {
if (first.team) {
checkTeamfb(first);
first.send("<hic>" + this.name + msg + ",你的队伍解散了。</hic>");
first.team.length = 0;
first.team = null;
first.send(dissmsg);
this.send(dissmsg);
}
}
}
}

137
os/char/chara_prop.js Normal file
View File

@@ -0,0 +1,137 @@
require("./character.js");
CHARACTER.prototype.add_prop = function (p, v) {
if (!p) return;
if (!this.prop) {
this.prop = {};
}
var v1 = this.prop[p] || 0;
this.prop[p] = v1 + v;
}
CHARACTER.prototype.clear_prop = function () {
this.prop = {};
}
CHARACTER.prototype.query_prop = function (name) {
if (this.prop)
return this.prop[name] || 0;
return 0;
}
CHARACTER.prototype.query_force_rad = function () {
if (this.force_skill && this.force_skill.force_rad)
return this.force_skill.force_rad || 0.1;
return 0.1;
}
CHARACTER.prototype.add_maxmp = function (count) {
this.max_mp += count;
this.recount();
this.notify("<hig>你增加了" + count + "点内力。</hig>");
}
CHARACTER.prototype.query_temp = function (name, def) {
if (!this.temp) return def;
var item = this.temp[name];
if (item && item.e) {
if (Date.now() <= item.e) {
return item.v;
}
this.temp[name] = null;
return def;
}
return item ?? def;
}
CHARACTER.prototype.set_temp = function (name, value, time) {
if (!this.temp) this.temp = {};
if (time) {
this.temp[name] = {
v: value,
e: Date.now() + time
};
} else {
this.temp[name] = value;
}
}
CHARACTER.prototype.remove_temp = function (name) {
if (!this.temp) return;
this.temp[name] = null;
}
CHARACTER.prototype.add_temp = function (name, value, time) {
let val = this.query_temp(name, 0) + value;
this.set_temp(name, val, time);
return val;
}
CHARACTER.prototype.change_prop = function (prop, isadd) {
if (!prop) return;
for (var item in prop) {
switch (item) {
case "desc":
break;
case "skill":
var sks = prop[item];
for (var sk in sks) {
var lv = this.query_skill(sk, 0);
if (!lv) {
this.add_prop(sk, isadd ? sks[sk] : -sks[sk]);
continue;
}
var sk_base = SKILL.get(sk);
if (!sk_base) continue;
sk_base.release_prop(this, lv);
this.add_prop(sk, isadd ? sks[sk] : -sks[sk]);
lv = this.query_skill(sk, 0);
sk_base.attach_prop(this, lv);
if (this.is_player) {
this.notify('{type:"dialog",dialog:"skills",id:"' + sk + '",level:' + lv + '}');
}
}
break;
default:
this.add_prop(item, isadd ? prop[item] : -prop[item]);
break;
}
}
}
CHARACTER.prototype.add_fbscore = function (v, max) {
var fb = this.environment.query_fb_first(this.query_teamid());
if (!fb) return;
fb.score = (fb.score || 0) + v;
if (max > 0 && fb.score > max) fb.score = max;
}
CHARACTER.prototype.query_fbscore = function (v) {
var first_room = this.environment.query_fb_first(this.query_teamid());
if (!first_room) return 0;
return first_room.score || 0;
}
CHARACTER.prototype.add_score = function (val) {
}
CHARACTER.prototype.add_combat_prop = function (name, val) {
this.add_prop(name, val);
if (!this.combat_props) this.combat_props = [];
this.combat_props.push([name, val]);
if (name === 'max_hp') {
this.max_hp += val;
}
}
CHARACTER.prototype.clear_combat_prop = function (name, val) {
if (this.combat_props) {
for (let i = 0; i < this.combat_props.length; i++) {
this.add_prop(this.combat_props[i][0], -this.combat_props[i][1]);
if (this.combat_props[i][0] === 'max_hp') {
this.max_hp -= this.combat_props[i][1];
this.notify_hp();
}
}
this.combat_props = null;
this.recount();
}
}

566
os/char/chara_skill.js Normal file
View File

@@ -0,0 +1,566 @@
require("./character.js");
CHARACTER.prototype.query_skill = function (name, def) {
if (!this.skills || !this.skills[name]) return def || 0;
return this.skills[name].level + this.query_prop(name);
}
CHARACTER.prototype.skill_map = function () {
//给NPC初始化技能用的不做任何判断
this.skills = this.skills || {};
for (var i = 0; i < arguments.length; i++) {
var item = arguments[i];
if (!item) continue;
var skill_base = SKILL.get(item[0]);
if (!skill_base) {
console.log(item[0] + " not exits")
continue;
}
var skill = {
level: item[1] || 1,
exp: 0
};
this.skills[skill_base.id] = skill;
if (item[2]) {
var enables = item[2];
if (typeof enables == "string") enables = [enables];
for (var j = 0; j < enables.length; j++) {
skill[enables[j]] = true;
this.skills[enables[j]].enable_skill = item[0];
}
}
}
}
CHARACTER.prototype.remove_skill = function (skillid) {
var skill = this.skills[skillid];
if (!skill) return;
var baseskill = SKILL.get(skillid);
if (!baseskill) return false;
if (baseskill.type == SKILL_TYPES.BASE) {
if (skill.enable_skill) {
var old_skill = SKILL.get(skill.enable_skill);
if (!old_skill || !this.skills[skill.enable_skill]) {
return false;
}
old_skill.disenable(this, skillid);
this.skills[skill.enable_skill][skillid] = false;
}
} else {
for (var key in this.skills) {
if (this.skills[key].enable_skill == skillid) {
this.skills[key].enable_skill = null;
}
}
}
baseskill.release_prop(this, this.query_skill(skillid));
delete this.skills[skillid];
this.init_skill();
this.recount();
this.add_score(-baseskill.query_score(skill.level, this));
baseskill.on_remove && baseskill.on_remove(this);
return true;
}
//增加技能
CHARACTER.prototype.set_skill = function (skid, level) {
if (!this.skills) this.skills = {};
var item = this.skills[skid];
var skill_base = SKILL.get(skid);
if (!skill_base) return;
if (!item) {
item = {
//id: skid,
level: level,
exp: 0
};
this.skills[skid] = item;
skill_base.attach_prop(this, level);
} else {
skill_base.release_prop(this, this.query_skill(skid));
item.level = level;
skill_base.attach_prop(this, this.query_skill(skid));
}
this.init_skill();
this.recount();
}
CHARACTER.prototype.skill_limit = function () {
if (this.exp < 100) return 10;
switch (this.level) {
case 1: return Math.round(Math.pow(this.exp * 20, 1 / 3));
case 2: return Math.round(Math.pow(this.exp * 30, 1 / 3));
case 3: return Math.round(Math.pow(this.exp * 40, 1 / 3));
case 4: return Math.round(Math.pow(this.exp * 50, 1 / 3));
case 5: return Math.round(Math.pow(this.exp * 60, 1 / 3));
case 6: return Math.round(Math.pow(this.exp * 60, 1 / 3));
default:
return Math.round(Math.pow(this.exp * 10, 1 / 3));
}
}
CHARACTER.prototype.query_ref_skill = function (skill) {
if (!skill || !skill.ref) return;
var refs = skill.ref.split("/");
var sp_skill = SKILL.get(refs[0]);
if (sp_skill) {
return sp_skill.get_pfm(refs[1]);
}
}
//判断某个技能是否装备到某个基本技能上
CHARACTER.prototype.is_enable_skill = function (skid, type) {
if (!this.skills) return;
var item = this.skills[skid];
if (!item) return;
return item[type];
}
//装备技能到基本技能
CHARACTER.prototype.enable_skill = function (base, skill) {
if (!this.skills) return;
var baseskill = this.skills[base];
if (!baseskill) return;
if (baseskill.enable_skill) {
var old_skill = this.skills[baseskill.enable_skill];
if (!old_skill) return;
old_skill[base] = false;
old_skill = SKILL.get(baseskill.enable_skill);
if (old_skill) {
old_skill.disenable(this, base);
}
}
if (skill) {
var sp_skill = this.skills[skill];
if (baseskill && sp_skill) {
var sp_skill_base = SKILL.get(skill);
if (!sp_skill_base || sp_skill_base.enable(this, base) !== true)
return false;
baseskill.enable_skill = skill;
sp_skill[base] = true;
}
} else {
baseskill.enable_skill = null;
}
this.init_skill();
this.recount();
return true;
}
//初始化人物使用的技能
CHARACTER.prototype.init_skill = function () {
this.attack_skill = this.query_used_skill(this.query_weapon_type());
this.noweapon_skill = this.query_used_skill(WEAPON_TYPE.NONE);
this.dodge_skill = this.query_used_skill(BASE_SKILLS.DODGE);
this.parry_skill = this.query_used_skill(BASE_SKILLS.PARRY);
this.force_skill = this.query_used_skill(BASE_SKILLS.FORCE);
this.on_skillchanged && this.on_skillchanged();
this.auto_skills = null;
}
CHARACTER.prototype.query_used_skill = function (skname) {
if (!this.skills) {
return WORLD.DEFAULT_SKILLS[skname];
}
var skill = this.skills[skname];
if (skill) {
var skill_base = SKILL.get(skill.enable_skill || skname);
if (!skill_base) skill.enable_skill = null;
else return skill_base;
}
return WORLD.DEFAULT_SKILLS[skname];
}
CHARACTER.prototype.query_status = function (sid) {
if (!this.status) return 0;
for (var i = 0; i < this.status.length; i++) {
if (this.status[i].id == sid) {
return this.status[i].count;
}
}
return 0;
}
CHARACTER.prototype.add_status = function (buff, from) {
if (this.hp <= 0) return false;
if (!this.status) this.status = [];
var sid = buff.id;
buff.override = buff.override || 0;
buff.count = buff.count || 1;
buff.max_count = buff.max_count || 10;
buff.start_time = Date.now();
if (buff.on_interval) {
buff.over_count = buff.over_count || 0;
}
if (this.ig_control && !buff.no_diff) {
if (buff.is_busy || buff.is_faint || buff.is_miss || buff.is_rash) {
return false;
}
}
if (buff.downside && buff.duration && !buff.no_diff) {
//buff.duration = buff.duration - this.query_prop("diff_downside");
buff.duration = Math.round(buff.duration * (100 - this.query_prop("diff_downside_per")) / 100);
if (buff.duration <= 0) {
return false;
}
}
if (buff.is_busy && !buff.no_diff) {
if (from) {
buff.duration = buff.duration + from.query_prop("busy");
buff.duration = buff.duration * (100 + from.query_prop("busy_per")) / 100;
}
buff.duration = buff.duration - this.query_prop("diff_busy");
buff.duration = Math.round(buff.duration * (100 - this.query_prop("diff_busy_per")) / 100);
if (buff.duration <= 0) {
return false;
}
}
for (var i = 0; i < this.status.length; i++) {
if (this.status[i].id == sid) {
var item = this.status[i];
if (item.override != buff.override) return false;
if (item.override == 0) {
//0不覆盖 1叠加 2覆盖替换
return false;
}
if (item.override == 1) {
if (item.max_count <= item.count) {
return false;
}
item.count += buff.count;
clearTimeout(item.handler);
if (item.duration)
item.handler = this.call_out(this.remove_status, item.duration, sid);
this.change_buff(item, true, buff.count);
item.start_time = buff.start_time;
this.status_changed(item, "refresh");
} else {
item.handler && clearTimeout(item.handler);
this.change_buff(item, false, item.count);//覆盖先移除 后添加 重新计时
this.status_changed(item, "remove");
if (buff.duration)
item.handler = this.call_out(this.remove_status, buff.duration, sid);
this.status[i] = buff;
buff.start_time = buff.start_time;
this.change_buff(buff, true, buff.count);
this.status_changed(buff, "add");
}
return;
}
}
if (buff.duration)
buff.handler = this.call_out(this.remove_status, buff.duration, sid);
this.status.push(buff);
this.change_buff(buff, true, buff.count);
this.status_changed(buff, "add");
}
CHARACTER.prototype.clear_downside = function (type) {
if (!this.status) return;
var removed = "0";
var count = 0;
for (var i = 0; i < this.status.length; i++) {
var item = this.status[i];
if ((item.downside || false) == type && !item.no_clear) {
this.change_buff(item, false, item.count);
item.handler && clearTimeout(item.handler);
this.status.splice(i, 1);
i--;
removed += ',"' + item.id + '"';
count++;
}
}
if (removed.length == 1 || !this.environment) return;
var items = this.environment.items;
var msg = '{type:"status",id:"' + this.id + '",sid:[' + removed + '],action:"remove"}';
for (var i = 0; i < items.length; i++) {
var player = items[i];
if (player.is_player) {
player.send(msg);
}
}
return count;
}
CHARACTER.prototype.clear_combat_status = function () {
if (!this.status || !this.status.length) return;
var removed = "0";
for (var i = this.status.length - 1; i >= 0; i--) {
var item = this.status[i];
if (item.only_combat) {
this.change_buff(item, false, item.count);
item.handler && clearTimeout(item.handler);
this.status.splice(i, 1);
removed += ',"' + item.id + '"';
}
}
if (removed.length == 1 || !this.environment) return;
var items = this.environment.items;
var msg = '{type:"status",id:"' + this.id + '",sid:[' + removed + '],action:"remove"}';
for (var i = 0; i < items.length; i++) {
var player = items[i];
if (player.is_player) {
player.send(msg);
}
}
}
CHARACTER.prototype.remvoe_statuses = function (func) {
if (!this.status || !this.status.length) return;
var removed = "0";
for (var i = this.status.length - 1; i >= 0; i--) {
var item = this.status[i];
if (func(item)) {
this.change_buff(item, false, item.count);
item.handler && clearTimeout(item.handler);
this.status.splice(i, 1);
removed += ',"' + item.id + '"';
}
}
if (removed.length == 1 || !this.environment) return;
var items = this.environment.items;
var msg = '{type:"status",id:"' + this.id + '",sid:[' + removed + '],action:"remove"}';
for (var i = 0; i < items.length; i++) {
var player = items[i];
if (player.is_player) {
player.send(msg);
}
}
}
CHARACTER.prototype.clear_status = function () {
if (!this.status || !this.status.length) return;
for (var i = 0; i < this.status.length; i++) {
var item = this.status[i];
this.change_buff(item, false, item.count);
item.handler && clearTimeout(item.handler);
}
this.status.length = 0;
if (!this.environment) return;
var msg = '{type:"status",id:"' + this.id + '",action:"clear"}';
var items = this.environment.items;
for (var i = 0; i < items.length; i++) {
var player = items[i];
if (player.is_player) {
player.send(msg);
}
}
}
CHARACTER.prototype.change_buff = function (buff, isadd, buff_count) {
if (isadd) {
if (buff.prop) {
for (var i = 0; i < buff_count; i++) {
this.change_prop(buff.prop, true);
}
this.recount();
}
if (buff.on_attach) buff.on_attach(this);
if (buff.ig_control) this.ig_control = buff.duration;
if (buff.start_msg) {
this.send_room(buff.start_msg);
}
if (buff.is_busy) this.is_busy = buff.duration;
if (buff.is_miss) this.is_miss = buff.duration;
if (buff.is_rash) this.is_rash = buff.duration;
if (buff.is_shadow) this.is_shadow = buff.duration;
if (buff.is_faint) {
this.is_faint = buff.duration;
}
} else {
if (buff.prop) {
for (var i = 0; i < buff_count; i++) {
this.change_prop(buff.prop, false);
}
this.recount();
}
if (buff.on_expire) buff.on_expire(this);
if (buff.is_busy) this.is_busy = 0;
if (buff.is_miss) this.is_miss = 0;
if (buff.is_rash) this.is_rash = 0;
if (buff.ig_control) this.ig_control = 0;
if (buff.is_shadow) this.is_shadow = 0;
if (buff.is_faint) {
this.is_faint = 0;
}
if (this.hp > 0 && buff.finish_msg) {
this.send_room(buff.finish_msg);
}
this.remove_temp(buff.id);
}
}
CHARACTER.prototype.appdend_status = function (str) {
if (!this.status) return;
var now = Date.now();
str.push(",status:[");
for (var i = 0; i < this.status.length; i++) {
if (i > 0) str.push(",");
var item = this.status[i];
str.push('{sid:"');
str.push(item.id);
str.push('",name:"');
str.push(item.name);
str.push('",duration:');
if (item.on_interval) {
str.push(item.duration * item.duration_count);
} else {
str.push(item.duration);
}
str.push(',overtime:');
str.push(now - item.start_time);
if (item.override === 1) {
str.push(',"count":');
str.push(item.count);
}
if (item.downside) {
str.push(',downside:');
str.push(true);
}
str.push('}');
}
str.push("]");
}
CHARACTER.prototype.notify_status = function () {
if (!this.status) return;
var str = ['{type:"status",id:\"'];
str.push(this.id);
str.push("\",action:'load',items:[");
var now = Date.now();
for (var i = 0; i < this.status.length; i++) {
if (i > 0) str.push(",");
var item = this.status[i];
str.push('{sid:"');
str.push(item.id);
str.push('",name:"');
str.push(item.name);
str.push('",duration:');
if (item.on_interval) {
str.push(item.duration * item.duration_count);
} else {
str.push(item.duration);
}
str.push(',overtime:');
str.push(now - item.start_time);
if (item.override === 1) {
str.push(',"count":');
str.push(item.count);
}
if (item.downside) {
str.push(',downside:');
str.push(true);
}
str.push('}');
}
str.push("]}");
this.send(str.join(""));
}
CHARACTER.prototype.status_changed = function (item, type) {
var str = [];
str.push('{type:"status","action":"');
str.push(type);
str.push('",id:"');
str.push(this.id);
str.push('",sid:"');
str.push(item.id);
str.push('"');
if (type === "add") {
str.push(',"name":"');
str.push(item.name);
str.push('","duration":');
if (item.on_interval) {
str.push(item.duration * item.duration_count);
} else {
str.push(item.duration);
}
if (item.override === 1) {
str.push(',"count":');
str.push(item.count);
}
if (item.downside) {
str.push(',downside:');
str.push(true);
}
} else if (type === "refresh") {
str.push(',count:');
str.push(item.count);
}
str.push('}');
if (!this.environment) return;
var msg = str.join("");
var items = this.environment.items;
for (var i = 0; i < items.length; i++) {
var player = items[i];
if (player.is_player) {
player.send(msg);
}
}
}
CHARACTER.prototype.remove_status = function (sid, isall) {
if (!this.status) return;
for (var i = this.status.length - 1; i >= 0; i--) {
if (this.status[i].id === sid) {
var item = this.status[i];
if (item.handler) clearTimeout(item.handler);
item.handler = null;
if (item.on_interval && !isall) {
item.over_count++;
if (item.on_interval) {
if (item.on_interval(this, item.over_count) === false) {
item.duration_count = item.duration_count || 2;
item.over_count = item.duration_count;
}
}
if (item.duration_count === 0 || (item.duration_count > 1 && item.duration_count > item.over_count)) {
if (item.duration)
item.handler = this.call_out(this.remove_status, item.duration, sid);
// item.start_time = Date.now();
return;
}
}
this.change_buff(item, false, 1);
if (item.override === 1) {
item.count--;
if (item.count === 0 || isall) {
this.change_buff(item, false, item.count);
this.status_changed(item, "remove");
this._splice_status(i, item);
} else {
if (item.duration)
item.handler = this.call_out(this.remove_status, item.duration, sid);
item.start_time = Date.now();
this.status_changed(item, "refresh");
}
} else {
//覆盖和不覆盖的都直接移除
this.status_changed(item, "remove");
this._splice_status(i, item);
}
return;
}
}
}
CHARACTER.prototype._splice_status = function (index, item) {
if (this.status[index] === item) {
return this.status.splice(index, 1);
}
for (var i = 0; i < this.status.length; i++) {
if (this.status[i] === item) {
return this.status.splice(i, 1);
}
}
}

351
os/char/character.js Normal file
View File

@@ -0,0 +1,351 @@
require("../item");
/*global CHARACTER ROOM ITEM*/
CHARACTER = function () {
this.name = "生物";
this.hp = this.max_hp = 100;
this.mp = this.max_mp = 100;
this.str = this.con = this.dex = this.int = 20;
this.money = 0;
}
CHARACTER.inherits(ITEM);
CHARACTER.prototype.send = function () {
}
CHARACTER.prototype.notify = function () {
}
CHARACTER.prototype.send_commands = function () {
}
CHARACTER.prototype.notify_fail = function () {
return false;
}
CHARACTER.prototype.is_living = function () {
return this.hp > 0;
}
CHARACTER.prototype.is_in = function (path) {
if (!this.environment) return false;
return this.environment.path === path;
}
CHARACTER.prototype.is_here = function (obj) {
if (!this.environment || !obj.environment) return false;
return this.environment === obj.environment;
}
CHARACTER.prototype.find_obj = function (oid, parent) {
var items = this.items;
if (parent) items = parent.items;
return this.find_obj_byid(items, oid);
}
CHARACTER.prototype.send_message = function (msg, include_me) {
if (!msg || !this.environment) return;
var list = this.environment.items;
for (var i = 0; i < list.length; i++) {
if (list[i].is_player) {
if (list[i] === this && !include_me) continue;
if (!list[i].no_message)
list[i].notify(msg);
}
}
}
CHARACTER.prototype.send_combat = function (text, target) {
if (!this.environment || !text) return;
var list = this.environment.items;
var th_vision, item;
for (var i = 0; i < list.length; i++) {
item = list[i];
if (item.is_player) {
if (item === this) {
if (!item.query_setting("no_mcmsg"))
item.notify(splitmessage(this, text, 1, target));
} else if (item === target) {
if (!item.query_setting("no_mcmsg"))
item.notify(splitmessage(this, text, 2, target));
} else if (!item.no_message && !item.query_setting("no_combatmsg")) {
if (!th_vision) th_vision = splitmessage(this, text, 3, target);
item.notify(th_vision);
}
}
}
}
CHARACTER.prototype.send_room = function (text, target, excludeself) {
if (!this.environment || !text) return;
var list = this.environment.items;
var th_vision;
for (var i = 0; i < list.length; i++) {
if (list[i].is_player) {
if (list[i] === this) {
!excludeself && list[i].notify(splitmessage(this, text, 1, target));
} else if (list[i] === target) {
list[i].notify(splitmessage(this, text, 2, target));
} else if (!list[i].no_message) {
if (!th_vision) th_vision = splitmessage(this, text, 3, target);
list[i].notify(th_vision);
}
}
}
}
CHARACTER.prototype.query_setting = function (name) {
return false;
}
function splitmessage(me, text, type, target) {
if (text.length < 3) return text;
var str = [];
var start = 0;
for (var i = 0; i < text.length; i++) {
if (text[i] === "$") {
start < i && str.push(text.substring(start, i));
var ch = text[++i];
start = i + 1;
//type 1本人视角 2目标视角 3第三人称视角
switch (ch) {
case "N"://本人
str.push(type === 1 ? "你" : me.name);
break;
case "n"://目标
str.push(type === 2 ? "你" : target.name);
break;
case "P":
str.push(type === 1 ? "你" : me.call3());
break;
case "p":
str.push(type === 2 ? "你" : target.call3());
break;
case "l":
str.push(me.attack_part ? me.attack_part.name : "");
break;
case "W":
case "w":
str.push(me.weapon_name() || "手");
break;
case "i":
str.push(target.weapon_name() || "手");
break;
case "T":
str.push(me.throwing_name());
break;
}
}
}
start < i && str.push(text.substring(start, i));
return str.join("");
}
//执行一串命令
CHARACTER.prototype.command = function (req) {
if (this.wait_input) { //如果用户等待输入
this.wait_input.apply(this, [this, req]);
return;
}
var cmd = null, pars = null, start = 0, i = 0;
for (; i < req.length; i++) {
if (req[i] === ' ') {
if (start < i) {
cmd = req.substring(start, i);
pars = req.substring(i + 1);
break;
}
start = i;
}
}
if (!cmd) cmd = req;
this.do_command(cmd, pars);
}
CHARACTER.prototype.do_command = function (cmdName, str) {
var cmd = WORLD.COMMANDS[cmdName];
var pars;
if (cmd && cmd.regex && str) {
pars = cmd.regex.exec(str);
pars ? pars[0] = this : pars = [this, str];
} else {
pars = [this, str];
}
if (this.do_item_action(this.environment, cmdName, pars)) {
//如果环境触发这个命令就返回
return;
}
cmd = cmd || WORLD.DEFAULT_COMMAND;
if (cmd) {
if (!this.check_command(cmd))
return;//不允许执行
if (cmd.enter.apply(cmd, pars) !== false) {
return;//命令执行完成。
}
}
if (str) {
//如果有参数,尝试找下这个物件
if (this.do_item_action(this.find_obj(str, this.environment), cmdName, pars)) {
//如果物件触发这个命令就返回
return;
}
}
this.send("什么?");
}
CHARACTER.prototype.do_item_action = function (item, cmd, pars) {
if (!item || !item.actions) return;
var cmdItem = item.actions[cmd];
if (!cmdItem || !cmdItem.action) return;
if (!this.check_command(cmdItem))
return true;//返回true 不允许执行
if (cmdItem.action.apply(item, pars) !== false)
return true; //返回true表示不继续执行该命令
}
CHARACTER.prototype.check_command = function (cmd) {
if (cmd.allow_level > this.user_level) {
this.send("什么?");
return false;
}
if (this.hp <= 0 && !cmd.allow_die) {
//死亡状态,除了一些特殊指令都不能做
return this.notify_fail("你现在是灵魂状态,不能那么做。");
}
if (!cmd.allow_faint && this.is_faint) {
this.send("你正在昏迷中!");
return false;
}
if (!cmd.allow_state && this.state) {
return this.notify_fail("你正在" + this.state.title + ",没时间这么做。");
}
if (!cmd.allow_fight && this.fight_type > 0) {
return this.notify_fail("你正在战斗,待会再说。");
}
if (!cmd.allow_busy && this.is_busy) {
return this.notify_fail("你现在正忙。");
}
return true;
}
CHARACTER.prototype.create = function (path, par) {
//模板被创建,实际上没真正用
if (par) this.path = path + par;
this.on_create && this.on_create(path, par);
WORLD.NPC_STROE.set(this.path, this);
}
CHARACTER.prototype.update = function (path, par) {
this.create(path, par);
}
//真正被复制到房间
CHARACTER.prototype.clone = function () {
if (this.temp) this.temp = Object.create(this.temp);
if (this.prop) this.prop = Object.create(this.prop);
if (this.equipment) {
let eqs = [];
for (let i = 0; i < this.equipment.length; i++) {
let item = this.equipment[i];
if (item) {
eqs[i] = OBJ.CREATE(item.path);
}
}
this.equipment = eqs;
}
//装备和道具只保留引用应该没事2个相同NPC的装备和背包是同一个道具
//好像随从不行
if (this.items) {
let items = [];
for (let i = 0; i < this.items.length; i++) {
items[i] = OBJ.CREATE(this.items[i].path);
}
this.items = items;
}
this.create_id();
this.init();
this.recount();
this.hp = this.max_hp;
this.mp = this.max_mp;
this.on_clone && this.on_clone();
}
CHARACTER.prototype.init = function () {
if (this.equipment) {
let groups = {};
for (let i = 0; i < this.equipment.length; i++) {
let item = this.equipment[i];
if (item) {
item.change_prop(this, true);
item.on_eq && item.on_eq(this);
if (item && item.group_name) {
groups[item.group_name] = (groups[item.group_name] || 0) + 1;
var prop = item.group_prop(groups[item.group_name]);
if (prop) {
this.change_prop(prop, true);
}
}
}
}
}
if (this.is_player) this.score = 0;
if (this.skills) {
for (let item in this.skills) {
var base_skill = SKILL.get(item);
if (!base_skill) {
delete this.skills[item];
continue;
}
base_skill.attach_prop(this, this.query_skill(item));
if (this.is_player) {
this.score += base_skill.query_score(this.skills[item].level, this);
}
}
}
this.init_skill();
}
CHARACTER.EXP_LIMIT = [300000, 3000000, 20000000];
CHARACTER.prototype.add_exp = function (exp, pot, money) {
if (exp) {
exp += this.query_temp("exp_up", 0);
}
if (pot) {
pot += this.query_temp("pot_up", 0);
}
var str = ["<hig>你获得了"];
if (exp) {
this.exp += exp;
str.push(exp);
str.push("点经验");
}
if (pot) {
this.pot += pot;
if (exp) str.push("");
str.push(pot);
str.push("点潜能");
}
if (money) {
this.money += money;
if (exp || pot) str.push("");
str.push(UTIL.moneyToStr(money));
}
if (str.length === 1) return;
str.push("。</hig>");
this.send(str.join(""));
}
CHARACTER.prototype.add_money = function (val) {
this.money += val;
}
CHARACTER.prototype.check_groupeq = function () {
var eqs = {};
for (var i = 0; i < this.equipment.length; i++) {
var item = this.equipment[i];
if (item && item.group_name) {
eqs[item.group_name] = (eqs[item.group_name] || 0) + 1;
var prop = item.group_prop(eqs[item.group_name]);
if (prop) {
this.change_prop(prop, true);
}
}
}
}

250
os/char/combat.js Normal file
View File

@@ -0,0 +1,250 @@
require("./character.js");
CHARACTER.prototype.begin_attack = function (target, type) {
if (!target || target === this) return;
if (!this.attack_skill) {
return this.send("error skill");
}
this.add_enemy(target);
this.fight_type = this.fight_type || 0;
if (type > this.fight_type) {
if (this.force_skill && this.force_skill.on_beginfight) {
this.force_skill.on_beginfight(this, target);
}
if (this.attack_skill && this.attack_skill.on_beginfight) {
this.attack_skill.on_beginfight(this, target);
}
if (!this.fight_type) {
if (this.attack_handler) clearTimeout(this.attack_handler);
this.attack_handler = this.call_out(this.auto_attack, Math.random() * this.gjsd);
this.send('{type:"combat",start:1}');
}
this.fight_type = type; //1fight hp<30% 2 kill 0
}
}
CHARACTER.prototype.do_fight = function (target) {
this.begin_attack(target, 1);
}
CHARACTER.prototype.do_kill = function (target) {
if (this.fight_type == 2 && this.query_enemy() == target) return;
this.begin_attack(target, 2);
target.begin_attack(this, 2);
target.notify("<hir>看起来" + this.name + "想杀死你!</hir>\n");
this.notify("<hir>看起来" + target.name + "想杀死你!</hir>\n");
}
CHARACTER.prototype.add_enemy = function (target) {
if (!this.enemy) {
this.enemy = [];
}
this.enemy.push(target);
}
CHARACTER.prototype.notify_hp = function (type, val) {
if (!this.environment) return;
var items = this.environment.items;
var str = null;
if (type) {
str = "{type:\"sc\",id:\"" + this.id + "\"," + type + ":" + val + "";
} else {
var ary = ["{type:\"sc\",id:\""];
ary.push(this.id);
ary.push("\",hp:");
ary.push(this.hp);
ary.push(",max_hp:");
ary.push(this.max_hp);
ary.push(",mp:");
ary.push(this.mp);
ary.push(",max_mp:");
ary.push(this.max_mp);
str = ary.join("");
}
var showdamage = type ? type === "hp" : false;
for (var i = 0; i < items.length; i++) {
var player = items[i];
if (player.is_player) {
if (showdamage && this.damages && player.query_setting('show_damage')) {
player.send(str + ",damage:" + (this.damages[player.id] || 0) + "}");
} else {
player.send(str + "}");
}
}
}
}
CHARACTER.prototype.add_hp = function (v) {
if (v > this.max_hp - this.hp) v = this.max_hp - this.hp;
else if (v < -this.hp) v = -this.hp;
if (!v) return 0;
this.hp += v;
this.notify_hp("hp", this.hp);
return v;
}
CHARACTER.prototype.add_mp = function (v) {
var mp = this.mp + v;
if (mp > this.max_mp) mp = this.max_mp;
if (mp < 0) mp = 0;
if (mp === this.mp) return;
this.mp = mp;
this.notify_hp("mp", this.mp);
return v;
}
CHARACTER.prototype.is_fighting = function (p) {
if (!this.fight_type) return false;
if (!this.enemy || !this.enemy.length) {
this.fight_type = 0;
this.clear_combat_status();
return false;
}
if (p) {
if (p.environment !== this.environment) return false;
return this.enemy.contain(p);
}
return true;
}
CHARACTER.prototype.end_fight = function () {
if (this.enemy) this.enemy.length = 0;
this.release_time = 0;
if (!this.fight_type) return;
this.send('{type:"combat",end:1}');
if (this.record_damage && this.hp > 0) this.damages = null;
this.fight_type = 0;
if (this.attack_handler) clearTimeout(this.attack_handler);
this.attack_handler = null;
this.clear_combat_status();
this.clear_combat_prop();
return false;
}
CHARACTER.prototype.query_enemy = function () {
if (!this.enemy) return;
for (var i = 0; i < this.enemy.length; i++) {
if (this.enemy[i].hp <= 0 || !this.is_here(this.enemy[i])
|| !this.enemy[i].fight_type) {
this.enemy.splice(i, 1);
i--;
}
}
return this.enemy[0];
}
CHARACTER.prototype.can_attack = function () {
return this.hp > 0 && this.fight_type > 0 && !this.is_faint && !this.is_busy;
}
CHARACTER.prototype.end_attack = function (target) {
if (!target) return;
if (!this.fight_type) return;
if (this.attack_skill.on_end_attack) {
this.attack_skill.on_end_attack(this, target);
}
if (this.fight_type === 1 && target.hp / target.max_hp < 0.3) {
if (target.hp <= 0) target.hp = 1;
if (target.is_faint) {
this.send_room(WINNER_MSG[this.random(4)], target);
} else {
this.send_room(WINNER_MSG.random(), target);
}
target.on_fight_over && target.on_fight_over(this, false);
this.on_fight_over && this.on_fight_over(target, true);
target.end_fight();
return this.end_fight();
} else if (target.hp <= 0 && target.die(this) !== false) {
target.end_fight();
this.enemy.remove(target);
if (!this.enemy.length) {
if (this.hp <= 0) {
this.hp = 1;
}
return this.end_fight();
}
}
return true;//是否继续攻击
}
CHARACTER.prototype.query_part = function () {
return CHARACTER_PARTS.random();
}
CHARACTER.prototype.full = function () {
this.hp = this.max_hp;
this.mp = this.max_mp;
this.clear_distime();
this.release_time = 0;
this.notify_hp();
}
CHARACTER.prototype.clear_distime = function (pfmid) {
if (this.auto_skills) {
if (!pfmid) {
for (let i = 0; i < this.auto_skills.length; i++) {
let item = this.auto_skills[i];
item.release_time = 0;
}
} else {
for (let i = 0; i < this.auto_skills.length; i++) {
let item = this.auto_skills[i];
if (item.pfm.id === pfmid) {
item.release_time = 0;
break;
}
}
}
}
}
CHARACTER.prototype.do_attacks = function (par) {
var targets = par.targets;
if (!targets) {
targets = new Array(this.enemy.length);
for (var i = 0; i < this.enemy.length; i++) {
targets[i] = this.enemy[i];
}
}
if (!targets.length) return;
var attack_msg = par.attack_msg;
if (attack_msg === undefined) attack_msg = (par.no_weapon ? this.noweapon_skill : this.attack_skill).query_attack_action(this, targets[0]);
if (attack_msg !== "") this.send_combat(attack_msg, targets[0]);
par.attack_msg = "";
for (let i = 0; i < targets.length; i++) {
par.target = targets[i];
this.do_attack(par);
this.end_attack(targets[i]);
}
}
var CHARACTER_PARTS = [
{ name: "左脚", hert: 0.8, crit: 0 },
{ name: "右脚", hert: 0.8, crit: 0 },
{ name: "左腿", hert: 0.85, crit: 0 },
{ name: "右腿", hert: 0.85, crit: 0 },
{ name: "小腹", hert: 0.91, crit: 3 },
{ name: "胸前", hert: 0.95, crit: 4 },
{ name: "后背", hert: 0.97, crit: 4 },
{ name: "头部", hert: 1.2, crit: 10 },
{ name: "颈部", hert: 1.1, crit: 5 },
{ name: "后心", hert: 1, crit: 4 },
{ name: "左肩", hert: 0.85, crit: 1 },
{ name: "右肩", hert: 0.89, crit: 1 },
{ name: "左手", hert: 0.85, crit: 0 },
{ name: "左手", hert: 0.85, crit: 0 },
{ name: "腰间", hert: 0.99, crit: 5 }
];
var WINNER_MSG = [
"<CYN>$N哈哈大笑愉快地说道承让了</CYN>",
"<CYN>$N双手一拱笑著说道知道我的厉害了吧</CYN>",
"<CYN>$N哈哈大笑双手一拱笑著说道承让</CYN>",
"<CYN>$N胜了这招向后跃开三尺笑道承让</CYN>",
"<CYN>$n脸色微变说道佩服佩服</CYN>",
"<CYN>$n向后退了几步说道这场比试算我输了佩服佩服</CYN>",
"<CYN>$n向后一纵躬身做揖说道阁下武艺不凡果然高明</CYN>",
];

485
os/char/follower.js Normal file
View File

@@ -0,0 +1,485 @@
require("../util/util.js");
require("./user.js");
FOLLOWER = function () {
this.hp = this.max_hp = 100;
this.mp = this.max_mp = 100;
this.str = this.con = this.dex = this.int = this.per = this.age = 20;
this.family = FAMILIES.NONE;
this.auto_pfm = true;
this.master = null;
this.level = 3;
this.master_name = null;
this.max_item_count = 10;
this.settings = {
auto_kill: 1,
auto_dice: 1
};
}
FOLLOWER.inherits(CHARACTER);
FOLLOWER.prototype.query_setting = function (name) {
if (!this.settings) return 0;
return this.settings[name] || 0;
}
FOLLOWER.prototype.set_setting = function (name, value) {
if (!this.settings) this.settings = {};
if (!value || value == "0") {
delete this.settings[name];
} else {
if (value == "1") value = 1;
this.settings[name] = value;
}
this.login_message = null;
}
FOLLOWER.prototype.send = function (text) {
if (this.listener) {
text = text.replace('你', this.name);
this.listener.send(text);
}
}
FOLLOWER.prototype.notify_fail = function (text) {
this.send(text);
return false;
}
FOLLOWER.prototype.notify = function (text) {
this.send(text);
}
FOLLOWER.prototype.set_listener = function (me, target) {
if (me.id == this.master) this.listener = target;
}
FOLLOWER.STORES = new Map();
FOLLOWER.CLEAR = function (me) {
if (!me.follower) return;
for (var i = 0; i < me.follower.length; i++) {
var npc = FOLLOWER.STORES.get(me.id + "_" + me.follower[i].id);
if (npc) {
FOLLOWER.STORES.delete(me.id + "_" + me.follower[i].id);
npc.set_state(null);
npc.environment && npc.environment.item_changed(npc, false);
npc.clear_status();
}
}
}
FOLLOWER.RESET = function (me) {
if (!me.follower) return;
for (var i = 0; i < me.follower.length; i++) {
var npc = FOLLOWER.STORES.get(me.id + "_" + me.follower[i].id);
if (npc) {
npc.set_state(null);
npc.environment && npc.environment.item_changed(npc, false);
}
}
}
FOLLOWER.INIT_FROM_USER = function (me, datas) {
for (var j = 0; j < datas.length; j++) {
var data = datas[j];
var my_npc = FOLLOWER.STORES.get(me.id + "_" + data.id);
if (my_npc) continue;
if (!datas[j].id) continue;
my_npc = new FOLLOWER();
var obj = NPC.CLONE(data.path);
for (var i = 0; i < SAVE_NUMPROP.length; i++) {
my_npc[SAVE_NUMPROP[i]] = data.prop[i] || 0;
}
for (var i = 0; i < SAVE_STRPROP.length; i++) {
my_npc[SAVE_STRPROP[i]] = data[SAVE_STRPROP[i]] || obj[SAVE_STRPROP[i]];
}
my_npc.on_makelove = obj ? obj.on_makelove : null;
my_npc.on_master_enter = obj ? obj.on_master_enter : null;
my_npc.equipment = data.temp;
my_npc.settings = data.settings;
my_npc.skills = data.skills;
my_npc.path = obj.path;
my_npc.items = me.read_items(data.items);
my_npc.equipment = me.read_items(data.eq);
my_npc.level = my_npc.level || obj.level || 3;
my_npc.init();
my_npc.recount();
my_npc.hp = my_npc.max_hp;
my_npc.mp = my_npc.max_mp;
FOLLOWER.STORES.set(me.id + "_" + my_npc.id, my_npc);
my_npc.master = me.id;
my_npc.master_name = me.name;
}
}
FOLLOWER.INIT = function (me, par) {
if (!par || !par.path) return;
var npc;
var id = me.id + "_" + par.id;
if (par.id) {
npc = FOLLOWER.STORES.get(id);
if (npc) return npc;
}
var obj = NPC.CLONE(par.path);
if (!obj) return;
npc = new FOLLOWER();
for (var i = 0; i < SAVE_NUMPROP.length; i++) {
npc[SAVE_NUMPROP[i]] = obj[SAVE_NUMPROP[i]] || 0;
}
for (var i = 0; i < SAVE_STRPROP.length; i++) {
npc[SAVE_STRPROP[i]] = obj[SAVE_STRPROP[i]] || "";
}
npc.on_makelove = obj.on_makelove;
npc.on_master_enter = obj.on_master_enter;
npc.equipment = obj.equipment;
npc.skills = obj.skills;
npc.items = obj.items;
npc.id = par.id;
npc.path = obj.path;
npc.level = obj.level || 3;
npc.init();
npc.recount();
FOLLOWER.STORES.set(id, npc);
npc.master = me.id;
npc.master_name = me.name;
return npc;
}
FOLLOWER.REPLACE = function (me, old, npc) {
if (!old || !npc) return;
var copys = ["str", "con", "dex", "int", "gender", "kar", "per", "name", "title", "desc", "on_master_learn", "on_master_enter"];
for (var i = 0; i < copys.length; i++) {
old[copys[i]] = npc[copys[i]];
}
if (!old.skills) old.skills = {};
if (!old.equipment) old.equipment = [];
if (npc.equipment && npc.equipment[0]) {
if (old.equipment[0]) {
npc.items.push(npc.equipment[0]);
} else {
old.equipment[0] = npc.equipment[0];
}
npc.equipment[0] = null;
}
if (!old.items) old.items = [];
if (npc.items && npc.items.length) {
for (var i = 0; i < npc.items.length; i++) {
old.items.push(npc.items[i]);
}
npc.items.length = 0;
}
for (var sk in npc.skills) {
var oldSkill = old.skills[sk];
if (oldSkill && oldSkill.addin && oldSkill.addin.length)
continue;//已经进阶的不覆盖
if (!oldSkill || oldSkill.level < npc.skills[sk].level) {
old.skills[sk] = npc.skills[sk];
}
}
if (npc.exp > old.exp) old.exp = npc.exp;
if (npc.pot > old.pot) old.pot = npc.pot;
if (npc.max_mp > old.max_mp) old.max_mp = npc.max_mp;
old.prop = {};
old.init();
if (old.status) {
for (var j = old.status.length - 1; j >= 0; j--) {
var item = old.status[j];
old.change_buff(item, true, item.count);
}
}
old.recount();
old.master_json = null;
old.color_name = null;
old.on_master_enter = npc.on_master_enter;
old.on_makelove = npc.on_makelove;
old.path = npc.path;
old.level = npc.level > old.level ? npc.level : old.level;
if (old.environment) {
old.environment.item_changed(old, true);
}
for (var i = 0; i < me.follower.length; i++) {
if (me.follower[i].id == old.id) {
me.follower[i].path = npc.path;
break;
}
}
}
FOLLOWER.GET = function (me, par) {
var id = me.id + "_" + par.id;
return FOLLOWER.STORES.get(id);
}
FOLLOWER.CREATE = function (me, par, callback) {
if (!par || !par.path) return;
var id = me.id + "_" + par.id;
var npc = FOLLOWER.STORES.get(id);
if (npc) return callback(npc);
}
var SAVE_NUMPROP = ["str", "con", "dex", "int", "gender", "max_mp", "limit_mp", "exp", "pot", "kar", "per"
, "hp", "mp", "max_item_count", "money", 'level'];
var SAVE_STRPROP = ["id", "name", "title", "desc"];
FOLLOWER.prototype.save = function (me) {
var str = ["prop:["];
for (var i = 0; i < SAVE_NUMPROP.length; i++) {
str.push(this[SAVE_NUMPROP[i]] || 0);
str.push(",");
}
str.push("0],");
var items = this.items || [];
str.push("items:[");
if (items) {
for (var i = 0; i < items.length; i++) {
if (i > 0) str.push(",");
items[i].save_db(str);
}
}
str.push("]");
if (this.skills) {
str.push(",skills:");
str.push(JSON.stringify(this.skills));
}
if (this.temp) {
str.push(",temp:", this.format_temp(this.temp));
}
if (this.settings) {
str.push(",settings:");
str.push(JSON.stringify(this.settings));
}
if (this.equipment) {
str.push(",eq:[");
for (var i = 0; i < this.equipment.length; i++) {
if (i > 0) str.push(",");
if (this.equipment[i]) this.equipment[i].save_db(str);
else str.push("null");
}
str.push("]");
}
return str.join("");
}
FOLLOWER.SAVE = function (me) {
if (!me.follower) return "[]";
var str = ["["];
for (var i = 0; i < me.follower.length; i++) {
var item = me.follower[i];
if (str.length > 1) str.push(",");
str.push('{path:"');
str.push(me.follower[i].path);
str.push('",id:"');
str.push(me.follower[i].id);
str.push('"');
var npc = FOLLOWER.STORES.get(me.id + "_" + item.id);
if (npc) {
str.push(",");
str.push(npc.save(me));
}
str.push('}');
}
str.push("]");
return str.join("");
}
var DIE_MSG = ["\n$N扑在地上挣扎了几下腿一伸口中喷出几口<HIR>鲜血</HIR>,死了!\n",
"\n$N大叫一声倒在地上挣扎了几下<HIR>死了</HIR>\n",
"\n$N口中喷出几口<HIR>鲜血</HIR>,倒在地上,死了!\n"];
FOLLOWER.prototype.die = function (killer) {
if (!this.environment) return;
if (this.on_die && this.on_die(killer) == false) {
this.hp = 1;
return false;
}
this.clear_status();
this.send_room(DIE_MSG.random());
var corpse = new CORPSE();
corpse.init(this, false);
this.environment.item_changed(corpse, true);
this.environment.item_changed(this, false);
this.environment = null;
}
FOLLOWER.prototype.heart_beat = function (dt) {
if (!this.hp) return;
// this.add_exp(this.grow_level, this.grow_level);
if (!this.fight_type) {
if (this.hp < this.max_hp) {
this.add_hp(parseInt(this.max_hp / 3));
}
if (this.mp < this.max_mp) {
this.add_mp(parseInt(this.max_mp / 3));
}
if (this.chat_msg) {
var r = this.random(10);
if (r > 7)
this.send_message(this.chat_msg.random());
}
}
if (this.state && (!this.fight_type || this.state.allow_fight)) {
this.state.heat_count += 1;
if (this.state.heat_count >= this.state.rate) {
this.state.heat_count = 0;
if (this.state.on_enter(this) === false) {
this.set_state(null, true);
}
}
}
}
FOLLOWER.prototype.set_state = function (state, isauto) {
if (this.state && !state) {
if (this.state.on_stop) {
if (this.state.on_stop(this, isauto) == false) {
return;
}
}
}
this.state = state;
if (state) {
state.rate = state.rate || 1;
state.heat_count = 0;
state.start_time = Date.now();
}
this.color_name = null;
this.environment && this.environment.item_changed(this, true);
this.master_json = null;
}
FOLLOWER.prototype.query_mastercommands = function () {
if (this.master_json) return this.master_json;
var json = {};
json.type = "item";
json.desc = this.desc;
json.id = this.id;
json.name = this.name;
json.commands = [];
json.commands.push({
cmd: "look " + this.id,
name: "查看"
});
json.commands.push({
cmd: "fight " + this.id,
name: "比试"
});
json.commands.push({
cmd: "score " + this.id,
name: "属性"
});
json.commands.push({
cmd: "pack " + this.id,
name: "背包"
});
json.commands.push({
cmd: "cha " + this.id,
name: "技能"
});
json.commands.push({
cmd: "team with " + this.id,
name: "组队"
});
json.commands.push({
cmd: "trade " + this.id,
name: "给" + this.call3() + "东西"
});
if (this.state) {
json.commands.push({
cmd: "dc " + this.id + " stopstate",
name: "停止" + this.state.title.replace('中', "")
});
}
if (this.actions) {
for (var i = 0; i < this.actions.length; i++) {
json.commands.push({
cmd: this.actions[i].cmd,
name: this.actions[i].name
});
}
}
this.master_json = JSON.stringify(json)
return this.master_json;
}
FOLLOWER.prototype.query_commands = function (player) {
if (player.id == this.master) {
return this.query_mastercommands(player);
}
if (this.json) return this.json;
var json = {};
json.type = "item";
json.desc = this.desc;
json.id = this.id;
json.follower = true;
json.commands = [];
json.commands.push({
cmd: "look " + this.id,
name: "查看"
});
if (!this.no_fight)
json.commands.push({
cmd: "fight " + this.id,
name: "比试"
});
json.commands.push({
cmd: "kill " + this.id,
name: "击杀"
});
json.commands.push({
cmd: "ask " + this.id + " about 主人",
name: "询问主人"
});
this.json = JSON.stringify(json)
return this.json;
}
FOLLOWER.prototype.on_ask = function (me, par) {
switch (par) {
case "主人":
me.notify(this.name + "说道:我的主人就是" + this.master_name + "呀。");
break;
}
}
FOLLOWER.prototype.on_teamin = function (me) {
if (!this.team) return;
for (var i = 0; i < this.team.length; i++) {
var tm = this.team[i];
if (this.master == tm.id) {
this.do_follow(tm);
}
}
}
FOLLOWER.prototype.on_teamout = function (me) {
if (!this.team) return;
for (var i = 0; i < this.team.length; i++) {
var tm = this.team[i];
if (this.master == tm.id) {
this.do_follow(null);
if (this.environment && this.environment.is_fb()) {
this.environment.item_changed(this, false, this.name + "离开了。");
}
}
}
}
FOLLOWER.prototype.long_name = function () {
if (this.color_name) return this.color_name;
var str = [];
if (this.title) {
str.push(this.title);
str.push(" "); this.name;
}
str.push(this.name);
if (this.state) {
str.push("<hig>&lt;" + this.state.title + "&gt;</hig>");
}
return this.color_name = str.join("");
}
FOLLOWER.prototype.on_enter = function (me) {
if (me.id == this.master) {
this.on_master_enter && this.on_master_enter(me);
}
}
FOLLOWER.prototype.on_master_leave = function (me, nextrm) {
if (this.state || !this.team || this.team != me.team) return false;
if (this.hp <= 0) return false;
if (me.environment === this.environment) return false;
//如果去副本或者家里就跟
if (nextrm.is_fb() || nextrm.parent.id == "home") {
return true;
}
//如果当前是副本就自己回去
//if (this.environment.is_fb())
// this.environment.item_changed(this, false, this.name + "离开了。");
return false;
}

114
os/char/monster.js Normal file
View File

@@ -0,0 +1,114 @@
require("../util/util.js");
require("./character");
MONSTER = function () {
this.hp = this.max_hp = 100;
this.mp = this.max_mp = 100; this.auto_pfm = true;
this.family = FAMILIES.MONSTER;
this.str = this.con = this.dex = this.int = 20;
}
MONSTER.inherits(CHARACTER);
MONSTER.prototype.can_speek = false;
MONSTER.prototype.init_skill = function () {
this.attack_skill = this.query_used_skill(BASE_SKILLS.BITE);
this.dodge_skill = this.query_used_skill(BASE_SKILLS.DODGE);
this.parry_skill = this.query_used_skill(BASE_SKILLS.PARRY);
this.force_skill = this.query_used_skill(BASE_SKILLS.FORCE);
this.noweapon_skill = this.attack_skill;
}
MONSTER.prototype.query_desc = function (me) {
return this.query_commands(me);
}
MONSTER.prototype.query_commands = function (player) {
if (this.json) return this.json;
var json = {};
json.type = "item";
json.desc = this.name + "\n" + this.desc;
json.id = this.id;
json.commands = [];
json.commands.push({
cmd: "kill " + this.id,
name: "击杀"
});
if (this.actions) {
for (var cmd in this.actions) {
if (!this.actions[cmd].name) continue;
json.commands.push({
cmd: cmd + " " + this.id,
name: this.actions[cmd].name
});
}
}
this.json = JSON.stringify(json)
return this.json;
}
MONSTER.prototype.call3 = function () {
return "它";
}
MONSTER.prototype.destroy = function (msg) {
if (this.environment) {
this.environment.item_changed(this, false, msg);
}
}
MONSTER.prototype.die = function (killer) {
if (!this.environment) return;
if (this.on_die && this.on_die(killer) === false) {
this.hp = 1;
return false;
}
this.hp = 0;
this.clear_status();
this.send_message(this.name + "惨嚎一声,死了!");
var corpse = new CORPSE();
var isinfb = this.environment.is_fb();
corpse.init(this, isinfb);
this.die_room = this.environment;
this.environment.item_changed(corpse, true);
this.environment.item_changed(this, false);
if (isinfb && this.score && killer) {
//副本分数
killer.add_fbscore(this.score);
}
this.on_died && this.on_died(killer, corpse);
WORLD.auto_get(killer, corpse, this);
if (killer && killer.attack_skill && killer.attack_skill.on_enemy_die) {
killer.attack_skill.on_enemy_die(killer, this);
}
}
MONSTER.prototype.query_part = function () {
return MONSTER_PARTS.random();
}
MONSTER.prototype.heart_beat = function (dt) {
if (!this.fight_type && this.hp > 0) {
if (this.hp < this.max_hp) {
this.add_hp(parseInt(this.max_hp / 2));
}
if (this.mp < this.max_mp) {
this.add_mp(parseInt(this.max_mp / 2));
}
if (this.chat_msg) {
var r = this.random(10);
if (r > 5)
this.send_message(this.chat_msg.random());
}
}
}
var MONSTER_PARTS = [
{ name: "左爪", hert: 0.8, crit: 0 },
{ name: "右爪", hert: 0.8, crit: 0 },
{ name: "后腿", hert: 0.85, crit: 0 },
{ name: "小腹", hert: 0.91, crit: 3 },
{ name: "胸前", hert: 0.95, crit: 4 },
{ name: "背部", hert: 0.97, crit: 4 },
{ name: "头部", hert: 1.2, crit: 10 },
{ name: "颈部", hert: 1.1, crit: 5 },
{ name: "前肢", hert: 0.85, crit: 1 },
{ name: "腰间", hert: 0.99, crit: 5 },
];

227
os/char/npc.js Normal file
View File

@@ -0,0 +1,227 @@
NPC = function () {
this.hp = this.max_hp = 100;
this.mp = this.max_mp = 100;
this.str = this.con = this.dex = this.int = this.per = this.age = 20;
this.family = FAMILIES.NONE;
this.auto_pfm = true;
}
NPC.inherits(CHARACTER);
NPC.prototype.set_chat_msg = function (items, chance) {
if (items) {
this.chat_msg = items;
//this.chat_chance = chance || 10;
}
}
NPC.prototype.do_chat_msg = function () {
if (!this.is_fighting() && this.is_living && this.chat_msg) {
this.do_say(this.chat_msg.random());
}
}
NPC.prototype.format_equipments = function (call3, str, eqcmd) {
if (this.equipment && this.equipment.length) {
var eqstr = [];
for (var i = 0; i < this.equipment.length; i++) {
var item = this.equipment[i];
if (!item) continue;
eqstr.push("<span cmd='", eqcmd || "look", " ", (i),
" of ", this.id, "'>◆", item.color_name, "</span>\n");
}
if (eqstr.length) {
return str.push(call3, "装备着:\n", eqstr.join(""));
}
}
str.push(call3, "穿着一件<wht>布衣</wht>。\n");
}
NPC.prototype.set_goods = function () {
if (!arguments.length) return;
this.sell_list = [];
for (var i = 0; i < arguments.length; i++) {
var item = arguments[i];
var obj = OBJ.CREATE(item);
if (!obj) continue;
obj.count = -1;
this.sell_list.push(obj);
}
}
NPC.prototype.query_commands = function (player) {
if (this.json) return this.json;
this.json = this.query_commands_json(player, false);
return this.json;
}
NPC.prototype.query_commands_json = function (player, isyb) {
var json = {};
json.type = "item";
json.desc = this.desc;
json.id = this.id;
json.name = this.name;
json.commands = [];
json.commands.push({
cmd: "look " + this.id,
name: "查看"
});
if (!this.no_fight)
json.commands.push({
cmd: "fight " + this.id,
name: "比试"
});
json.commands.push({
cmd: "kill " + this.id,
name: "击杀"
});
if (this.on_master) {
json.commands.push({
cmd: "bai " + this.id,
name: "拜师"
});
}
if (this.on_checkskill || this.on_master) {
json.commands.push({
cmd: "cha " + this.id,
name: "学习"
});
json.master = true;
}
if (this.sell_list) {
json.commands.push({
cmd: "list " + this.id,
name: "购买"
});
json.trader = true;
}
if (this.question) {
for (var cmd in this.question) {
json.commands.push({
cmd: "ask " + this.id + " about " + cmd,
name: "询问" + cmd
});
}
}
if (this.actions) {
for (var cmd in this.actions) {
if (!this.actions[cmd].name) continue;
json.commands.push({
cmd: cmd + " " + this.id,
name: this.actions[cmd].name
});
}
}
return JSON.stringify(json);
}
NPC.prototype.update_action = function (acts) {
this.json = null;
this.actions = acts;
}
var DIE_MSG = ["\n$N扑在地上挣扎了几下腿一伸口中喷出几口<HIR>鲜血</HIR>,死了!\n",
"\n$N大叫一声倒在地上挣扎了几下<HIR>死了</HIR>\n",
"\n$N口中喷出几口<HIR>鲜血</HIR>,倒在地上,死了!\n"];
NPC.prototype.die = function (killer) {
if (!this.environment) return;
if (this.on_die && this.on_die(killer) == false) {
this.hp = 1;
return false;
}
this.hp = 0;
this.clear_status();
this.send_room(DIE_MSG.random());
this.clear_follow();
var corpse = new CORPSE();
var isinfb = this.environment.is_fb();
corpse.init(this, isinfb);
this.die_room = this.environment;
this.environment.item_changed(corpse, true);
this.environment.item_changed(this, false);
if (isinfb && this.score && killer && killer.add_fbscore) {
//副本分数
killer.add_fbscore(this.score);
}
if (!isinfb && !this.no_refresh && !this.master && !this.die_room.is_shadow) {
this.call_out(this.relive, this.on_master ? 60000 : 300000);
}
this.on_died && this.on_died(killer, corpse);
WORLD.auto_get(killer, corpse, this);
if (killer && killer.attack_skill && killer.attack_skill.on_enemy_die) {
killer.attack_skill.on_enemy_die(killer, this);
}
}
NPC.prototype.relive = function () {
if (!this.die_room) return;
var room = ROOM.Get(this.die_room.path);
var obj = room.find_obj_bypath(this.path);
if (obj) return;
obj = NPC.CLONE(this.path);
room.item_changed(obj, true);
this.die_room = null;
this.equipment = null;
this.items = null;
this.skills = null;
}
NPC.prototype.destroy = function (msg) {
if (this.environment) {
this.environment.item_changed(this, false, msg);
}
this.clear_follow();
}
NPC.prototype.heart_beat = function (dt) {
if (!this.fight_type) {
if (this.hp < this.max_hp) {
this.add_hp(parseInt(this.max_hp / 2));
}
if (this.mp < this.max_mp) {
this.add_mp(parseInt(this.max_mp / 2));
}
if (this.chat_msg) {
if (this.random(10) > 8)
this.send_message(this.chat_msg.random());
}
this.on_heart_beat && this.on_heart_beat(dt);
} else if (this.hp <= 0) {
var eny = this.query_enemy();
if (!eny) {
this.hp = 1;
this.fight_type = 0;
}
}
}
NPC.CREATE = function (path, env, oncreate, count) {
if (!path || !env) return;
if (env.environment) env = env.environment;
count = count || 1;
let obj = null;
for (let i = 0; i < count; i++) {
obj = NPC.CLONE(path);
env.item_changed(obj, true);
if (oncreate) oncreate(obj);
}
return obj;
}
NPC.CLONE = function (path) {
let base = NPC.GET(path);
let item = Object.create(base);
item.clone();
return item;
}
NPC.GET = function (path) {
let base = WORLD.NPC_STROE.get(path);
if (!base) {
base = BASE.CREATE(__PATH.NPC, path);
if (!base) throw new Error('没有人物' + path + "的定义。");
//这里会自己调用create方法存储到NPC_STROE记住了吗
}
return base;
}

845
os/char/user.js Normal file
View File

@@ -0,0 +1,845 @@
require("./character.js");
USER = function () {
this.socket = null;
this.family = FAMILIES.NONE;
this.max_item_count = 20;
this.max_store_count = 20;
this.money = 0;
this.request_count = 0;
this.cash_money = 0;
this.score = 0;
this.follower = null;
this.password = "";
this.loginTime = 0;
this.id_address = null;
this.user_level = 0;
this.eq_group = 0;
};
USER.inherits(CHARACTER);
USER.prototype.is_player = true;
USER.prototype.notify = function (text) {
//玩家不能接收消息的状态 不发送
if (this.socket && !this.is_faint && text && text.length < 30240)
this.socket.send(text);
}
USER.prototype.send = function (text) {
//直接发送消息 不管玩家状态
if (this.socket && text && text.length < 30240) {
this.socket.send(text);
}
}
USER.prototype.notify_fail = function (text) {
if (this.socket && !this.is_faint)
this.socket.send(text);
return false;
}
USER.prototype.send_warn = function (content, cmds, time) {
var str = ["{type:\"warn\",content:\""];
str.push(content);
str.push("\"");
if (time) {
str.push(",time:");
str.push(time);
}
str.push(",cmds:[");
for (var i = 0; i < cmds.length; i += 2) {
if (i > 0) str.push(",");
str.push("{cmd:\"");
str.push(cmds[i]);
str.push("\",name:\"");
str.push(cmds[i + 1]);
str.push("\"}");
}
str.push("]}");
this.send(str.join(""));
}
USER.prototype.send_commands = function () {
var str = ["{type:\"cmds\",items:["];
for (var i = 0; i < arguments.length; i += 2) {
if (i > 0) str.push(",");
str.push("{cmd:\"");
str.push(arguments[i]);
str.push("\",name:\"");
str.push(arguments[i + 1]);
str.push("\"}");
}
str.push("]}");
this.send(str.join(""));
}
USER.prototype.is_connect = function () {
return this.socket !== null;
}
USER.prototype.send_loginmessage = function () {
if (!this.login_message) {
var str = ['{type:"login"'];
if (this.settings) {
str.push(",setting:")
str.push(JSON.stringify(this.settings));
this.no_message = this.settings['no_message'] == 1;
}
str.push(",id:\"");
str.push(this.id, '",level:', this.level);
str.push("}");
this.login_message = str.join("");
}
this.send(this.login_message)
}
USER.prototype.relogin = function (newUser) {
if (!newUser.socket) return;
newUser.socket.user = null;
this.socket = newUser.socket;
newUser.socket = null;
this.socket.user = this;
this.send_loginmessage();
if (!this.environment) {
var rm = ROOM.Get(this.quit_room);
if (!rm) {
return this.send("出现错误请联系管理员报告BUG谢谢");
}
this.environment = rm;
}
this.send(this.environment.to_json());
this.environment.send_exits(this);
this.send(this.environment.items_to_json());
// if (!WORLD.is_end_cross(this)) {
this.send_room(this.name + "重新连线。");
if (this.environment.on_relogin) {
this.environment.on_relogin(this);
}
// }
this.disconnect_time = 0;
this.check_state();
this.on_skillchanged();
}
USER.prototype.ip = function () {
return this.socket.remoteAddress;
}
USER.prototype.port = function () {
return this.socket.remotePort;
}
USER.prototype.quit = function () {
var rm = this.environment;
if (this.environment) {
this.team_out("离开了游戏,自动退出队伍");
this.environment.item_changed(this, false, this.name + "离开了游戏。");
this.environment = rm;
this.clear_follow();
this.environment.clear_copy(this);
this.environment.parent.on_leaved(this);
}
this.environment = null;
this.clear_status();
this.environment = rm;
WORLD.login_out(this);
this.environment = null;
this.clear_home();
if (this.socket) {
this.socket.user = null;
this.socket = null;
}
}
USER.prototype.in_world = function () {
//判断是否连线进入过游戏,
return !!this.environment && !!this.socket;
}
USER.prototype.disconnect = function (isreplace) {
if (this.environment && this.socket) {
// this.send_message(this.name + "断线了。");
if (isreplace)
this.send("<RED>有人使用你的角色从别的地址登陆游戏,请重新登陆</RED>");
}
this.disconnect_time = Date.now();
if (this.socket) {
let socket = this.socket;
this.socket = null;
socket.user = null;
socket.end();
//if (!socket.destroyed)
// socket.destroy();
}
}
USER.prototype.loadData = function (role) {
this.id = role.id;
this.name = role.name;
this.level = role.level;
//this.title = role.title;de
//role.data = role.data.toString();
var data = JSON.toObject(role.data);
for (var i = 0; i < SAVE_NUMPROP.length; i++) {
this[SAVE_NUMPROP[i]] = data.prop[i] || 0;
}
this.quit_room = data.quit_room;
this.items = this.read_items(data.items);
this.stores = this.read_items(data.stores);
this.books = data.books ?? [];
this.equipment = this.read_items(data.eq);
this.settings = data.settings;
this.skills = data.skills ?? {};
this.eq_groups = data.eq_groups;
this.sk_groups = data.sk_groups ?? [null, [], []];
this.temp = data.temp;
this.read_titles(data.titles);
if (data.follower) {
this.follower = [];
FOLLOWER.INIT_FROM_USER(this, data.follower);
for (var i = 0; i < data.follower.length; i++) {
this.follower.push({
id: data.follower[i].id,
path: data.follower[i].path
});
}
}
var fam = this.query_temp("family");
if (fam) {
this.family = FAMILIES[fam] || FAMILIES.NONE;
}
this.user_level = role.user_level;
}
USER.prototype.read_titles = function (titles) {
this.titles = [];
if (!titles) return;
for (let item of titles) {
this.titles.push({
title: item[0], type: item[1],
use: item[2] === 1
});
if (item[2]) {
this.title = item[0];
}
}
}
USER.prototype.read_items = function (items) {
var objs = [];
if (!items) return objs;
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (!item) {
objs.push(null);
continue;
}
var obj = OBJ.CREATE(item[0]);
if (obj) {
obj.load_db(item);
obj.on_load(this);
objs.push(obj);
}
}
return objs;
}
USER.prototype.do_login = function () {
this.init();
this.recount();
this.long_name();
WORLD.STATS.checkStats(this);
this.send_loginmessage();
if (this.family) this.family.on_login(this);
var rm = ROOM.Get(this.query_temp("new") ? "new/new1" : this.quit_room);
if (!rm || rm.is_fb()) rm = ROOM.Get(DEFAULT_ROOM);
if (rm.is_copy()) {
var copy_room = rm.query_copy2(this);
if (copy_room) {
this.moveto(copy_room, null, this.name + "连线进入这个世界。");
} else {
if (this.query_temp("new")) {
//还没完成新手教程的,从头开始
this.set_temp("new", 1);
this.items = [];//清理掉之前的物品
this.exp = this.pot = this.money = 0;
}
copy_room = rm.create_copy2(this);
this.moveto(copy_room);
}
//如果在副本副本下线,不可能
} else {
this.moveto(rm, null, this.name + "连线进入这个世界。");
}
this.check_state();
}
var DEFAULT_ROOM = "yz/wumiao";
var SAVE_NUMPROP = ["str", "con", "dex", "int", "gender", "max_mp", "limit_mp", "exp", "pot", "kar", "per"
, "hp", "mp", "max_item_count", "money", "reg_time",
"max_store_count", "cash_money", 'eq_group'];
USER.prototype.getData = function () {
var str = ["{prop:["];
for (var i = 0; i < SAVE_NUMPROP.length; i++) {
str.push(this[SAVE_NUMPROP[i]]);
str.push(",");
}
str.push(0);
str.push("],quit_room:\"");
if (this.environment) {
if (this.environment.is_fb() || this.environment.no_save
|| this.environment.parent.no_save) {
str.push(this.query_temp("enter_room"));
} else {
str.push(this.environment.path);
}
} else {
str.push(this.query_temp("enter_room", DEFAULT_ROOM));
}
str.push("\"");
var items = this.items;
if (items) {
str.push(",items:[");
for (let i = 0; i < items.length; i++) {
if (i > 0) str.push(",");
items[i].save_db(str);
}
str.push("]");
}
items = this.stores;
if (items) {
str.push(",stores:[");
for (let i = 0; i < items.length; i++) {
if (i > 0) str.push(",");
items[i].save_db(str);
}
str.push("]");
}
items = this.books;
if (items && items.length > 0) {
str.push(',books:["', items.join('", "'), '"]');
}
if (this.skills) {
str.push(",skills:");
str.push(JSON.stringify(this.skills));
}
str.push(",temp:", this.format_temp(this.temp));
if (this.settings) {
str.push(",settings:");
str.push(JSON.stringify(this.settings));
}
if (this.equipment) {
str.push(",eq:[");
for (var i = 0; i < this.equipment.length; i++) {
if (i > 0) str.push(",");
if (this.equipment[i]) this.equipment[i].save_db(str);
else str.push("null");
}
str.push("]");
}
if (this.titles) {
str.push(",titles:[");
for (var i = 0; i < this.titles.length; i++) {
if (i > 0) str.push(",");
var item = this.titles[i];
str.push('["', item.title, '","', item.type, '"');
if (item.use) str.push(',1');
str.push(']');
}
str.push("]");
}
if (this.follower) {
str.push(",follower:");
str.push(FOLLOWER.SAVE(this));
}
str.push(',eq_groups:[');
for (let i = 0; i < this.eq_groups.length; i++) {
if (i > 0) str.push(',');
if (i === this.eq_group || !this.eq_groups[i]) str.push('[]');
else str.push('["', this.eq_groups[i].join('","'), '"]');
}
str.push('],sk_groups:[');
for (let i = 0; i < this.sk_groups.length; i++) {
if (i > 0) str.push(',');
if (!this.sk_groups[i]) str.push('0');
else str.push('["', this.sk_groups[i].join('","'), '"]');
}
str.push("]}");
var role = {};
role.id = this.id;
role.userid = this.userid;
role.name = this.name;
role.level = this.level;
role.title = this.title || this.get_level_desc();
role.data = str.join("");
return role;
}
USER.prototype.save = function () {
WORLD.DB.saveRole(this.getData());
}
USER.prototype.die = function (killer) {
if (this.on_die && this.on_die(killer) === false) {
this.hp = 1;
return false;
}
this.clear_status();
this.hp = 0;
this.mp = 0;
this.send_room(DIE_MSG.random());
var env = this.environment;
if (env.items.length < 10) {
var corpse = new CORPSE();
corpse.init(this);
env.item_changed(corpse, true);
}
env.item_changed(this, false);
this.environment = env;
this.check_state();
WORLD.on_user_die(this, killer);
this.on_died(killer);
}
USER.prototype.on_died = function () {
}
USER.prototype.check_state = function () {
if (this.hp <= 0) {
if (this.state) this.set_state(null);
this.send('{type:"die",commands:[{cmd:"relive",name:"去武庙复活"},{cmd:"relive locale",name:"原地复活"}]}');
} else {
if (this.state) this.set_state(this.state);
}
}
USER.prototype.query_commands = function (player) {
if (this.commands_json) return this.commands_json;
var json = {};
json.type = "item";
json.desc = this.long_name();
json.id = this.id;
json.commands = [];
json.commands.push({
cmd: "look " + this.id,
name: "查看"
});
if (player != this) {
if (!this.no_fight)
json.commands.push({
cmd: "fight " + this.id,
name: "比试"
});
json.commands.push({
cmd: "kill " + this.id,
name: "击杀"
});
json.commands.push({
cmd: "team add " + this.id,
name: "邀请组队"
});
if (this.level > 1 && !this.query_setting("ban_master") && !this.query_temp("tudi") && !this.query_temp("shifu")) {
json.commands.push({
cmd: "baishi " + this.id,
name: "拜师"
});
}
}
this.commands_json = JSON.stringify(json)
return this.commands_json;
}
USER.prototype.query_title = function (type) {
if (!this.titles) return null;
for (var i = 0; i < this.titles.length; i++) {
if (this.titles[i].type == type) {
return this.titles[i].title;
}
}
}
USER.prototype.add_title = function (title, type) {
if (!this.titles) this.titles = [];
var obj = { title: title, type: type };
for (var i = 0; i < this.titles.length; i++) {
if (this.titles[i].type == type) {
obj.use = this.titles[i].use;
this.titles.splice(i, 1);
break;
}
}
if (obj.title) {
if (!this.titles.length) obj.use = true;
this.titles.push(obj);
}
if (obj.use) {
if (!title) {
if (this.titles.length) {
this.titles[0].use = true;
title = this.titles[0].title;
}
}
this.title = title;
this.color_name = null;
if (this.environment)
this.environment.item_changed(this, true);
}
}
USER.prototype.query_setting = function (name) {
if (!this.settings) return 0;
return this.settings[name] || 0;
}
USER.prototype.set_setting = function (name, value) {
if (!this.settings) this.settings = {};
if (!value || value == "0") {
delete this.settings[name];
} else {
if (value == "1") value = 1;
this.settings[name] = value;
}
this.login_message = null;
}
USER.prototype.heart_beat = function (dt) {
this.request_count = 0;
if (this.state && (!this.fight_type || this.state.allow_fight)) {
this.state.heat_count += 1;
if (this.state.heat_count >= this.state.rate) {
this.state.heat_count = 0;
if (this.state.on_enter(this, dt) === false) {
this.set_state(null, true);
}
}
}
this.on_heart_beat && this.on_heart_beat(dt);
if (this.disconnect_time) {
//如果断线 在挂机就一天没有就5分钟下线
if (dt - this.disconnect_time > (this.state ? 86400000 : 3600000)) {
return this.quit();
}
}
}
USER.prototype.set_state = function (state, isauto) {
if (this.state && !state) {
if (this.state.on_stop) {
if (this.state.on_stop(this, isauto) == false) {
return;
}
}
this.send("{type:\"state\"}");
}
this.state = state;
if (state) {
state.rate = state.rate || 1;
state.heat_count = 0;
state.start_time = Date.now();
var msg = "{type:\"state\",state:\"你正在" + state.title + "\"";
if (state.desc) {
msg += ",desc:" + state.desc;
}
if (state.no_stop) {
msg += ",no_stop:true";
}
if (state.commands) {
msg += ",commands:" + state.commands;
}
this.send(msg + "}");
}
this.color_name = null;
if (this.environment)
this.environment.item_changed(this, true);
}
USER.prototype.get_state = function () {
var str = "";
if (!this.socket) str += "<red>&lt;断线中&gt;</red>";
if (this.state) str += ("<hig>&lt;" + this.state.title + "&gt;</hig>");
return str;
}
const LEVELS_TITLES = ["普通百姓", "武士", "武师", "宗师", "武圣", "武帝", "武神"];
USER.prototype.long_name = function () {
if (!this.color_name) {
var cc = this.get_level_color();
var str = [];
if (cc) {
str.push("<");
str.push(cc);
str.push(">");
}
if (this.title) {
str.push(this.title);
str.push(" ");
}
if (!this.title || this.level > 0) {
str.push(LEVELS_TITLES[this.level]);
str.push(" ");
}
str.push(this.name);
if (cc) {
str.push("</");
str.push(cc);
str.push(">");
}
this.color_name = str.join("");
this.commands_json = null;
}
return this.color_name + this.get_state();
}
USER.prototype.init_tasks = function () {
for (var i = 0; i < WORLD.TASKS.length; i++) {
var task = WORLD.TASKS[i];
task.on_start && task.on_start(this);
}
}
USER.prototype.query_jingli = function () {
var expend = this.query_temp("ex_jl") || 0;
return 200 - expend + (this.query_temp("add_jl") || 0);
}
const jclimits = [1000, 2000, 3000, 5000, 7000, 10000, 15000];
USER.prototype.query_jclimit = function () {
return jclimits[this.level] || 1000;
}
USER.prototype.add_obj = function (obj, count) {
if (!obj) return;
if (typeof obj == "string") {
obj = OBJ.clone_to(obj, this, count);
if (!obj) return;
} else {
obj = this.push_item(obj);
}
this.items_changed(obj);
obj.notify_action(this, true);
return obj;
}
USER.prototype.remove_obj = function (obj, count) {
if (typeof obj == "string") {
obj = this.find_obj(obj);
}
if (!obj) return;
count = count || obj.count || 1;
var newobj = this.remove_item(obj, count);
if (newobj == obj) {
obj.notify_action(this, false);
}
this.items_changed(obj, count);
return newobj;
}
USER.prototype.items_changed = function (item, drop_count) {
if (drop_count) {
this.send('{type:"dialog",dialog:"pack",id:"' + item.id + '",remove:' + drop_count + ',money:' + this.money + '}');
} else {
if (item.is_money) {
return this.send('{type:"dialog",dialog:"pack",money:' + this.money + '}');
}
var str = ['{type:"dialog",dialog:"pack",'];
str.push('name:"');
str.push(item.color_name);
str.push('",id:"');
str.push(item.id);
str.push('",count:');
str.push(item.count);
str.push(',grade:');
str.push(item.grade);
str.push(',unit:"');
str.push(item.unit);
str.push('"');
if (item.is_equipment) {
str.push(',can_eq:1');
}
if (item.on_use) {
str.push(',can_use:1');
}
if (item.on_study) {
str.push(',can_study:1');
}
if (item.on_open) {
str.push(',can_open:1');
}
if (item.combine_count) {
str.push(',can_combine:' + item.combine_count);
}
str.push(',value:');
str.push(item.transable ? item.value : 0);
str.push(",money:");
str.push(this.money);
str.push('}');
this.send(str.join(""));
}
}
//初始化人物使用的技能
USER.prototype.on_skillchanged = function () {
var str = ["{type:\"perform\",skills:["];
if (this.skills) {
var bases = ["", "force", "unarmed", "dodge", "parry", "throwing"];
var weapon = this.query_weapon_type(), base_type = null;
if (weapon != WEAPON_TYPE.NONE) bases[0] = weapon;
for (var i = 0; i < bases.length; i++) {
base_type = bases[i];
if (!base_type) continue;
var base_skill = this.skills[base_type];
if (base_skill) {
var sp_skill = SKILL.get(base_skill.enable_skill || base_type), pfmitem = null;
if (sp_skill && sp_skill.pfm) {
let sk_level = this.query_skill(base_skill.enable_skill || base_type, 0);
for (var p in sp_skill.pfm) {
pfmitem = sp_skill.pfm[p];
if (pfmitem.check && !pfmitem.check(this,
sk_level, base_type)) continue;
if (pfmitem.enable_skill && pfmitem.enable_skill != base_type) continue;
if (str.length > 1) str.push(",");
str.push("{id:\"");
str.push(base_type + "." + p);
str.push("\",name:\"");
str.push(pfmitem.query_name(this, base_type));
str.push("\"");
if (pfmitem.distime) {
str.push(",distime:");
str.push(pfmitem.query_distime(this));
}
str.push("}");
}
}
pfmitem = this.query_ref_skill(this.skills[base_skill.enable_skill]);
if (pfmitem && pfmitem.enable_skill && pfmitem.enable_skill == bases[i]) {
if (str.length > 1) str.push(",");
str.push("{id:\"");
str.push(bases[i] + ".ref");
str.push("\",name:\"");
str.push(pfmitem.query_name(this, base_type));
str.push("\"");
if (pfmitem.distime) {
str.push(",distime:");
str.push(pfmitem.query_distime(this, this.query_skill(base_skill.enable_skill), true));
}
str.push("}");
}
}
}
}
str.push("]");
str.push("}");
this.send(str.join(""));
}
USER.prototype.go_home = function () {
let my_room = this.query_home();
this.moveto(my_room, this.name + "向里面走去。");
}
USER.prototype.query_home = function (rm_name) {
let home = this.query_temp("home");
if (!home) return null;
if (!rm_name) rm_name = home == 1 ? "home/danjian" : "home/yuanzi";
let rm = ROOM.Get(rm_name);
let my_room = rm.query_copy2(this);
if (!my_room) {
my_room = rm.create_copy2(this);
}
return my_room;
}
USER.prototype.add_score = function (val) {
if (!val) return;
this.score += val;
WORLD.STATS.updateScore(this);
}
USER.prototype.add_money = function (val) {
let money = parseInt(this.money + val);
if (!(money >= 0)) return false;
this.money = money;
//this.send(`{"type":"dialog","dialog":"pack","money":${money}}`);
return true;
}
USER.prototype.add_cash = function (count, desc) {
if (!(count > 0 || count < 0)) return;
this.cash_money += count;
WORLD.log(this, count, desc);
if (count >= 0) {
this.notify("<hio>你获得了" + count + "元宝。</hio>");
}
this.send(`{"type":"dialog","dialog":"shop","money":[${this.money},${this.cash_money}]}`);
}
USER.prototype.query_cash = function (is_cash) {
return this.cash_money;
}
USER.prototype.can_follow = function (npc) {
if (!this.follower) this.follower = [];
var max = this.query_temp("max_follower") || 3;
if (this.follower.length >= max) return false;
for (var i = 0; i < this.follower.length; i++) {
if (this.follower[i].path == npc.path) {
return false;
}
}
return true;
}
USER.prototype.add_follower = function (npc) {
if (!this.can_follow(npc)) return false;
var item = {
path: npc.path,
id: npc.id
};
this.follower.push(item);
FOLLOWER.INIT(this, item);
return true;
}
USER.prototype.clear_home = function (clear_follower = true) {
var home = ROOM.Get("home/yuanzi");
if (home) {
home = home.query_copy(this.id)
if (home)
home.clear_copy(this);
}
if (clear_follower)
FOLLOWER.CLEAR(this);
else
FOLLOWER.RESET(this);
}
USER.prototype.clear_distime = function (pfmid) {
if (!this.temp) return;
if (pfmid) {
this.temp["pfm/" + pfmid] = null;
this.send('{type:"clearDistime",id:"' + pfmid + '"}');
} else {
for (var key in this.temp) {
if (key.startsWith("pfm/")) {
this.temp[key] = null;
}
}
this.send('{type:"clearDistime"}');
}
}
var DIE_MSG = ["\n$N扑在地上挣扎了几下腿一伸口中喷出几口<HIR>鲜血</HIR>,死了!\n",
"\n$N大叫一声倒在地上挣扎了几下<HIR>死了</HIR>\n",
"\n$N口中喷出几口<HIR>鲜血</HIR>,倒在地上,死了!\n"];
USER.prototype.add_combat_prop = function (name, val) {
this.add_prop(name, val);
if (!this.combat_props) this.combat_props = [];
this.combat_props.push([name, val]);
}
USER.prototype.clear_combat_prop = function (name, val) {
if (this.combat_props) {
for (let i = 0; i < this.combat_props.length; i++) {
this.add_prop(this.combat_props[i][0], -this.combat_props[i][1]);
}
this.combat_props = null;
this.recount();
this.notify_hp();
}
}