init: add workspace files
This commit is contained in:
234
os/char/chara_comm.js
Normal file
234
os/char/chara_comm.js
Normal 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
175
os/char/chara_equip.js
Normal 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
169
os/char/chara_move.js
Normal 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
137
os/char/chara_prop.js
Normal 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
566
os/char/chara_skill.js
Normal 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
351
os/char/character.js
Normal 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
250
os/char/combat.js
Normal 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
485
os/char/follower.js
Normal 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><" + this.state.title + "></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
114
os/char/monster.js
Normal 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
227
os/char/npc.js
Normal 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
845
os/char/user.js
Normal 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><断线中></red>";
|
||||
if (this.state) str += ("<hig><" + this.state.title + "></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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user