init: add workspace files
This commit is contained in:
179
os/base.js
Normal file
179
os/base.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
|
||||
定义当对象从文件生成时的基类,
|
||||
当文件内部调用this.inherit(父类名)后,将真正继承父类的原型和实例属性。
|
||||
但是文件内部不能修改this.prototype,修改将会作用到父类上面。
|
||||
可以用this.XXX扩展属性和方法
|
||||
*/
|
||||
|
||||
BASE = function () {
|
||||
|
||||
}
|
||||
|
||||
BASE.prototype.set = function (pars) {
|
||||
if (!pars) return;
|
||||
for (var item in pars) {
|
||||
this[item] = pars[item];
|
||||
}
|
||||
}
|
||||
/*
|
||||
该方法使用直接赋值方式继承父对象的所有原型方法,
|
||||
如果子对象对原型修改,将会改变父对象的原型。
|
||||
所以该方法只能获取父对象的原型不能修改它,
|
||||
|
||||
实际上是作为new的另外一种方式,通过apply获取实例属性,通过__proto__获取父类原型
|
||||
|
||||
*/
|
||||
BASE.prototype.inherits = function (ctor) {
|
||||
this.__proto__ = ctor.prototype;
|
||||
ctor.apply(this);
|
||||
}
|
||||
/*
|
||||
create方法由继承自base类的类自己实现,当对象被从文件创建时候调用
|
||||
参数fname=该对象的文件的相对路径,ctor=构造方法
|
||||
*/
|
||||
BASE.prototype.create = function (fname, ctor) {
|
||||
}
|
||||
BASE.prototype.add_event = function (fname, func, time) {
|
||||
///在time秒内用新的func替换旧的fname方法
|
||||
if (!this[fname])
|
||||
this[fname] = this.fire_event.bind(this, fname);
|
||||
if (!this._events) this._events = {};
|
||||
if (!this._events[fname]) this._events[fname] = [];
|
||||
this._events[fname].push({
|
||||
func: func,
|
||||
time: time ? (Date.now() + time) : Number.MAX_SAFE_INTEGER
|
||||
});
|
||||
//var old_func = this[fname];
|
||||
//this[fname] = func;
|
||||
//if (time) this.call_out(() => this[fname] = old_func, time);
|
||||
//return old_func;
|
||||
}
|
||||
BASE.prototype.remove_event = function (name, func) {
|
||||
if (!this._events) return;
|
||||
var evts = this._events[name];
|
||||
if (!evts) return;
|
||||
for (var i = 0; i < evts.length; i++) {
|
||||
if (evts[i].func === func) {
|
||||
evts.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (!evts.length) {
|
||||
this._events[name] = null;
|
||||
this[name] = null;
|
||||
}
|
||||
}
|
||||
BASE.prototype.fire_event = function (name) {
|
||||
if (!this._events) return;
|
||||
var evts = this._events[name];
|
||||
if (!evts) return;
|
||||
var dt = Date.now();
|
||||
for (var i = 0; i < evts.length; i++) {
|
||||
if (evts[i].time > dt) {
|
||||
if (evts[i].func.call(this) == false) return false;
|
||||
} else {
|
||||
evts.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (!evts.length) {
|
||||
this._events[name] = null;
|
||||
this[name] = null;
|
||||
}
|
||||
}
|
||||
/*
|
||||
生成对象标识,前8位是毫秒级时间戳的36进制形式,后4位随机码,
|
||||
最起码保证每毫秒生成的标识不会重复
|
||||
*/
|
||||
var key = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
BASE.prototype.create_uid = function () {
|
||||
var str = [];
|
||||
str.push(Date.now().toString(36));
|
||||
var length = key.length;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
str.push(key[Math.floor(Math.random() * length)]);
|
||||
}
|
||||
return str.join("");
|
||||
}
|
||||
BASE.prototype.random = function (num) {
|
||||
return Math.floor(Math.random() * num);
|
||||
}
|
||||
BASE.prototype.call_out = function (func, time, arg1, arg2) {
|
||||
return setTimeout(func.bind(this, arg1, arg2), time);
|
||||
}
|
||||
BASE.prototype.call_interval = function (func, time, count, end_func) {
|
||||
count--;
|
||||
var index = 0;
|
||||
if (func(index++) === false || count === 0) {
|
||||
return end_func && end_func();
|
||||
}
|
||||
var handler = 0;
|
||||
handler = setInterval(function () {
|
||||
|
||||
count--;
|
||||
if (func(index++) === false || count === 0) {
|
||||
clearInterval(handler);
|
||||
end_func && end_func();
|
||||
}
|
||||
}, time);
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
const vm = require('vm');
|
||||
const fs = require("fs");
|
||||
//根据文件路径new一个对象
|
||||
BASE.ITEMS = {};
|
||||
BASE.CREATE = function (path, fname) {
|
||||
|
||||
var ary = BASE.PATH_REG.exec(fname);
|
||||
if (!ary) {
|
||||
return console.error("path %s is incorrect:", path + fname);
|
||||
}
|
||||
fname = ary[1];
|
||||
var paras = ary[2];
|
||||
var fkey = path + fname;
|
||||
var func = BASE.ITEMS[fkey];
|
||||
if (func) {
|
||||
return BASE.NEW(fname, func, paras);
|
||||
}
|
||||
const filepath = fkey + ".js";
|
||||
try {
|
||||
const script = fs.readFileSync(filepath);
|
||||
func = vm.compileFunction(script.toString(), [],
|
||||
{ filename: filepath });
|
||||
|
||||
BASE.ITEMS[fkey] = func;
|
||||
return BASE.NEW(fname, func, paras);
|
||||
} catch (e) {
|
||||
console.error("create %s%s error:", filepath, e, e.stack);
|
||||
}
|
||||
}
|
||||
BASE.CLONE = function (fname) {
|
||||
}
|
||||
BASE.PATH_REG = /^(\w+(?:\/\w+)*)(#\w+)?$/;
|
||||
BASE.NEW = function (fname, func, par) {
|
||||
var obj = new BASE();
|
||||
func.apply(obj);
|
||||
obj.path = fname;
|
||||
obj.create(fname, par);
|
||||
return obj;
|
||||
}
|
||||
|
||||
BASE.UPDATE = function (path, fname) {
|
||||
var ary = BASE.PATH_REG.exec(fname);
|
||||
if (!ary) {
|
||||
throw "path " + fname + " is incorrect:";
|
||||
}
|
||||
fname = ary[1];
|
||||
var fkey = path + fname;
|
||||
var data = fs.readFileSync(fkey + ".js");
|
||||
var func = new Function(data);
|
||||
BASE.ITEMS[fkey] = func;
|
||||
var obj = new BASE();
|
||||
func.apply(obj);
|
||||
obj.path = fname;
|
||||
obj.update && obj.update(fname, ary[2]);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
47
os/command.js
Normal file
47
os/command.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
所有命令的基类,
|
||||
自动加载所有定义在__COMMAND文件夹下的命令文件
|
||||
*/
|
||||
|
||||
|
||||
COMMAND = function () {
|
||||
this.allow_fight = true;
|
||||
this.allow_level = 0;
|
||||
}
|
||||
|
||||
COMMAND.inherits(BASE);
|
||||
//将命令绑定到某些对象上 调用obj.do_commandname();
|
||||
COMMAND.prototype.for_item = function (item, name) {
|
||||
if (this.exec) {
|
||||
name = name || this.command;
|
||||
item.prototype["do_" + name] = this.exec;
|
||||
}
|
||||
}
|
||||
COMMAND.prototype.create = function (fname) {
|
||||
// console.error("command %s success", fname);
|
||||
if (this.command) {
|
||||
var str = this.command.split(',');
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (WORLD.COMMANDS[str[i]]) console.error("command %s 重复", fname);
|
||||
WORLD.COMMANDS[str[i]] = this;
|
||||
}
|
||||
} else {
|
||||
console.error("command %s not have command name", fname);
|
||||
}
|
||||
}
|
||||
COMMAND.prototype.update = function () {
|
||||
if (this.command) {
|
||||
var str = this.command.split(',');
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
WORLD.COMMANDS[str[i]] = this;
|
||||
}
|
||||
} else {
|
||||
console.error("command %s not have command name", fname);
|
||||
}
|
||||
}
|
||||
COMMAND.DO = function (cmd, par1, par2, par3) {
|
||||
var cmd = WORLD.COMMANDS[cmd];
|
||||
if (cmd) {
|
||||
cmd.enter(null, par1, par2, par3);
|
||||
}
|
||||
}
|
||||
116
os/const.js
Normal file
116
os/const.js
Normal file
@@ -0,0 +1,116 @@
|
||||
SKILL_TYPES = {
|
||||
BASE: 0,
|
||||
SKILL: 1,
|
||||
KNOWLEDGE: 2
|
||||
};
|
||||
BASE_SKILLS = {
|
||||
FORCE: "force",
|
||||
DODGE: "dodge",
|
||||
PARRY: "parry",
|
||||
BITE: "bite"
|
||||
};
|
||||
|
||||
EQUIP_TYPE = {
|
||||
WEAPON: 0,
|
||||
CLOTH: 1,
|
||||
SHOES: 2,
|
||||
HEAD: 3,
|
||||
CAPE: 4,
|
||||
RING: 5,
|
||||
NECKLACE: 6,//项链
|
||||
JEWELS: 7,//饰品
|
||||
WRIST: 8,//护腕
|
||||
WAIST: 9,//腰带
|
||||
THROWING: 10//
|
||||
}
|
||||
WEAPON_TYPE = {
|
||||
NONE: "unarmed",
|
||||
SWORD: "sword",
|
||||
BLADE: "blade",
|
||||
STAFF: "staff",
|
||||
CLUB: "club",
|
||||
WHIP: "whip",
|
||||
THROWING: "throwing"
|
||||
}
|
||||
PROPERTIES = {
|
||||
"con1": "先天根骨",
|
||||
"dex1": "先天身法",
|
||||
"int1": "先天悟性",
|
||||
"str1": "先天臂力",
|
||||
"con": "根骨",
|
||||
"dex": "身法",
|
||||
"int": "悟性",
|
||||
"str": "臂力",
|
||||
"fy": "防御",
|
||||
"per": "容貌",
|
||||
"age": "年龄",
|
||||
gj: "攻击",
|
||||
ds: "躲闪",
|
||||
zj: "招架",
|
||||
mz: "命中",
|
||||
bj_per: "暴击",
|
||||
limit_mp: "内力上限",
|
||||
gjsd: "攻击速度",
|
||||
gjsd_per: "攻击速度",
|
||||
mz_per: "命中",
|
||||
max_hp: "气血",
|
||||
max_mp: "内力",
|
||||
releasetime: "绝招释放时间",
|
||||
distime: "绝招冷却时间",
|
||||
expend_mp: "内力消耗",
|
||||
releasetime_per: "绝招释放时间",
|
||||
distime_per: "绝招冷却时间",
|
||||
expend_mp_per: "内力消耗",
|
||||
add_sh_per: "最终伤害",
|
||||
add_bjsh_per: "暴击伤害",
|
||||
diff_sh_per: "伤害减免",
|
||||
diff_sh: "受到的伤害减少",
|
||||
diff_fy_per: "忽视对方防御",
|
||||
fy_per: "防御",
|
||||
zj_per: "招架",
|
||||
gj_per: "攻击",
|
||||
ds_per: "躲闪",
|
||||
hp_per: "气血",
|
||||
study_per: "学习效率",
|
||||
dazuo_per: "打坐效率",
|
||||
lianxi_per: "练习效率",
|
||||
busy: "忙乱时间",
|
||||
busy_per: "忙乱时间",
|
||||
diff_busy: "忽视忙乱",
|
||||
diff_busy_per: "忽视忙乱",
|
||||
diff_bj: "暴击抵抗",
|
||||
add_sh: "伤害增加",
|
||||
diff_downside: "负面状态抵抗",
|
||||
diff_downside_per: "负面状态抵抗",
|
||||
dazuo: "打坐效率",
|
||||
|
||||
diff_sh_per2: "伤害减免",
|
||||
diff_fy_per2: "伤害减免",
|
||||
recover_per: "疗伤效果",
|
||||
|
||||
lianyao1: "炼药效率",
|
||||
lianyao2: "丹药产出",
|
||||
|
||||
lianyao_exp_per: "炼药获得经验",
|
||||
no_fy: "无法防御",
|
||||
no_pfm: "禁止绝招",
|
||||
kuang_exp: "挖矿经验",
|
||||
kuang_pot: "挖矿潜能",
|
||||
|
||||
diaoyu_exp: "钓鱼经验",
|
||||
diaoyu_pot: "钓鱼潜能",
|
||||
|
||||
diaoyu1: "钓鱼效率",
|
||||
kuang1: "挖矿效率",
|
||||
caiyao1: "采药效率",
|
||||
|
||||
caiyao_exp: "采药经验",
|
||||
caiyao_pot: "采药潜能",
|
||||
|
||||
|
||||
xiulian_exp: "闭关经验",
|
||||
shuangxiu: "双修效率",
|
||||
fenjie: "分解获得的玄晶",
|
||||
|
||||
};
|
||||
|
||||
123
os/data.js
Normal file
123
os/data.js
Normal file
@@ -0,0 +1,123 @@
|
||||
|
||||
module.exports = {
|
||||
parties: new Map(),
|
||||
PAIMAI: new Map(),
|
||||
temp: {},
|
||||
save: function () {
|
||||
|
||||
let str = ["{"];
|
||||
this.save_temp(str);
|
||||
this.on_save(str);
|
||||
str.push('}');
|
||||
return WORLD.DB.saveData(str.join(""));
|
||||
},
|
||||
temp_replacer: function (key, value) {
|
||||
if (value.e) {
|
||||
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
save_temp: function (str) {
|
||||
str.push('temp:', JSON.stringify(this.temp));
|
||||
},
|
||||
load: async function () {
|
||||
const data = await WORLD.DB.readData(__PATH.DATA + "data.js");
|
||||
this.temp = data.temp ?? {};
|
||||
this.on_load(data);
|
||||
},
|
||||
query_temp: function (name, def) {
|
||||
if (!this.temp) return;
|
||||
let item = this.temp[name];
|
||||
if (item && item.e) {
|
||||
if (Date.now() <= item.e) {
|
||||
return item.v;
|
||||
}
|
||||
delete this.temp[name];
|
||||
return def;
|
||||
}
|
||||
return item || def;
|
||||
},
|
||||
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;
|
||||
}
|
||||
},
|
||||
remove_temp: function (name) {
|
||||
if (!this.temp) return;
|
||||
this.temp[name] = null;
|
||||
},
|
||||
|
||||
add_temp: function (name, value, time) {
|
||||
if (!this.temp) this.temp = {};
|
||||
let old = this.temp[name];
|
||||
if (time) {
|
||||
if (old && old.e) {
|
||||
time = Date.now() + time;
|
||||
if (old.e < Date.now()) {
|
||||
old.e = time;
|
||||
old.v = value;
|
||||
} else {
|
||||
if (old.e < time) old.e = time;
|
||||
old.v += value;
|
||||
}
|
||||
return old.v;
|
||||
} else {
|
||||
let v = value + (old || 0);
|
||||
this.temp[name] = {
|
||||
v: v,
|
||||
e: Date.now() + time
|
||||
};
|
||||
return v;
|
||||
}
|
||||
} else {
|
||||
let v = value + (old || 0);
|
||||
this.temp[name] = v;
|
||||
return v;
|
||||
}
|
||||
},
|
||||
temp_data: {},
|
||||
clear_data: function () {
|
||||
this.temp_data = {};
|
||||
}
|
||||
,
|
||||
add_data: function (key, user, val) {
|
||||
if (!val) return;
|
||||
let data = this.temp_data[key];
|
||||
if (!data) data = this.temp_data[key] = {};
|
||||
let user_data = data[user.id];
|
||||
if (!user_data) user_data = data[user.id] = { name: user.name, value: 0 };
|
||||
user_data.value += val;
|
||||
}, query_max_data: function (key) {
|
||||
let data = this.temp_data[key];
|
||||
if (!data) return;
|
||||
let userData = null;
|
||||
for (let key in data) {
|
||||
let item = data[key];
|
||||
if (!userData) userData = item;
|
||||
else if (item.value > userData.value) {
|
||||
userData = item;
|
||||
}
|
||||
}
|
||||
return userData;
|
||||
}, query_min_data: function (key) {
|
||||
let data = this.temp_data[key];
|
||||
if (!data) return;
|
||||
let userData = null;
|
||||
for (let key in data) {
|
||||
let item = data[key];
|
||||
if (!userData) userData = item;
|
||||
else if (item.value < userData.value) {
|
||||
userData = item;
|
||||
}
|
||||
}
|
||||
return userData;
|
||||
}
|
||||
};
|
||||
|
||||
250
os/item.js
Normal file
250
os/item.js
Normal file
@@ -0,0 +1,250 @@
|
||||
require("./util/util");
|
||||
ITEM = function () {
|
||||
|
||||
}
|
||||
ITEM.inherits(BASE);
|
||||
|
||||
|
||||
ITEM.prototype.heart_beat = function (dt) {
|
||||
|
||||
}
|
||||
ITEM.prototype.init = function () {
|
||||
|
||||
}
|
||||
//物件对命令的反应有几种方式实现
|
||||
//1. 直接实现ON_XXXX,cmd里定义的有直接对象的命令推荐这种,比如on_accept是当别人给你东西时候,on_checkskill当别人学你技能时,适合目标明确的操作
|
||||
//2. add_action方式,房间里的指令推荐用这种,虽然也可以实现1,但是因为调用add_action时候还没ID,适合房间的自定义命令和已定义的有目标的命令
|
||||
//3. on(xxx)方式,对房间里的命令的反映,适合回应目标不是当前对象,或没有目标的命令
|
||||
//actions里定义的动作会作为对象的可用操作发送出去
|
||||
//添加物件可以接收的命令,目标是当前对象的
|
||||
ITEM.prototype.add_action = function (cmd, name, func) {
|
||||
if (!cmd) return;
|
||||
if (!this.actions) this.actions = {};
|
||||
var act = this.actions[cmd];
|
||||
if (act) {
|
||||
if (!name) {
|
||||
act.action = func;
|
||||
} else {
|
||||
act.name = name;
|
||||
}
|
||||
if (!func) {
|
||||
act.name = name;
|
||||
} else {
|
||||
act.action = func;
|
||||
}
|
||||
} else {
|
||||
act = {
|
||||
name: name,
|
||||
action: func
|
||||
};
|
||||
this.actions[cmd] = act;
|
||||
}
|
||||
this.json = null;
|
||||
return act;
|
||||
}
|
||||
//移除物件可以接收的命令
|
||||
ITEM.prototype.remove_action = function (name, func) {
|
||||
if (!this.actions) this.actions = {};
|
||||
if (typeof (name) === "string") {
|
||||
delete this.actions[name];
|
||||
} else {
|
||||
for (var i = 0; i < name.length; i++) {
|
||||
delete this.actions[name[i]];
|
||||
}
|
||||
}
|
||||
this.json = null;
|
||||
}
|
||||
//执行命令 返回true表示已经完成命令,后续不需要执行
|
||||
ITEM.prototype.exec = function (cmdName, pars) {
|
||||
if (this.actions) {
|
||||
var cmd = this.actions[cmdName];
|
||||
if (cmd && cmd.action) {
|
||||
return cmd.action.apply(this, pars);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ITEM.prototype.max_item_count = 10;
|
||||
ITEM.prototype.item_count = function () {
|
||||
return this.items ? this.items.length : 0;
|
||||
}
|
||||
ITEM.prototype.is_full = function (val) {
|
||||
if (!this.items) return false;
|
||||
if (val) return this.items.length + val > this.max_item_count;
|
||||
|
||||
return this.items.length >= this.max_item_count;
|
||||
}
|
||||
ITEM.prototype.find_obj = function (id) {
|
||||
return null;
|
||||
}
|
||||
ITEM.prototype.find_obj_bypath = function (path, parent) {
|
||||
parent = parent || this;
|
||||
if (!parent.items) return;
|
||||
for (var i = 0; i < parent.items.length; i++) {
|
||||
if (parent.items[i].path === path) {
|
||||
return parent.items[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
ITEM.prototype.each_item = function (func, parent) {
|
||||
if (!func) return;
|
||||
parent = parent || this;
|
||||
var l = parent.items.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
var item = parent.items[i];
|
||||
if (!item) continue;
|
||||
if (func(item) === false) return;
|
||||
}
|
||||
};
|
||||
ITEM.prototype.is = function (obj) {
|
||||
if (!obj) return false;
|
||||
if (typeof obj === "string")
|
||||
return this.path === obj;
|
||||
return this.path === obj.path;
|
||||
}
|
||||
ITEM.prototype.remove_item_byid = function (obj, count = 0) {
|
||||
if (!obj || !this.items) return;
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (item.id === obj) {
|
||||
if (item.combined && count > 0) {
|
||||
var subitem = item.uncombine(count);
|
||||
if (!subitem) return;
|
||||
if (subitem === item) {
|
||||
this.items.splice(i, 1);
|
||||
}
|
||||
return subitem;
|
||||
} else {
|
||||
this.items.splice(i, 1);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ITEM.prototype.remove_item = function (obj, count) {
|
||||
if (!obj || !this.items) return;
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (item === obj) {
|
||||
if (item.combined) {
|
||||
var subitem = item.uncombine(count);
|
||||
if (!subitem) return;
|
||||
if (subitem === item) {
|
||||
this.items.splice(i, 1);
|
||||
}
|
||||
return subitem;
|
||||
} else {
|
||||
this.items.splice(i, 1);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ITEM.prototype.move_item_to = function (obj, count, target) {
|
||||
if (!obj || !this.items) return;
|
||||
var moved_obj = this.remove_item(obj, count);
|
||||
if (!target) return;
|
||||
return target.push_item(moved_obj);
|
||||
}
|
||||
ITEM.prototype.push_item = function (moved_obj) {
|
||||
if (!moved_obj) return;
|
||||
if (!this.items) this.items = [];
|
||||
if (moved_obj.is_money && this.money !== undefined) {
|
||||
|
||||
this.money += moved_obj.value * moved_obj.count;
|
||||
} else if (moved_obj.combined) {
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].is(moved_obj)) {
|
||||
this.items[i].combine(moved_obj);
|
||||
return this.items[i];
|
||||
}
|
||||
}
|
||||
this.items.push(moved_obj);
|
||||
} else {
|
||||
this.items.push(moved_obj);
|
||||
}
|
||||
return moved_obj;
|
||||
}
|
||||
ITEM.prototype.create_id = function () {
|
||||
this.id = UTIL.create_id();
|
||||
|
||||
}
|
||||
ITEM.prototype.refresh = function () {
|
||||
this.json = null;
|
||||
}
|
||||
ITEM.prototype.is_hidden = function () {
|
||||
return false;
|
||||
}
|
||||
ITEM.prototype.query_create_time = function () {
|
||||
var id = this.id;
|
||||
if (!id) return;
|
||||
var time = parseInt(id.substr(4), 16);
|
||||
|
||||
return new Date(time * 1000 + UTIL.begin);
|
||||
}
|
||||
|
||||
ITEM.prototype.find_obj_byid = function (items, oid) {
|
||||
if (!items) return;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].id === oid) {
|
||||
return items[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ITEM.prototype.long_name = function () {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ITEM.prototype.create = function (file, ctor) {
|
||||
this.uid = this.create_uid();
|
||||
}
|
||||
ITEM.prototype.destroy = function () {
|
||||
|
||||
}
|
||||
|
||||
ITEM.prototype.format_temp = function (temp, timeout = 120000) {
|
||||
if (!temp) return "{}";
|
||||
var dt = Date.now() + timeout;
|
||||
var tmp = ["{"];
|
||||
for (var key in temp) {
|
||||
var v = temp[key];
|
||||
if (!v) continue;
|
||||
if (v.e) {
|
||||
if (dt > v.e || !v.v) continue;
|
||||
if (tmp.length > 1) tmp.push(",");
|
||||
tmp.push("\"");
|
||||
tmp.push(key);
|
||||
tmp.push("\":{e:");
|
||||
tmp.push(v.e);
|
||||
tmp.push(",v:");
|
||||
if (typeof v.v == "string") {
|
||||
tmp.push("\"");
|
||||
tmp.push(v.v);
|
||||
tmp.push("\"");
|
||||
} else {
|
||||
tmp.push(v.v);
|
||||
}
|
||||
tmp.push("}");
|
||||
} else {
|
||||
if (tmp.length > 1) tmp.push(",");
|
||||
tmp.push("\"");
|
||||
tmp.push(key);
|
||||
tmp.push("\":");
|
||||
if (typeof v == "string") {
|
||||
tmp.push("\"");
|
||||
tmp.push(v);
|
||||
tmp.push("\"");
|
||||
} else {
|
||||
tmp.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
tmp.push("}");
|
||||
return tmp.join("");
|
||||
}
|
||||
69
os/item/container.js
Normal file
69
os/item/container.js
Normal file
@@ -0,0 +1,69 @@
|
||||
require("./obj.js");
|
||||
CONTAINER = function () {
|
||||
this.count = 1;
|
||||
this.combined = false;
|
||||
|
||||
}
|
||||
CONTAINER.inherits(OBJ);
|
||||
CONTAINER.prototype.is_container = true;
|
||||
CONTAINER.prototype.on_get = function () {
|
||||
return false;
|
||||
}
|
||||
CONTAINER.prototype.set_items = function () {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var item = arguments[i];
|
||||
if (item) {
|
||||
if (typeof item == "string") {
|
||||
OBJ.clone_to(item, this);
|
||||
} else if (item.length) {
|
||||
OBJ.clone_to(item[0], this,item[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CONTAINER.prototype.query_items = function () {
|
||||
return this.items;
|
||||
}
|
||||
//这个单纯的字符串描述
|
||||
CONTAINER.prototype.get_desc = function (me) {
|
||||
var str = [this.color_name, this.desc];
|
||||
var items = this.query_items(me);
|
||||
if (items && items.length) {
|
||||
str.push("它里面有:");
|
||||
for (var i = 0; i <items.length; i++) {
|
||||
var item = items[i];
|
||||
str.push("\t" + UTIL.to_c(item.count) + item.unit + item.color_name);
|
||||
}
|
||||
} else {
|
||||
str.push("它里面什么都没有。");
|
||||
}
|
||||
return str.join("\n");
|
||||
}
|
||||
CONTAINER.prototype.clear_items = function (me) {
|
||||
this.items.length = 0;
|
||||
}
|
||||
//这个提供给LOOK SELECT命令的
|
||||
CONTAINER.prototype.query_desc = function (me) {
|
||||
if (this.json) return this.json;
|
||||
var obj = {};
|
||||
obj.type = "item";
|
||||
obj.id = this.id;
|
||||
obj.desc = this.get_desc(me);
|
||||
obj.commands = [];
|
||||
obj.commands.push({
|
||||
cmd: "get all from " + this.id,
|
||||
name: "全部拾取"
|
||||
});
|
||||
|
||||
this.json = JSON.stringify(obj)
|
||||
return this.json;
|
||||
}
|
||||
CONTAINER.CREATE = function (name,desc,lv,odds) {
|
||||
var obj = OBJ.CREATE("sp/box#lv");
|
||||
obj.items = OBJ.create_by_odds(odds);
|
||||
obj.name = name;
|
||||
obj.desc = desc || obj.desc;
|
||||
obj.grade = lv;
|
||||
obj.create();
|
||||
return obj;
|
||||
}
|
||||
71
os/item/corpse.js
Normal file
71
os/item/corpse.js
Normal file
@@ -0,0 +1,71 @@
|
||||
require("../item/obj.js");
|
||||
CORPSE = function () {
|
||||
this.unit = "具";
|
||||
this.count = 1;
|
||||
this.no_alloc = false;
|
||||
}
|
||||
CORPSE.inherits(CONTAINER);
|
||||
CORPSE.prototype.on_get = function (player) {
|
||||
return false;
|
||||
}
|
||||
CORPSE.prototype.init = function (player, iskeep) {
|
||||
this.create_id();
|
||||
this.fromid = player.id;
|
||||
this.name = player.name + "的尸体";
|
||||
this.color_name = "<wht>" + this.name + "</wht>";
|
||||
this.environment = player.environment;
|
||||
this.desc = "然而" + player.call3() + "已经死了,只剩下一具尸体静静地躺在这里。";
|
||||
this.items = player.query_drop();
|
||||
if (!iskeep) this.call_out(this.disappear, 60000);
|
||||
|
||||
}
|
||||
CORPSE.prototype.query_items = function (player) {
|
||||
if (this.environment.is_fb() && player.team) {
|
||||
if (!this.no_drops) {
|
||||
this.no_drops = [];
|
||||
for (var i = 0; i < player.team.length; i++) {
|
||||
if (!this.environment.query_temp(player, player.team[i].id)) {
|
||||
this.no_drops.push(player.team[i].id);
|
||||
}
|
||||
}
|
||||
this.on_getitem = this.check_get;
|
||||
}
|
||||
}
|
||||
return this.items;
|
||||
}
|
||||
CORPSE.prototype.clear_items = function (me, noget) {
|
||||
this.items.length = 0;
|
||||
if (noget && noget.length) this.items = noget;
|
||||
}
|
||||
CORPSE.prototype.check_get = function (player, item) {
|
||||
if (!this.no_drops) return true;
|
||||
if (this.no_drops.indexOf(player.id) == -1) return true;
|
||||
player.notify('你不可以拾取' + item.color_name + "。");
|
||||
return false;
|
||||
}
|
||||
CORPSE.prototype.disappear = function () {
|
||||
if (this.items) this.items.length = 0;
|
||||
if (this.environment) {
|
||||
this.environment.notify("一阵风吹去," + this.name + "已经不见了。");
|
||||
this.environment.item_changed(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
CORPSE.prototype.query_desc = function (me) {
|
||||
if (this.json) return this.json;
|
||||
var obj = {};
|
||||
obj.type = "item";
|
||||
obj.desc = this.get_desc(me);
|
||||
obj.id = this.id;
|
||||
obj.commands = [];
|
||||
obj.commands.push({
|
||||
cmd: "get all from " + this.id,
|
||||
name: "全部拾取"
|
||||
});
|
||||
if (this.no_alloc) {
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
this.json = JSON.stringify(obj);
|
||||
return this.json;
|
||||
}
|
||||
|
||||
450
os/item/equipment.js
Normal file
450
os/item/equipment.js
Normal file
@@ -0,0 +1,450 @@
|
||||
|
||||
require("../util/util.js");
|
||||
EQUIPMENT = function () {
|
||||
this.eq_type = EQUIP_TYPE.WEAPON;
|
||||
this.level = 0;
|
||||
this.exp = 0;
|
||||
this.grade = 0;
|
||||
this.count = 1;
|
||||
this.combined = false;
|
||||
this.showAction = true;
|
||||
this.allow_fight = true;
|
||||
this.otype = 4;
|
||||
}
|
||||
EQUIPMENT.inherits(OBJ);
|
||||
EQUIPMENT.prototype.is_equipment = true;
|
||||
EQUIPMENT.prototype.transable = true;
|
||||
//EQUIPMENT.prototype.eq_msg = "$N装备上$n。";
|
||||
//EQUIPMENT.prototype.uneq_msg = "$N脱下$n。";
|
||||
EQUIPMENT.prototype.change_prop = function (me, is_attach) {
|
||||
me.change_prop(this.prop, is_attach);
|
||||
if (this.st_prop) {
|
||||
for (var i = 0; i < this.st_prop.length; i++) {
|
||||
me.change_prop(this.st_prop[i].prop, is_attach);
|
||||
}
|
||||
}
|
||||
}
|
||||
EQUIPMENT.prototype.notify_action = function (me, isadd) {
|
||||
if (!this.on_use) return;
|
||||
isadd = me.equipment[this.eq_type] == this;
|
||||
if (isadd)
|
||||
me.send("{type:'addAction',id:'" + this.id + "',name:'" + this.name + "',distime:" + (this.distime || 0) + "}");
|
||||
else
|
||||
me.send("{type:'removeAction',id:'" + this.id + "'}");
|
||||
}
|
||||
EQUIPMENT.prototype.check = function (me) {
|
||||
if (!this.condition) return true;
|
||||
for (var key in this.condition) {
|
||||
var val = this.condition[key];
|
||||
switch (key) {
|
||||
case "skill":
|
||||
for (var sk in val) {
|
||||
if (me.query_skill(sk, 0) < val[sk]) {
|
||||
var sk_base = SKILL.get(sk);
|
||||
|
||||
return me.notify_fail("你的" + sk_base.color_name + "等级不够" + val[sk] + ",无法装备" + this.color_name + "。");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "str1":
|
||||
case "con1":
|
||||
case "dex1":
|
||||
case "int1":
|
||||
if (me[key.replace("1", "")] < val) {
|
||||
return me.notify_fail("你的先天" + PROPERTIES[key] + "不够" + val + ",无法装备" + this.color_name + "。");;
|
||||
}
|
||||
break;
|
||||
case "str":
|
||||
case "con":
|
||||
case "dex":
|
||||
case "int":
|
||||
if (me[key] + me.query_prop(key) < val) {
|
||||
return me.notify_fail("你的" + PROPERTIES[key] + "不够" + val + ",无法装备" + this.color_name + "。");;
|
||||
}
|
||||
break;
|
||||
case "gender":
|
||||
if (me.gender != val) return me.notify_fail("你不是" + (val == 1 ? "男性" : "女性") + ",无法装备" + this.color_name + "。");
|
||||
break;
|
||||
case "desc":
|
||||
break;
|
||||
default:
|
||||
var me_val = me[key] || 0;
|
||||
me_val = me_val + me.query_prop(key);
|
||||
if (!me_val || me_val < val) {
|
||||
|
||||
return me.notify_fail("你的" + PROPERTIES[key] + "不够" + val + ",无法装备" + this.color_name + "。");;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EQUIPMENT.prototype.eq = function (me, notsend) {
|
||||
if (this.check(me) == false) {
|
||||
return false;
|
||||
}
|
||||
if (this.on_eq && this.on_eq(me) == false) {
|
||||
return false;
|
||||
}
|
||||
this.change_prop(me, true);
|
||||
this.check_group(me, true);
|
||||
//me.add_score(this.query_score());
|
||||
if (!notsend) {
|
||||
if (this.eq_msg)
|
||||
me.send_room(this.eq_msg, this);
|
||||
else {
|
||||
var msg;
|
||||
switch (this.eq_type) {
|
||||
case EQUIP_TYPE.WEAPON:
|
||||
msg = "$N抽出一" + this.unit + this.color_name + "拿在手上。";
|
||||
break;
|
||||
case EQUIP_TYPE.CLOTH:
|
||||
case EQUIP_TYPE.SHOES:
|
||||
case EQUIP_TYPE.PANTS:
|
||||
msg = "$N穿上一" + this.unit + this.color_name + "。";
|
||||
break;
|
||||
case EQUIP_TYPE.RING:
|
||||
msg = "$N拿出一" + this.unit + this.color_name + "戴在手上。";
|
||||
break;
|
||||
case EQUIP_TYPE.NECKLACE:
|
||||
case EQUIP_TYPE.JEWELS:
|
||||
case EQUIP_TYPE.WRIST:
|
||||
msg = "$N戴上一" + this.unit + this.color_name + "。";
|
||||
break;
|
||||
default:
|
||||
msg = "$N装备上一" + this.unit + this.color_name + "。";
|
||||
break;
|
||||
}
|
||||
me.send_room(msg, this);
|
||||
}
|
||||
}
|
||||
me.send('{type:"dialog",dialog:"pack",id:"' + this.id + '",eq:' + this.eq_type + '}');
|
||||
}
|
||||
EQUIPMENT.prototype.uneq = function (me, notsend) {
|
||||
this.on_uneq && this.on_uneq(me);
|
||||
this.change_prop(me, false);
|
||||
this.check_group(me, false);
|
||||
//me.add_score(-this.query_score());
|
||||
|
||||
if (!notsend) {
|
||||
if (this.uneq_msg)
|
||||
me.send_room(this.uneq_msg, this);
|
||||
else {
|
||||
var msg;
|
||||
switch (this.eq_type) {
|
||||
case EQUIP_TYPE.WEAPON:
|
||||
msg = "$N收回手中的" + this.color_name + "。";
|
||||
break;
|
||||
case EQUIP_TYPE.CLOTH:
|
||||
case EQUIP_TYPE.SHOES:
|
||||
case EQUIP_TYPE.PANTS:
|
||||
case EQUIP_TYPE.WRIST:
|
||||
msg = "$N将" + this.color_name + "脱了下来。";
|
||||
break;
|
||||
case EQUIP_TYPE.RING:
|
||||
case EQUIP_TYPE.NECKLACE:
|
||||
case EQUIP_TYPE.JEWELS:
|
||||
msg = "$N将" + this.color_name + "取了下来。";
|
||||
break;
|
||||
default:
|
||||
msg = "$N脱下一" + this.unit + this.color_name + "。";
|
||||
break;
|
||||
}
|
||||
me.send_room(msg, this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
me.send('{type:"dialog",dialog:"pack",id:"' + this.id + '",uneq:' + this.eq_type + '}');
|
||||
}
|
||||
|
||||
EQUIPMENT.prototype.condition_tostring = function (str) {
|
||||
if (!this.condition) return;
|
||||
for (var key in this.condition) {
|
||||
var val = this.condition[key];
|
||||
switch (key) {
|
||||
case "skill":
|
||||
for (var sk in val) {
|
||||
var sk_base = SKILL.get(sk);
|
||||
str.push(sk_base.name + "要求:" + val[sk] + "级");
|
||||
}
|
||||
break;
|
||||
case "desc":
|
||||
str.push(desc);
|
||||
break;
|
||||
case "gender":
|
||||
str.push("性别要求:" + (val == 1 ? "男" : "女"));
|
||||
break;
|
||||
default:
|
||||
str.push(PROPERTIES[key] + "要求:" + val);
|
||||
break;
|
||||
}
|
||||
str.push("\n");
|
||||
}
|
||||
}
|
||||
EQUIPMENT.prototype.parts = ['武器', '衣服', '鞋', '头部', '披风', '戒指', '项链', '饰品', '护腕', '腰带', '暗器'];
|
||||
EQUIPMENT.prototype.qualities = ["普通", "精良", "高级", "稀有", "绝世", "传说", "神器"];
|
||||
|
||||
EQUIPMENT.prototype.get_desc = function (me) {
|
||||
var str = [this.color_name];
|
||||
str.push("\n");
|
||||
str.push(this.parts[this.eq_type]);
|
||||
//str.push("\n");
|
||||
//str.push(this.query_quality());
|
||||
str.push("\n");
|
||||
this.condition_tostring(str);
|
||||
|
||||
if (this.desc) str.push(this.desc);
|
||||
str.push("\n");
|
||||
if (this.prop) {
|
||||
str.push("<");
|
||||
str.push(this.query_grade_color());
|
||||
str.push(">");
|
||||
str.push(UTIL.prop_toString(this.prop));
|
||||
|
||||
str.push("</");
|
||||
str.push(this.query_grade_color());
|
||||
str.push(">\n");
|
||||
}
|
||||
if (this.st_prop) {
|
||||
for (var i = 0; i < this.st_prop.length; i++) {
|
||||
str.push(this.st_prop[i].name);
|
||||
str.push("\n");
|
||||
}
|
||||
}
|
||||
if (this.hole_count) {
|
||||
for (var i = 0; i < this.hole_count; i++) {
|
||||
str.push("◇");
|
||||
}
|
||||
}
|
||||
this.query_group_desc(me, str);
|
||||
return str.join("");
|
||||
}
|
||||
|
||||
|
||||
EQUIPMENT.prototype.query_quality = function () {
|
||||
return this.qualities[this.grade];
|
||||
}
|
||||
const level_desc = ["", "☆", "★", "★☆", "★★", "★★☆", "★★★",
|
||||
"★★★☆", "★★★★", "★★★★☆", "★★★★★", "★★★★★☆", "★★★★★★"];
|
||||
EQUIPMENT.prototype.level_up = function (lev) {
|
||||
var cc = this.query_grade_color();
|
||||
|
||||
this.prop = {};
|
||||
this.level = lev;
|
||||
this.levelchange_prop();
|
||||
this.color_name = "<" + cc + ">" + level_desc[this.level] + this.name + "</" + cc + ">";
|
||||
this.json = null;
|
||||
}
|
||||
|
||||
|
||||
EQUIPMENT.prototype.levelData = [
|
||||
0, 10, 20, 40, 70, 110, 160, 220, 290, 370, 460, 560, 670
|
||||
];
|
||||
EQUIPMENT.prototype.levelchange_prop = function () {
|
||||
if (!(this.level >= 0 && this.level < 13)) return;
|
||||
const base_props = this.original_prop ?? Object.getPrototypeOf(this).prop;
|
||||
var val = this.levelData[this.level];
|
||||
for (var key in base_props) {
|
||||
var value = base_props[key];
|
||||
switch (key) {
|
||||
case "desc":
|
||||
case "str1":
|
||||
case "con1":
|
||||
case "dex1":
|
||||
case "int1":
|
||||
case "per":
|
||||
case "kar":
|
||||
case "skill":
|
||||
this.prop[key] = value;
|
||||
break;
|
||||
|
||||
case "fy_per":
|
||||
case "zj_per":
|
||||
case "mz_per":
|
||||
case "hp_per":
|
||||
case "ds_per":
|
||||
case "gj_per":
|
||||
case "diff_busy":
|
||||
case "busy_per":
|
||||
case "caiyao1":
|
||||
case "diaoyu1":
|
||||
case "kuang1":
|
||||
case "lianyao1":
|
||||
case "diff_sh":
|
||||
case "expend_mp":
|
||||
this.prop[key] = value + parseInt(value * val / 1000);
|
||||
break;
|
||||
case "diff_downside_per":
|
||||
case "gjsd":
|
||||
case "releasetime":
|
||||
case "distime":
|
||||
case "diff_downside":
|
||||
case "distime_per":
|
||||
case "releasetime_per":
|
||||
case "gjsd_per":
|
||||
|
||||
case "bj_per":
|
||||
case "diff_bj":
|
||||
case "add_bjsh_per":
|
||||
|
||||
case "add_sh_per":
|
||||
case "diff_busy_per":
|
||||
case "diff_sh_per":
|
||||
case "diff_fy_per":
|
||||
case "expend_mp_per":
|
||||
case "busy":
|
||||
this.prop[key] = value;
|
||||
break;
|
||||
default:
|
||||
if (PROPERTIES[key])
|
||||
this.prop[key] = value + parseInt(value * val / 100);
|
||||
else
|
||||
this.prop[key] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
EQUIPMENT.prototype.clear_stone = function () {
|
||||
if (!this.st_prop) return;
|
||||
|
||||
this.hole_count += (this.st_prop.length);
|
||||
this.st_prop.length = 0;
|
||||
}
|
||||
EQUIPMENT.prototype.push_stone = function (stone) {
|
||||
if (!stone || !stone.prop) return false;
|
||||
if (!this.hole_count) return false;
|
||||
|
||||
if (!this.st_prop) this.st_prop = [];
|
||||
this.hole_count--;
|
||||
var cc = stone.query_grade_color();
|
||||
var str = ["<", cc, ">◆", stone.name, " "];
|
||||
str.push(UTIL.prop_toString(stone.prop, " "));
|
||||
str.push("</");
|
||||
str.push(cc);
|
||||
str.push(">");
|
||||
|
||||
this.json = null;
|
||||
this.st_prop.push({
|
||||
id: stone.id,
|
||||
path: stone.path,
|
||||
name: str.join(""),
|
||||
prop: stone.prop,
|
||||
grade: stone.grade
|
||||
});
|
||||
}
|
||||
EQUIPMENT.prototype.clone = function (me) {
|
||||
var obj = OBJ.CREATE(this.path);
|
||||
if (this.temp) {
|
||||
obj.temp = {};
|
||||
for (var key in this.temp) {
|
||||
obj.temp[key] = this.temp[key];
|
||||
}
|
||||
}
|
||||
obj.on_reload && obj.on_reload(me);
|
||||
obj.level_up(this.level);
|
||||
obj.st_prop = this.st_prop;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EQUIPMENT.prototype.save_db = function (str) {
|
||||
str.push('["', this.path, '","', this.id, '",', this.level);
|
||||
if (this.st_prop && this.st_prop.length) {
|
||||
str.push(",[");
|
||||
for (var i = 0; i < this.st_prop.length; i++) {
|
||||
if (i > 0) str.push(",");
|
||||
str.push('"', this.st_prop[i].path, '"');
|
||||
}
|
||||
str.push("]");
|
||||
}
|
||||
// else {
|
||||
// str.push(',[]');
|
||||
// }
|
||||
if (this.is_locked)
|
||||
str.push(',1');
|
||||
if (this.temp)
|
||||
str.push(",", this.format_temp(this.temp));
|
||||
str.push("]");
|
||||
}
|
||||
EQUIPMENT.prototype.load_db = function (data) {
|
||||
//const [path, id, level, sts, locked,temp] = data;
|
||||
this.id = data[1];
|
||||
if (data[2] > 0) {
|
||||
this.level = data[2];
|
||||
}
|
||||
for (let i = 3; i < data.length; i++) {
|
||||
let value = data[i];
|
||||
if (value === 1) this.is_locked = true;
|
||||
else if (Array.isArray(value)) {
|
||||
for (var j = 0; j < value.length; j++) {
|
||||
var st_item = OBJ.CREATE(value[j]);
|
||||
if (st_item) {
|
||||
this.push_stone(st_item);
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
this.temp = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
EQUIPMENT.prototype.on_load = function (me) {
|
||||
this.on_reload && this.on_reload(me);
|
||||
if (this.level > 0) {
|
||||
this.level_up(this.level);
|
||||
}
|
||||
}
|
||||
|
||||
EQUIPMENT.prototype.VALUES = [100, 1000, 2000, 10000, 100000, 1000000, 100000000];
|
||||
EQUIPMENT.prototype.on_create = function (path, par) {
|
||||
this.value = this.VALUES[this.grade];
|
||||
|
||||
}
|
||||
|
||||
EQUIPMENT.prototype.query_group_desc = function (me, str) {
|
||||
if (!this.group_prop || !this.group_name) return;
|
||||
var count = 0;
|
||||
if (me && me.equipment) {
|
||||
for (var i = 0; i < me.equipment.length; i++) {
|
||||
if (me.equipment[i] && me.equipment[i].group_name == this.group_name) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 2; i < 8; i++) {
|
||||
var prop = this.group_prop(i);
|
||||
if (prop) {
|
||||
var cc = i <= count ? this.query_grade_color() : "blk";
|
||||
|
||||
str.push("<");
|
||||
str.push(cc);
|
||||
str.push(">");
|
||||
str.push("\n");
|
||||
str.push(UTIL.to_c(i));
|
||||
str.push("件套:");
|
||||
str.push(UTIL.prop_toString(prop, " "));
|
||||
str.push("</");
|
||||
str.push(cc);
|
||||
str.push(">");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
EQUIPMENT.prototype.check_group = function (me, isadd) {
|
||||
if (!this.group_prop || !this.group_name) return;
|
||||
var count = isadd ? 1 : 0;
|
||||
for (var i = 0; i < me.equipment.length; i++) {
|
||||
if (me.equipment[i] && me.equipment[i].group_name == this.group_name) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
var prop = this.group_prop(count);
|
||||
if (prop) {
|
||||
me.change_prop(prop, isadd);
|
||||
}
|
||||
|
||||
}
|
||||
25
os/item/money.js
Normal file
25
os/item/money.js
Normal file
@@ -0,0 +1,25 @@
|
||||
require("../item/obj.js");
|
||||
MONEY = function () {
|
||||
this.is_cash = false;
|
||||
this.combined = true;
|
||||
this.count = 1;
|
||||
}
|
||||
MONEY.inherits(OBJ);
|
||||
MONEY.prototype.is_money = true;
|
||||
MONEY.prototype.transable = true;
|
||||
|
||||
MONEY.prototype.create = function () {
|
||||
this.create_id();
|
||||
if (this.is_cash) {
|
||||
this.color_name = "<hio>" + this.name + "</hio>";
|
||||
} else {
|
||||
if (this.value == 1)
|
||||
this.color_name = "<yel>" + this.name + "</yel>";
|
||||
else if (this.value == 100)
|
||||
this.color_name = "<hiw>" + this.name + "</hiw>";
|
||||
else
|
||||
this.color_name = "<hiy>" + this.name + "</hiy>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
228
os/item/obj.js
Normal file
228
os/item/obj.js
Normal file
@@ -0,0 +1,228 @@
|
||||
|
||||
OBJ = function () {
|
||||
this.unit = "个";
|
||||
this.path = null;
|
||||
this.count = 1;
|
||||
this.combined = true;
|
||||
this.grade = 0;
|
||||
this.otype = 0;
|
||||
}
|
||||
|
||||
OBJ.inherits(ITEM);
|
||||
OBJ.prototype.transable = false;
|
||||
OBJ.prototype.init = function (me) {
|
||||
this.on_init && this.on_init(me);
|
||||
}
|
||||
OBJ.prototype.long_name = function () {
|
||||
if (this.combined) return UTIL.to_c(this.count) + this.unit + this.color_name;
|
||||
return this.color_name;
|
||||
}
|
||||
OBJ.prototype.unit_name = function (count) {
|
||||
return UTIL.to_c(count || this.count) + this.unit + this.color_name;
|
||||
|
||||
}
|
||||
OBJ.prototype.item_to_json = function () {
|
||||
return `["${this.name}","${this.id}",${this.count},${this.grade},"${this.unit}",${parseInt(this.value / 10)},${this.is_equipment ? 1 : 0},${this.on_use ? 1 : 0},${this.on_study ? 1 : 0},${this.on_open ? 1 : 0},${this.combine_count > 0 ? this.combine_count : 0}]`;
|
||||
}
|
||||
OBJ.prototype.query_commands = function (me) {
|
||||
return this.query_desc(me);
|
||||
}
|
||||
OBJ.prototype.query_desc = function (me) {
|
||||
if (this.json) return this.json;
|
||||
var obj = {};
|
||||
obj.type = "item";
|
||||
obj.id = this.id;
|
||||
obj.desc = this.get_desc(me);
|
||||
obj.commands = [];
|
||||
obj.commands.push({
|
||||
cmd: "get " + this.id,
|
||||
name: "捡起"
|
||||
});
|
||||
|
||||
this.json = JSON.stringify(obj)
|
||||
return this.json;
|
||||
}
|
||||
OBJ.prototype.get_desc = function () {
|
||||
return this.color_name + "\n" + this.desc;
|
||||
}
|
||||
OBJ.prototype.uncombine = function (spcount) {
|
||||
if (!spcount || spcount === this.count) return this;
|
||||
if (spcount < this.count) {
|
||||
var item = this.clone();
|
||||
item.count = spcount;
|
||||
this.count -= spcount;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
OBJ.prototype.clone = function () {
|
||||
var item = OBJ.CREATE(this.path);
|
||||
if (this.temp) {
|
||||
item.temp = Object.assign({}, this.temp);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
OBJ.prototype.combineTemp = function (target, source) {
|
||||
if (!source) return target;
|
||||
if (!target) return source;
|
||||
for (let key in source) {
|
||||
let val = source[key];
|
||||
if (val && typeof val === "number") {
|
||||
let thisVal = target[key];
|
||||
if (!thisVal) {
|
||||
target[key] = val;
|
||||
} else if (typeof thisVal === "number") {
|
||||
target[key] = thisVal > val ? thisVal : val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
OBJ.prototype.combine = function (obj) {
|
||||
if (this.is(obj)) {
|
||||
if (obj.temp || this.temp) {
|
||||
this.temp = this.combineTemp(this.temp, obj.temp);
|
||||
}
|
||||
this.count += (obj.count || 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OBJ.clone_to = function (otype, to, count) {
|
||||
if (!otype || !to) return;
|
||||
var item = OBJ.CREATE(otype);
|
||||
if (!item) return;
|
||||
count = count || 1;
|
||||
if (item.is_money && to.money != undefined) {
|
||||
item.count = count;
|
||||
to.money += item.value * item.count;
|
||||
return item;
|
||||
}
|
||||
if (!to.items) to.items = [];
|
||||
if (item.combined) {
|
||||
for (var i = 0; i < to.items.length; i++) {
|
||||
if (to.items[i].is(item)) {
|
||||
to.items[i].count += count;
|
||||
return to.items[i];
|
||||
}
|
||||
}
|
||||
|
||||
item.count = count;
|
||||
to.items.push(item);
|
||||
} else {
|
||||
to.items.push(item);
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
item = OBJ.CREATE(otype, 1);
|
||||
to.items.push(item);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
OBJ.prototype.save_db = function (str) {
|
||||
str.push('["', this.path, '","', this.id, '",', this.count);
|
||||
if (this.is_locked) {
|
||||
str.push(',1');
|
||||
}
|
||||
if (this.temp)
|
||||
str.push(",", this.format_temp(this.temp));
|
||||
str.push(']');
|
||||
|
||||
}
|
||||
OBJ.prototype.load_db = function (data) {
|
||||
//path, id, count, temp or lock
|
||||
|
||||
this.id = data[1];
|
||||
if (data[2] > 1) this.count = data[2];
|
||||
if (data[3]) {
|
||||
if (data[3] === 1) {
|
||||
this.is_locked = true;
|
||||
} else if (typeof data[3] === 'object') {
|
||||
this.temp = data[3];
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (data[4]) this.temp = data[4];
|
||||
}
|
||||
|
||||
OBJ.prototype.on_load = function (me) {
|
||||
this.on_reload && this.on_reload(me);
|
||||
}
|
||||
|
||||
OBJ.prototype.on_clone = function () {
|
||||
|
||||
}
|
||||
OBJ.CREATE = function (otype, count) {
|
||||
let base = WORLD.OBJ_STROE.get(otype);
|
||||
if (!base) {
|
||||
base = BASE.CREATE(__PATH.OBJ, otype);
|
||||
if (!base) throw new Error('没有物品' + otype + "的定义。");
|
||||
//这里会自己调用create方法存储到OBJ_STROE,记住了吗
|
||||
}
|
||||
|
||||
// var item = BASE.CREATE(__PATH.OBJ, otype);
|
||||
// if (!item) return;
|
||||
let item = Object.create(base);
|
||||
item.create_id();
|
||||
item.on_clone();
|
||||
if (count > 1)
|
||||
item.count = count;
|
||||
return item;
|
||||
}
|
||||
var grade_color = ["wht", "hig", "hic", "hiy", "HIZ", "hio", "ord"];
|
||||
|
||||
OBJ.prototype.create = function (path, par) {
|
||||
if (par) this.path = path + par;
|
||||
this.create_id();
|
||||
this.on_create && this.on_create(path, par);
|
||||
var cc = grade_color[this.grade];
|
||||
this.color_name = "<" + cc + ">" + this.name + "</" + cc + ">";
|
||||
WORLD.OBJ_STROE.set(this.path, this);
|
||||
}
|
||||
OBJ.prototype.update = function (path, par) {
|
||||
this.create(path, par);
|
||||
}
|
||||
|
||||
|
||||
|
||||
OBJ.prototype.query_grade_color = function () {
|
||||
return grade_color[this.grade];
|
||||
}
|
||||
|
||||
OBJ.prototype.notify_action = function (me, isadd) {
|
||||
if (!this.on_use) return;
|
||||
if (!this.showAction) return;
|
||||
if (isadd)
|
||||
me.send("{type:'addAction',id:'" + this.id + "',name:'" + this.name + "',distime:" + (this.distime || 0) + "}");
|
||||
else
|
||||
me.send("{type:'removeAction',id:'" + this.id + "'}");
|
||||
}
|
||||
|
||||
OBJ.prototype.query_temp = CHARACTER.prototype.query_temp;
|
||||
OBJ.prototype.set_temp = CHARACTER.prototype.set_temp;
|
||||
OBJ.prototype.remove_temp = CHARACTER.prototype.remove_temp;
|
||||
|
||||
OBJ.prototype.add_temp = CHARACTER.prototype.add_temp;
|
||||
OBJ.create_by_odds = function (args) {
|
||||
var items = [];
|
||||
if (!args) return items;
|
||||
let drop = null, per = null,
|
||||
obj = null;
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
drop = args[i];
|
||||
if (!drop) continue;
|
||||
|
||||
per = Math.random() * 10000;
|
||||
obj = (drop.odds || 10000) > per ? drop.obj : drop.fall_obj;
|
||||
if (obj) {
|
||||
if (drop.min_count) hit_count = 0;
|
||||
var count = drop.count || 1;
|
||||
if (drop.min && drop.max) {
|
||||
count = Math.floor(Math.random() * (drop.max - drop.min + 1)) + drop.min;
|
||||
}
|
||||
if (count > 0) {
|
||||
if (obj instanceof Array) obj = obj.random();
|
||||
items.push(OBJ.CREATE(obj, count));
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
38
os/login.js
Normal file
38
os/login.js
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
var crypto = require('crypto');
|
||||
module.exports = {
|
||||
max_idcount: 10,
|
||||
max_ipcount: 12,
|
||||
login_error: function (user, msg, close = true) {
|
||||
user.send(`{type:'loginerror',msg:'${msg}'}`);
|
||||
if (close)
|
||||
user.socket?.end();
|
||||
return false;
|
||||
},
|
||||
encryptUser: function (key, session) {
|
||||
if (!key || !session) return null;
|
||||
if (key.length >= 16) key = key.substr(0, 16);
|
||||
try {
|
||||
key = Buffer.from(key, 'utf8');
|
||||
var decipher = crypto.createDecipheriv('aes-128-cbc', key, __CONFIG.DESIV);
|
||||
var txt = decipher.update(session, 'base64', 'utf8');
|
||||
txt += decipher.final('utf8');
|
||||
var str = txt.split("%");
|
||||
if (str.length !== 5) return null;
|
||||
var id = parseInt(str[0]);
|
||||
if (id > 0)
|
||||
return {
|
||||
id: id,
|
||||
name: str[1],
|
||||
pwd: str[2],
|
||||
loginTime: parseInt(str[3]),
|
||||
level: parseInt(str[4])
|
||||
};
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
340
os/net-ws.js
Normal file
340
os/net-ws.js
Normal file
@@ -0,0 +1,340 @@
|
||||
"use strict";
|
||||
var crypto = require('crypto');
|
||||
var fs = require("fs");
|
||||
function wsServer(options) {
|
||||
var evt = ["Close", "Error", "SocketIn", "Connect", "Receive",
|
||||
"ClientError", "ClientClose", "ClientTimeout"];
|
||||
for (var i = 0; i < evt.length; i++) {
|
||||
this["on" + evt[i]] = function () {
|
||||
}
|
||||
}
|
||||
this.options = options.SSL ? {
|
||||
key: fs.readFileSync(options.KEY),
|
||||
cert: fs.readFileSync(options.CERT),
|
||||
requestCert: true,
|
||||
rejectUnauthorized: true,
|
||||
passphrase: options.PASSWORD,
|
||||
ca: [fs.readFileSync(options.CERT)]
|
||||
} : null;
|
||||
this.ssl = options.SSL;
|
||||
}
|
||||
wsServer.prototype.listen = function (port, func) {
|
||||
|
||||
var net = require(this.ssl ? 'tls' : 'net');
|
||||
var tcpserver = net.createServer(this.options, onClientConnect.bind(this));
|
||||
tcpserver.listen(port, func);
|
||||
tcpserver.on('close', this.onClose.bind(this));
|
||||
tcpserver.on('error', this.onError.bind(this));
|
||||
this.tcpServer = tcpserver;
|
||||
}
|
||||
wsServer.prototype.send = function (msg, socket) {
|
||||
socket.send(msg);
|
||||
}
|
||||
wsServer.prototype.close = function () {
|
||||
return new Promise((resolve) => {
|
||||
this.tcpServer.close(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = wsServer;
|
||||
function onClientConnect(socket) {
|
||||
|
||||
socket.send = function (msg) {
|
||||
if (msg)
|
||||
this.protocol.sendData(msg, socket);
|
||||
}
|
||||
socket.on('close', this.onClientClose.bind(this, socket));
|
||||
socket.on('error', this.onClientError.bind(this, socket));
|
||||
var $this = this;
|
||||
socket.setTimeout(3000);
|
||||
socket.on('timeout', this.onClientTimeout.bind(this, socket));
|
||||
$this.onSocketIn(socket);
|
||||
socket.on('data', function (data) {
|
||||
if (socket.protocol) {
|
||||
socket.protocol.readData(data, socket, $this);
|
||||
} else {
|
||||
var header = readHeader(data);
|
||||
socket.requestHeader = header;
|
||||
if (header["Sec-WebSocket-Key"]) {
|
||||
socket.protocol = protocols.var1;
|
||||
} else if (header["Sec-WebSocket-Key1"]) {
|
||||
socket.protocol = protocols.var2;
|
||||
} else {
|
||||
socket.protocol = protocols.tcp;
|
||||
socket.protocol.readData(data, socket, $this);
|
||||
return;
|
||||
}
|
||||
socket.protocol.handShake(header, socket, data);
|
||||
$this.onConnect(socket);
|
||||
}
|
||||
});
|
||||
}
|
||||
var protocols = {
|
||||
var1: {
|
||||
handShake: function (header, socket) {
|
||||
var hasher = crypto.createHash("sha1");
|
||||
hasher.update(header["Sec-WebSocket-Key"] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
var hashmsg = hasher.digest().toString('base64');
|
||||
var origin = header.Origin;
|
||||
var protocol = header['sec-websocket-protocol'];
|
||||
if (protocol)
|
||||
protocol.split(/, */);
|
||||
var respon = ["HTTP/1.1 101 Switching Protocols",
|
||||
"Connection: Upgrade",
|
||||
"Upgrade: WebSocket",
|
||||
`Sec-WebSocket-Accept:${hashmsg}`,
|
||||
`Sec-WebSocket-Origin:${origin}`];
|
||||
if (protocol) respon.push(`Sec-WebSocket-Protocol: ${protocol}`);
|
||||
//var extens = header["Sec-Websocket-Extensions"];
|
||||
//if (extens) {
|
||||
// respon.push(`Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits`);
|
||||
//}
|
||||
respon.push("\r\n");
|
||||
socket.write(respon.join("\r\n"));
|
||||
},
|
||||
readData: function (data, socket, server) {
|
||||
var start = 0;
|
||||
while (start < data.length) {
|
||||
var iseof = (data[start] >> 7) > 0;
|
||||
var frameType = data[start++] & 0xF;
|
||||
var hasMask = (data[start] >> 7) > 0;
|
||||
var length = (data[start++] & 0x7F);
|
||||
if (length == 126) {
|
||||
length = data.readUInt16BE(start);
|
||||
start = start + 2;
|
||||
}
|
||||
else if (length == 127) {
|
||||
length = data.readUInt32BE(start);
|
||||
start = start + 4;
|
||||
return;
|
||||
}
|
||||
var markIndex = start;
|
||||
start = start + 4;
|
||||
for (let i = 0; i < length; i++) {
|
||||
data[start] = data[start] ^ data[markIndex + (i % 4)];
|
||||
start++;
|
||||
}
|
||||
switch (frameType) {
|
||||
case FrameTypes.Close:
|
||||
socket.end();
|
||||
// server.onClientClose(socket);
|
||||
break;
|
||||
case FrameTypes.Binary:
|
||||
break;
|
||||
case FrameTypes.Ping:
|
||||
break;
|
||||
case FrameTypes.Pong:
|
||||
break;
|
||||
case FrameTypes.Text:
|
||||
var msg = data.toString("utf8", markIndex + 4, markIndex + 4 + length);
|
||||
server.onReceive(msg, socket);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
sendData: function (text, socket) {
|
||||
var textBuffer = Buffer.from(text);
|
||||
var length = textBuffer.length;
|
||||
var data;
|
||||
if (length < 126) {
|
||||
data = Buffer.alloc(length + 2);
|
||||
data[0] = 129;
|
||||
data.writeUInt8(length, 1);
|
||||
textBuffer.copy(data, 2);
|
||||
}
|
||||
else if (length >= 126 && length < 65536) {
|
||||
data = Buffer.alloc(length + 4);
|
||||
data[0] = 129;
|
||||
data.writeUInt8(126, 1);
|
||||
data.writeUInt16BE(length, 2);
|
||||
textBuffer.copy(data, 4);
|
||||
} else {
|
||||
data = Buffer.alloc(length + 10);
|
||||
data[0] = 0x81;
|
||||
data[1] = 127;
|
||||
data.writeUInt32BE(0, 2);
|
||||
data.writeUInt32BE(length, 6);
|
||||
textBuffer.copy(data, 10);
|
||||
}
|
||||
socket.write(data);
|
||||
}
|
||||
},
|
||||
var2: {
|
||||
handShake: function (header, socket, buffer) {
|
||||
var key1 = header["Sec-WebSocket-Key1"];
|
||||
var key2 = header["Sec-WebSocket-Key2"];
|
||||
|
||||
var origin = header["Origin"];
|
||||
|
||||
var n1 = getNumber(key1);
|
||||
n1 = parseInt(n1);
|
||||
n1 = n1 / getSpace(key1);
|
||||
|
||||
var n2 = getNumber(key2);
|
||||
n2 = parseInt(n2);
|
||||
n2 = n2 / getSpace(key2);
|
||||
|
||||
var buf = Buffer.alloc(16);
|
||||
|
||||
buf.writeIntBE(n1, 0, 4, true);
|
||||
|
||||
buf.writeIntBE(n2, 4, 4, true);
|
||||
|
||||
buffer.copy(buf, 8, buffer.length - 8, buffer.length);
|
||||
|
||||
var hasherbs = crypto.createHash("md5");
|
||||
hasherbs = hasherbs.update(buf);
|
||||
hasherbs = hasherbs.digest();
|
||||
|
||||
var host = "ws://" + header["Host"] + "/";
|
||||
var headers = [
|
||||
"HTTP/1.1 101 WebSocket Protocol Handshake",
|
||||
"Upgrade: WebSocket",
|
||||
"Connection: Upgrade",
|
||||
"Sec-WebSocket-Origin:" + origin,
|
||||
"Sec-WebSocket-Location:" + host
|
||||
, "\r\n"
|
||||
];
|
||||
socket.write(headers.join("\r\n"));
|
||||
socket.write(hasherbs);
|
||||
},
|
||||
buffer: null
|
||||
,
|
||||
readData: function (data, socket, server) {
|
||||
var start = 0;
|
||||
while (start < data.length) {
|
||||
if (data[start] != 0) {
|
||||
break;//error
|
||||
}
|
||||
var end = start + 1;
|
||||
while (data[end] != 255 && end < data.length) {
|
||||
end++;
|
||||
}
|
||||
var msg = data.toString("utf8", start + 1, end);
|
||||
server.onReceive(msg, socket);
|
||||
start = end + 1;
|
||||
}
|
||||
},
|
||||
sendData: function (text, socket) {
|
||||
var textBuffer = Buffer.from(text, "utf-8");
|
||||
var length = textBuffer.length;
|
||||
|
||||
var wrappedBytes = Buffer.alloc(length + 2);
|
||||
wrappedBytes[0] = 0;
|
||||
textBuffer.copy(wrappedBytes, 1);
|
||||
wrappedBytes[wrappedBytes.length - 1] = 255;
|
||||
socket.write(wrappedBytes);
|
||||
}
|
||||
},
|
||||
tcp: {
|
||||
|
||||
readData: function (data, socket, server) {
|
||||
|
||||
var start = 0;
|
||||
if (socket.unread_data) {
|
||||
data = Buffer.concat([socket.unread_data, data], socket.unread_data.length + data.length);
|
||||
socket.unread_data = null;
|
||||
}
|
||||
let isread = false;
|
||||
while (start < data.length) {
|
||||
let length = data.readUInt8(start);
|
||||
let index = start + 1;
|
||||
if (length === 254) {
|
||||
//不够读长度咋办
|
||||
length = data.readUInt16BE(index);
|
||||
index += 2;
|
||||
} else if (length === 255) {
|
||||
length = data.readUInt32BE(index);
|
||||
index += 4;
|
||||
}
|
||||
if (data.length < index + length) {
|
||||
socket.unread_data = isread ? data.slice(start) : data;
|
||||
return;
|
||||
}
|
||||
let msg = data.toString("utf8", index, index + length);
|
||||
|
||||
isread = true;
|
||||
|
||||
server.onTcpReceive(msg, socket);
|
||||
|
||||
start = index + length;
|
||||
|
||||
}
|
||||
},
|
||||
sendData: function (text, socket) {
|
||||
var textBuffer = Buffer.from(text);
|
||||
var length = textBuffer.length;
|
||||
var data;
|
||||
if (length < 254) {
|
||||
data = Buffer.alloc(length + 1);
|
||||
data.writeUInt8(length);
|
||||
textBuffer.copy(data, 1);
|
||||
}
|
||||
else if (length >= 254 && length < 65536) {
|
||||
data = Buffer.alloc(length + 3);
|
||||
data.writeUInt8(254);
|
||||
data.writeUInt16BE(length, 1);
|
||||
textBuffer.copy(data, 3);
|
||||
} else {
|
||||
data = Buffer.alloc(length + 5);
|
||||
data.writeUInt8(255);
|
||||
data.writeUInt32BE(length, 1);
|
||||
textBuffer.copy(data, 5);
|
||||
}
|
||||
socket.write(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getNumber(str) {
|
||||
return str.replace(/\D/g, "");
|
||||
|
||||
}
|
||||
function getSpace(str) {
|
||||
return str.replace(/\S/g, "").length;
|
||||
}
|
||||
function readHeader(data) {
|
||||
var header = {}, key, flag = 0;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
switch (data[i]) {
|
||||
case 0x0D://\r
|
||||
key && (header[key] = data.toString("utf8", flag, i));
|
||||
break;
|
||||
case 0x0A://\n
|
||||
key = null;
|
||||
flag = i + 1;
|
||||
break;
|
||||
case 0x3A://:
|
||||
if (!key) {
|
||||
key = data.toString("utf8", flag, i);
|
||||
data[i + 1] == 0x20 ? flag = i + 2 : flag = i + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag < data.length) {
|
||||
header.CONTENT = data.toString("utf8", flag);
|
||||
|
||||
}
|
||||
return header;
|
||||
}
|
||||
var FrameTypes =
|
||||
{
|
||||
Continuation: 0,
|
||||
Text: 1,
|
||||
Binary: 2,
|
||||
Close: 8,
|
||||
Ping: 9,
|
||||
Pong: 10,
|
||||
};
|
||||
|
||||
//%x0 代表一个继续帧
|
||||
//%x1 代表一个文本帧
|
||||
//%x2 代表一个二进制帧
|
||||
//%x3-7 保留用于未来的非控制帧
|
||||
//%x8 代表连接关闭
|
||||
//%x9 代表ping
|
||||
//%xA 代表pong
|
||||
//%xB-F 保留用于未来的控制帧
|
||||
135
os/room/area.js
Normal file
135
os/room/area.js
Normal file
@@ -0,0 +1,135 @@
|
||||
AREA = function () {
|
||||
this.rooms = [];
|
||||
this.map = [];
|
||||
this.name = "";
|
||||
this.is_area = false;
|
||||
this.first = null;
|
||||
this.is_show = true;
|
||||
this.is_copy = false;
|
||||
this.expend = 10;
|
||||
this.is_multi = false;
|
||||
this.index = 0;
|
||||
this.exp = 1000;
|
||||
this.pot = 1000;
|
||||
}
|
||||
AREA.inherits(BASE);
|
||||
AREA.prototype.create = function (path) {
|
||||
WORLD.AREAS.push(this);
|
||||
if (this.family) {
|
||||
FAMILIES[this.family].area = this;
|
||||
}
|
||||
}
|
||||
AREA.Get = function (id) {
|
||||
if (!WORLD.AREAS) return;
|
||||
for (var i = 0; i < WORLD.AREAS.length; i++) {
|
||||
if (WORLD.AREAS[i].id == id) return WORLD.AREAS[i];
|
||||
}
|
||||
}
|
||||
AREA.prototype.on_leaved = function (me) {
|
||||
//离开后
|
||||
}
|
||||
AREA.prototype.on_leave = function (me) {
|
||||
//进入前
|
||||
return true;
|
||||
}
|
||||
AREA.prototype.on_enterd = function (me) {
|
||||
//进入后
|
||||
}
|
||||
AREA.prototype.on_enter = function (me) {
|
||||
//进入前
|
||||
return true;
|
||||
}
|
||||
AREA.prototype.find_area = function (path) {
|
||||
}
|
||||
AREA.prototype.is_record = function (diff) {
|
||||
return this["record_" + diff];
|
||||
}
|
||||
AREA.prototype.query_exp = function () {
|
||||
var lv = this.fb_index || 0;
|
||||
return 1000 + lv * 100;
|
||||
}
|
||||
|
||||
AREA.prototype.query_desc = function () {
|
||||
return this.desc;
|
||||
}
|
||||
|
||||
AREA.prototype.clear = function () {
|
||||
this.json = null;
|
||||
this.drop_list = null;
|
||||
this.diff_drop_list = null;
|
||||
}
|
||||
AREA.prototype.query_drops = function (isdiff) {
|
||||
if (isdiff) return this.query_diff_drops();
|
||||
if (this.drop_list) return this.drop_list;
|
||||
var items = [];
|
||||
for (var i = 0; i < this.rooms.length; i++) {
|
||||
var rm = this.rooms[i];
|
||||
for (var j = 0; j < rm.items.length; j++) {
|
||||
if (rm.items[j].drop_list) {
|
||||
items.push(rm.items[j].drop_list);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
this.query_npc_drops(this.drop_npcs0, items);
|
||||
this.drop_list = items;
|
||||
return this.drop_list;
|
||||
}
|
||||
AREA.prototype.query_npc_drops = function (npcs, items) {
|
||||
if (!npcs || !npcs.length) return;
|
||||
for (var i = 0; i < npcs.length; i++) {
|
||||
var npc = NPC.GET(npcs[i]);
|
||||
if (!npc || !npc.drop_list) continue;
|
||||
items.push(npc.drop_list)
|
||||
}
|
||||
}
|
||||
AREA.prototype.query_diff_drops = function (isdiff) {
|
||||
if (this.diff_drop_list) return this.diff_drop_list;
|
||||
var items = [];
|
||||
for (var i = 0; i < this.rooms.length; i++) {
|
||||
var rm = this.rooms[i];
|
||||
for (var j = 0; j < rm.items.length; j++) {
|
||||
if (rm.items[j].drop_list) {
|
||||
items.push(rm.items[j].drop_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.query_npc_drops(this.drop_npcs1, items);
|
||||
this.diff_drop_list = items;
|
||||
return this.diff_drop_list;
|
||||
}
|
||||
AREA.prototype.update = function (path) {
|
||||
WORLD.COMMANDS["jh"].map_json = null;
|
||||
for (var i = 0; i < WORLD.AREAS.length; i++) {
|
||||
if (WORLD.AREAS[i].path == path) {
|
||||
var old_area = WORLD.AREAS[i];
|
||||
WORLD.AREAS[i] = this;
|
||||
this.rooms = old_area.rooms;
|
||||
if (this.rooms) {
|
||||
for (let room of this.rooms) {
|
||||
room.parent = this;
|
||||
}
|
||||
}
|
||||
old_area.rooms = null;
|
||||
if (this.family) {
|
||||
FAMILIES[this.family].area = this;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.create(path);
|
||||
}
|
||||
AREA.Get = function (id) {
|
||||
for (var i = 0; i < WORLD.AREAS.length; i++) {
|
||||
if (WORLD.AREAS[i].id == id) {
|
||||
return WORLD.AREAS[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
AREA.prototype.query_drop_items = function () {
|
||||
return this.drop_items;
|
||||
}
|
||||
AREA.prototype.query_actions = function () {
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
5
os/room/fam_area.js
Normal file
5
os/room/fam_area.js
Normal file
@@ -0,0 +1,5 @@
|
||||
FAMILY_AREA = function () {
|
||||
|
||||
}
|
||||
FAMILY_AREA.inherits(AREA);
|
||||
|
||||
692
os/room/room.js
Normal file
692
os/room/room.js
Normal file
@@ -0,0 +1,692 @@
|
||||
|
||||
ROOM = function () {
|
||||
this.name = "房间";
|
||||
this.desc = "";
|
||||
this.items = [];
|
||||
this.parent = null;
|
||||
}
|
||||
ROOM.inherits(ITEM);
|
||||
ROOM.prototype.max_item_count = 50;
|
||||
|
||||
ROOM.prototype.do_leave = function (obj, dir, leave_msg) {
|
||||
if (this.on_leave && this.on_leave(obj, dir) == false) {
|
||||
return false;
|
||||
}
|
||||
if (this.item_changed(obj, false, leave_msg, dir) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
ROOM.prototype.do_enter = function (obj, isshow, in_msg) {
|
||||
this.on_before_enter && this.on_before_enter(obj);
|
||||
if (obj.is_player) {
|
||||
obj.send(this.to_json());
|
||||
this.send_exits(obj);
|
||||
}
|
||||
this.item_changed(obj, true, in_msg);
|
||||
this.on_enter && this.on_enter(obj);
|
||||
}
|
||||
ROOM.prototype.item_changed = function (obj, isin, changed_msg, dir) {
|
||||
if (!obj) return;
|
||||
var msg;
|
||||
var obj_index = -1, isshow = !obj.query_temp('hidden');
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (item == obj) {
|
||||
obj_index = i;
|
||||
continue;
|
||||
}
|
||||
if (item.is_player && isshow) {
|
||||
if (!msg) msg = this.item_json(obj, isin);
|
||||
item.send(msg);
|
||||
|
||||
if (changed_msg && item != obj && !item.query_setting("off_move")) {
|
||||
item.send(changed_msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (obj.hp) {
|
||||
if (isin && item.on_enter) {
|
||||
item.on_enter(obj);
|
||||
} else if (!isin && item.on_leave) {
|
||||
if (item.on_leave(obj, dir) == false) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isin) {
|
||||
obj.environment = this;
|
||||
if (obj_index == -1) {
|
||||
this.items.push(obj);
|
||||
if (obj.is_player) obj.send(this.items_to_json());
|
||||
|
||||
} else if (obj.is_player) {
|
||||
if (!msg) msg = this.item_json(obj, isin);
|
||||
obj.send(msg);
|
||||
}
|
||||
} else if (obj_index > -1) {
|
||||
this.items.splice(obj_index, 1);
|
||||
obj.environment = null;
|
||||
}
|
||||
}
|
||||
ROOM.prototype.item_json = function (item, isin) {
|
||||
if (!item) return "";
|
||||
var str = [];
|
||||
if (isin) {
|
||||
str.push('{"type":"itemadd",');
|
||||
str.push("id:\"");
|
||||
str.push(item.id);
|
||||
str.push("\",name:\"");
|
||||
str.push(item.long_name());
|
||||
str.push("\"");
|
||||
if (item.is_player) {
|
||||
str.push(",p:1");
|
||||
}
|
||||
if (item.appdend_status) {
|
||||
str.push(",mp:");
|
||||
str.push(item.mp);
|
||||
str.push(",hp:");
|
||||
str.push(item.hp);
|
||||
str.push(",max_mp:");
|
||||
str.push(item.max_mp);
|
||||
str.push(",max_hp:");
|
||||
str.push(item.max_hp);
|
||||
item.appdend_status(str);
|
||||
}
|
||||
str.push("}");
|
||||
} else {
|
||||
str.push('{"type":"itemremove",id:"');
|
||||
str.push(item.id);
|
||||
str.push('"}');
|
||||
}
|
||||
return str.join("");
|
||||
}
|
||||
ROOM.prototype.items_to_json = function () {
|
||||
var str = ['{"type":"items","items":['];
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (!item.is_hidden()) {
|
||||
str.push("{id:\"");
|
||||
str.push(item.id);
|
||||
str.push("\",name:\"");
|
||||
str.push(item.long_name());
|
||||
str.push("\"");
|
||||
if (item.is_player) {
|
||||
str.push(",p:1");
|
||||
} else {
|
||||
if (!item.item_types) {
|
||||
item.item_types = item.hp > 0 ? `,m:${(item.on_checkskill || item.on_master) ? 1 : 0},l:${item.sell_list ? 1 : 0},f:${item.master ? 1 : 0}` : ",o:1";
|
||||
}
|
||||
str.push(item.item_types);
|
||||
}
|
||||
if (item.appdend_status) {
|
||||
str.push(",mp:");
|
||||
str.push(item.mp);
|
||||
str.push(",hp:");
|
||||
str.push(item.hp);
|
||||
str.push(",max_mp:");
|
||||
str.push(item.max_mp);
|
||||
str.push(",max_hp:");
|
||||
str.push(item.max_hp);
|
||||
|
||||
item.appdend_status(str);
|
||||
}
|
||||
str.push("},");
|
||||
}
|
||||
}
|
||||
str.push("0]}");
|
||||
return str.join("");
|
||||
}
|
||||
|
||||
ROOM.prototype.set_npc = function () {
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var name = arguments[i];
|
||||
if (typeof name == "string") name = [name, 1];
|
||||
var obj_path = name[0];
|
||||
if (!obj_path) continue;
|
||||
for (var j = 0; j < name[1]; j++) {
|
||||
var obj = NPC.CLONE(obj_path);
|
||||
if (obj) {
|
||||
this.items.push(obj);
|
||||
obj.environment = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.set_obj = function (names) {
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var name = arguments[i];
|
||||
if (typeof name == "string") name = [name, 1];
|
||||
var obj = OBJ.CREATE(name[0], name[1]);
|
||||
if (obj) {
|
||||
this.items.push(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
ROOM.prototype.set_item = function (id, name, desc, commands) {
|
||||
this.hidden_items = this.hidden_items || [];
|
||||
|
||||
if (commands && typeof commands[0] == "string") {
|
||||
commands = [commands];
|
||||
}
|
||||
let hidden_item = {
|
||||
id: id,
|
||||
name: name,
|
||||
desc: desc,
|
||||
commands: commands,
|
||||
query_desc: on_look_hidden_item,
|
||||
environment: this
|
||||
};
|
||||
|
||||
this.hidden_items.push(hidden_item);
|
||||
if (commands) {
|
||||
for (var j = 0; j < commands.length; j++) {
|
||||
this.add_action(commands[j][0], null, commands[j][2]);
|
||||
}
|
||||
//添加隐藏物品的命令到房间的actions,命令不能重复
|
||||
}
|
||||
return hidden_item;
|
||||
}
|
||||
|
||||
function on_look_hidden_item(player) {
|
||||
if (this.json) return this.json;
|
||||
var json = {};
|
||||
json.type = "item";
|
||||
json.desc = this.desc;
|
||||
if (this.commands) {
|
||||
json.commands = [];
|
||||
for (var i = 0; i < this.commands.length; i++) {
|
||||
if (this.commands[i][1])
|
||||
json.commands.push({
|
||||
cmd: this.commands[i][0] + " " + this.id,
|
||||
name: this.commands[i][1]
|
||||
});
|
||||
}
|
||||
}
|
||||
this.json = JSON.stringify(json)
|
||||
return this.json;
|
||||
}
|
||||
ROOM.prototype.find_obj = function (oid) {
|
||||
var items = this.items;
|
||||
if (!items) return;
|
||||
var item = this.find_obj_byid(items, oid);
|
||||
if (item) return item;
|
||||
if (!this.hidden_items) return;
|
||||
for (var i = 0; i < this.hidden_items.length; i++) {
|
||||
if (this.hidden_items[i].id == oid) return this.hidden_items[i];
|
||||
}
|
||||
}
|
||||
ROOM.prototype.find_by_path = function (path) {
|
||||
var items = this.items;
|
||||
if (!items) return;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].path == path) {
|
||||
return items[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.is_here = function (path) {
|
||||
var items = this.items;
|
||||
if (!items) return;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].path == path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.notify = function (msg) {
|
||||
if (!this.items) return;
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].is_player) {
|
||||
this.items[i].notify(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.query_exits = function (dir) {
|
||||
if (this.exits && this.exits[dir]) return true;
|
||||
return false;
|
||||
}
|
||||
ROOM.prototype.add_exit = function (dir, rm) {
|
||||
this.exits = this.exits || {};
|
||||
this.exits[dir] = rm;
|
||||
this.exits_changed();
|
||||
}
|
||||
ROOM.prototype.remove_exit = function (dir) {
|
||||
this.exits = this.exits || {};
|
||||
delete this.exits[dir];
|
||||
this.exits_changed();
|
||||
}
|
||||
|
||||
ROOM.prototype.exits_changed = function () {
|
||||
this.room_exits_json = null;
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].is_player)
|
||||
this.send_exits(this.items[i]);
|
||||
}
|
||||
}
|
||||
ROOM.prototype.send_exits = function (player) {
|
||||
player.send(this.exitsto_roomjson());
|
||||
}
|
||||
ROOM.prototype.exitsto_roomjson = function () {
|
||||
if (this.room_exits_json) return this.room_exits_json;
|
||||
var obj = {};
|
||||
obj.type = "exits";
|
||||
obj.items = {};
|
||||
if (this.exits) {
|
||||
for (var dir in this.exits) {
|
||||
if (!this.exits[dir]) continue;
|
||||
var rm = ROOM.Get(this.exits[dir]);
|
||||
if (!rm) continue;
|
||||
obj.items[dir] = rm.name;
|
||||
}
|
||||
}
|
||||
this.room_exits_json = JSON.stringify(obj);
|
||||
return this.room_exits_json;
|
||||
}
|
||||
ROOM.prototype.to_json = function () {
|
||||
if (this.json) return this.json;
|
||||
var obj = {};
|
||||
obj.type = "room";
|
||||
obj.path = this.path;
|
||||
obj.name = this.long_name;
|
||||
obj.desc = this.desc;
|
||||
obj.commands = [];
|
||||
if (this.actions) {
|
||||
for (var cmd in this.actions) {
|
||||
var name = this.actions[cmd].name;
|
||||
if (name)
|
||||
obj.commands.push({
|
||||
cmd: cmd,
|
||||
name: name
|
||||
});
|
||||
}
|
||||
}
|
||||
if (this.is_copy_room && !this.parent.not_fb) {
|
||||
obj.commands.push({
|
||||
cmd: "cr",
|
||||
name: "完成副本"
|
||||
});
|
||||
}
|
||||
this.json = JSON.stringify(obj);
|
||||
return this.json;
|
||||
|
||||
}
|
||||
ROOM.prototype.query_commands = function () {
|
||||
if (this.commands_json) return this.commands_json;
|
||||
var json = {};
|
||||
json.type = "command";
|
||||
|
||||
json.commands = [];
|
||||
if (this.actions) {
|
||||
for (var cmd in this.actions) {
|
||||
json.commands.push({
|
||||
name: this.actions[cmd].name,
|
||||
cmd: cmd
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.commands_json = JSON.stringify(json)
|
||||
return this.commands_json;
|
||||
}
|
||||
ROOM.prototype.refresh = function (obj) {
|
||||
this.json = null;
|
||||
this.commands_json = null;
|
||||
this.room_exits_json = null;
|
||||
var rmname = this.parent.name + "-" + this.name;
|
||||
if (this.parent.not_fb || !this.parent.is_copy) {
|
||||
this.long_name = rmname;
|
||||
} else {
|
||||
this.long_name = rmname + "(副本区域)";
|
||||
}
|
||||
if (obj) {
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].is_player) {
|
||||
this.items[i].send(this.to_json());
|
||||
this.send_exits(this.items[i]);
|
||||
this.items[i].send(this.items_to_json());
|
||||
}
|
||||
}
|
||||
// this.send_exits(obj);
|
||||
}
|
||||
|
||||
}
|
||||
ROOM.prototype.get_path = function () {
|
||||
if (this.path) return this.path;
|
||||
var str = this.name;
|
||||
var area = this.area;
|
||||
while (area) {
|
||||
str = area.name + "-" + str;
|
||||
area = area.parent;
|
||||
}
|
||||
this.path = str;
|
||||
return this.path;
|
||||
}
|
||||
ROOM.prototype.query_recover_room = function () {
|
||||
var area = this.parent;
|
||||
while (area) {
|
||||
if (area.recover_room) {
|
||||
return area.recover_room;
|
||||
}
|
||||
area = area.parent;
|
||||
}
|
||||
return "yz/wumiao";
|
||||
}
|
||||
ROOM.prototype.create = function (file) {
|
||||
var base_room = WORLD.ROOMS[file];
|
||||
|
||||
if (base_room) {
|
||||
this.parent = base_room.parent;
|
||||
if (this.parent.is_copy) {
|
||||
//副本区域
|
||||
if (this.parent.not_fb) {
|
||||
this.long_name = base_room.long_name;
|
||||
} else {
|
||||
this.long_name = base_room.long_name + "(副本区域)";
|
||||
}
|
||||
this.create_time = Date.now();
|
||||
this.is_copy_room = true;
|
||||
} else {
|
||||
//投影区域 房间人满了后
|
||||
this.is_shadow = true;
|
||||
this.long_name = base_room.long_name;//+ "(" + UTIL.to_c(base_room.shadow_rooms.length + 1) + "号)";
|
||||
|
||||
}
|
||||
WORLD.RUN_ROOMS.push(this);
|
||||
} else {
|
||||
this.initBaseRoom(file);
|
||||
}
|
||||
|
||||
this.on_create && this.on_create();
|
||||
}
|
||||
ROOM.prototype.initBaseRoom = function (file) {
|
||||
WORLD.ROOMS[file] = this;
|
||||
|
||||
var area = getAreaByPath(this.path);
|
||||
|
||||
this.parent = area;
|
||||
if (!area || !area.is_copy) {
|
||||
//如果是副本,第一个被创建的不放在运行的房间
|
||||
WORLD.RUN_ROOMS.push(this);
|
||||
}
|
||||
if (area) {
|
||||
if (!area.rooms) area.rooms = [];
|
||||
for (var i = 0; i < area.rooms.length; i++) {
|
||||
if (area.rooms[i].path == this.path) {
|
||||
area.rooms.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
area.rooms.push(this);
|
||||
this.long_name = area.name + "-" + this.name;
|
||||
} else {
|
||||
|
||||
this.long_name = this.name;
|
||||
}
|
||||
}
|
||||
ROOM.prototype.update = function (file) {
|
||||
this.on_create && this.on_create();
|
||||
var oldroom = WORLD.ROOMS[file];
|
||||
this.initBaseRoom(file);
|
||||
if (!oldroom) return;
|
||||
if (oldroom.copy_rooms) {
|
||||
this.copy_rooms = {};
|
||||
for (var key in oldroom.copy_rooms) {
|
||||
var rm = oldroom.copy_rooms[key];
|
||||
var newRm = BASE.CREATE(__PATH.MAP, this.path);
|
||||
this.replaceRoom(rm, newRm);
|
||||
newRm.owner = key;
|
||||
this.copy_rooms[key] = newRm;
|
||||
}
|
||||
oldroom.copy_rooms = null;
|
||||
} else {
|
||||
if (ROOM.public_rooms) {
|
||||
for (var i = 0; i < ROOM.public_rooms.length; i++) {
|
||||
if (ROOM.public_rooms[i] == oldroom) {
|
||||
ROOM.public_rooms[i] = this;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.replaceRoom = function (oldroom, newRoom) {
|
||||
var items = oldroom.items;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].is_player || items[i].master) {
|
||||
newRoom.items.push(items[i]);
|
||||
items[i].environment = newRoom;
|
||||
}
|
||||
}
|
||||
oldroom.destroy();
|
||||
}
|
||||
ROOM.prototype.destroy = function () {
|
||||
this.items.length = 0;
|
||||
this.owner = null;
|
||||
}
|
||||
ROOM.prototype.heart_beat = function (dt) {
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (!this.items[i].is_player)
|
||||
this.items[i].heart_beat(dt);
|
||||
}
|
||||
this.on_heart_beat && this.on_heart_beat(dt);
|
||||
}
|
||||
ROOM.prototype.is_copy = function () {
|
||||
if (!this.parent) return false;
|
||||
return this.parent.is_copy;
|
||||
}
|
||||
ROOM.prototype.is_fb = function () {
|
||||
if (!this.parent) return false;
|
||||
return this.parent.is_copy && !this.parent.not_fb;
|
||||
}
|
||||
ROOM.prototype.is_enter = function () {
|
||||
if (!this.parent) return false;
|
||||
return this.parent.first == this.path;
|
||||
}
|
||||
ROOM.prototype.query_fb_first = function (id) {
|
||||
//查询副本入口
|
||||
if (!this.parent || !this.parent.is_copy || !this.parent.rooms) return;
|
||||
return this.parent.rooms[0].query_copy(id);
|
||||
}
|
||||
ROOM.prototype.query_copy = function (id) {
|
||||
|
||||
if (!this.copy_rooms) this.copy_rooms = {};
|
||||
return this.copy_rooms[id];
|
||||
}
|
||||
ROOM.prototype.query_copy2 = function (user) {
|
||||
var id = this.parent.query_owner(user);
|
||||
if (!id) return this;
|
||||
return this.query_copy(id);
|
||||
}
|
||||
ROOM.prototype.clear_copy = function (me) {
|
||||
//清除复制的副本,四个位置,换地图,完成副本,复活,彻底掉线
|
||||
//但是又不能清除不是自己的副本,比如帮派
|
||||
if (!this.owner) return;
|
||||
let id = this.parent.query_owner(me);
|
||||
if (id !== this.owner) return;//只能清除自己或队伍创建的副本
|
||||
var name = "fb/";
|
||||
for (var key in me.temp) {
|
||||
if (key.startsWith(name)) {
|
||||
me.temp[key] = null;
|
||||
}
|
||||
}
|
||||
if (me.team) {
|
||||
for (var i = 0; i < me.team.length; i++) {
|
||||
let tm = me.team[i];
|
||||
if (tm !== me && tm.environment && tm.environment.parent === this.parent
|
||||
&& tm.environment.owner == this.owner) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.clear_by_area(this.parent, this.owner);
|
||||
}
|
||||
|
||||
ROOM.prototype.create_copy2 = function (me, diff_type) {
|
||||
|
||||
var id = this.parent.query_owner(me);
|
||||
if (!id) return;
|
||||
return this.create_copy(id, diff_type || 0);
|
||||
}
|
||||
ROOM.prototype.create_copy = function (id, diff_type) {
|
||||
//第一次创建副本,从入口开始创建,把所在区域所有房间都创建一遍
|
||||
if (!this.parent) return;
|
||||
// var rooms = [];
|
||||
this.create_by_area(this.parent, id, diff_type);
|
||||
//this.add_fbroom(rooms);
|
||||
return this.query_copy(id);
|
||||
}
|
||||
ROOM.prototype.create_by_area = function (area, id, diff_type) {
|
||||
if (area.rooms) {
|
||||
for (var i = 0; i < area.rooms.length; i++) {
|
||||
var base_room = area.rooms[i];
|
||||
var copy_room = BASE.CREATE(__PATH.MAP, base_room.path);
|
||||
if (!copy_room) continue;
|
||||
copy_room.set_difficulty(diff_type);
|
||||
if (!base_room.copy_rooms) base_room.copy_rooms = {};
|
||||
base_room.copy_rooms[id] = copy_room;
|
||||
copy_room.owner = id;
|
||||
}
|
||||
}
|
||||
if (area.areas) {
|
||||
for (var i = 0; i < area.areas.length; i++) {
|
||||
this.create_by_area(area.areas[i], id);
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.create_shadow = function () {
|
||||
//当房间人满了后 进入房间就另外创建一个房间投影,这种类型的房间最好不要放NPC,物品
|
||||
//这种房间创建了不销毁,重复使用
|
||||
if (this.is_copy_room || this.no_shadow) return;
|
||||
|
||||
if (!this.shadow_rooms) this.shadow_rooms = [];
|
||||
for (var i = 0; i < this.shadow_rooms.length; i++) {
|
||||
if (!this.shadow_rooms[i].is_full()) {
|
||||
return this.shadow_rooms[i];
|
||||
}
|
||||
}
|
||||
var shadow = BASE.CREATE(__PATH.MAP, this.path);
|
||||
if (shadow) {
|
||||
this.shadow_rooms.push(shadow);
|
||||
}
|
||||
return shadow;
|
||||
}
|
||||
ROOM.prototype.clear_by_area = function (area, id) {
|
||||
if (area.rooms) {
|
||||
for (var i = 0; i < area.rooms.length; i++) {
|
||||
var base_room = area.rooms[i];
|
||||
if (base_room.copy_rooms) {
|
||||
var rm = base_room.copy_rooms[id];
|
||||
if (rm) {
|
||||
WORLD.RUN_ROOMS.remove(rm);
|
||||
rm.destroy();
|
||||
delete base_room.copy_rooms[id];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (area.areas) {
|
||||
for (var i = 0; i < area.areas.length; i++) {
|
||||
this.clear_by_area(area.areas[i], id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAreaByPath(path) {
|
||||
var index = path.lastIndexOf("/");
|
||||
path = path.substr(0, index + 1);
|
||||
var items = WORLD.AREAS;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].room_path == path) return items[i];
|
||||
}
|
||||
}
|
||||
ROOM.Get = function (path) {
|
||||
var rm = WORLD.ROOMS[path];
|
||||
|
||||
if (!rm) return console.log("room %s is not exist", path);
|
||||
// if (!rm) throw new Error(path + "is not exist");
|
||||
return rm;
|
||||
}
|
||||
|
||||
|
||||
//房间存储数据,存在当前用户或队伍的房间区域的第一个房间里面,在副本销毁时候会释放
|
||||
ROOM.prototype.query_temp = function (me, name, def) {
|
||||
var first = this.query_fb_first(me.query_teamid());
|
||||
if (!first) return;
|
||||
if (!first.temp) return;
|
||||
var item = first.temp[name];
|
||||
if (item && item.e) {
|
||||
if (Date.now() <= item.e) {
|
||||
return item.v;
|
||||
}
|
||||
first.temp[name] = null;
|
||||
return def;
|
||||
}
|
||||
return item || def;
|
||||
}
|
||||
ROOM.prototype.set_temp = function (me, name, value, time) {
|
||||
var first = this.query_fb_first(me.query_teamid());
|
||||
if (!first) return;
|
||||
if (!first.temp) first.temp = {};
|
||||
if (time) {
|
||||
first.temp[name] = {
|
||||
v: value,
|
||||
e: Date.now() + time
|
||||
};
|
||||
} else {
|
||||
first.temp[name] = value;
|
||||
}
|
||||
}
|
||||
ROOM.prototype.add_temp = function (me, name, value, time) {
|
||||
let val = this.query_temp(me, name, 0) + value;
|
||||
this.set_temp(me, name, val, time);
|
||||
return val;
|
||||
}
|
||||
ROOM.RANDOM = function () {
|
||||
if (!this.public_rooms) {
|
||||
this.public_rooms = [];
|
||||
for (var i = 0; i < WORLD.AREAS.length; i++) {
|
||||
if (WORLD.AREAS[i].is_area && !WORLD.AREAS[i].is_public) {
|
||||
var rms = WORLD.AREAS[i].rooms;
|
||||
|
||||
for (var j = 0; j < rms.length; j++) {
|
||||
if (rms[j].max_item_count > 1)
|
||||
this.public_rooms.push(rms[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.public_rooms.random();
|
||||
}
|
||||
ROOM.prototype.set_difficulty = function (type) {
|
||||
this.on_set_difficulty && this.on_set_difficulty(type);
|
||||
}
|
||||
ROOM.prototype.send = function (msg) {
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].is_player) {
|
||||
this.items[i].send(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.find_me = function () {
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].is_player) {
|
||||
return this.items[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
ROOM.prototype.query = function (id) {
|
||||
let room = ROOM.Get(id);
|
||||
if (!room) return null;
|
||||
if (this.owner) {
|
||||
return room.query_copy(this.owner);
|
||||
}
|
||||
return room;
|
||||
}
|
||||
94
os/skill/family.js
Normal file
94
os/skill/family.js
Normal file
@@ -0,0 +1,94 @@
|
||||
FAMILY = function () {
|
||||
this.titles = [];
|
||||
this.npcs = [];
|
||||
this.battle_family = null;
|
||||
//this.scores = new Map();
|
||||
this.battle_score = 0;
|
||||
this.battle_gift = 0;
|
||||
this.can_battle = false;
|
||||
}
|
||||
|
||||
FAMILY.inherits(BASE);
|
||||
FAMILIES = {};
|
||||
FAMILY.prototype.set_titles = function () {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
this.titles.push(arguments[i]);
|
||||
}
|
||||
}
|
||||
FAMILY.prototype.create = function (path) {
|
||||
FAMILIES[this.id] = this;
|
||||
|
||||
}
|
||||
FAMILY.prototype.update = function (path) {
|
||||
FAMILIES[this.id] = this;
|
||||
}
|
||||
FAMILY.prototype.query_title = function (level) {
|
||||
return this.titles[level];
|
||||
}
|
||||
|
||||
|
||||
FAMILY.prototype.query_temp = CHARACTER.prototype.query_temp;
|
||||
FAMILY.prototype.set_temp = CHARACTER.prototype.set_temp;
|
||||
FAMILY.prototype.remove_temp = CHARACTER.prototype.remove_temp;
|
||||
FAMILY.prototype.add_temp = CHARACTER.prototype.add_temp;
|
||||
|
||||
FAMILY.prototype.send = function (str) {
|
||||
for (var i = 0; i < WORLD.USERS.length; i++) {
|
||||
if (WORLD.USERS[i].family == this) {
|
||||
WORLD.USERS[i].send(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
FAMILY.prototype.is_battle = function (fam) {
|
||||
return this.battle_family == fam.id;
|
||||
}
|
||||
FAMILY.prototype.add_score = function (me, sc) {
|
||||
this.battle_score += sc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CHARACTER.prototype.send_fam = function (str) {
|
||||
this.family.send(str);
|
||||
}
|
||||
FAMILY.prototype.create_name = function () {
|
||||
return UTIL.random_name(this.gender);
|
||||
}
|
||||
FAMILY.prototype.query_skill = function (grade) {
|
||||
if (!this.skill_levels) {
|
||||
this.skill_levels = [];
|
||||
for (var i = 0; i < this.skills.length; i++) {
|
||||
if (!this.skill_levels[this.skills[i].grade]) {
|
||||
this.skill_levels[this.skills[i].grade] = [];
|
||||
}
|
||||
this.skill_levels[this.skills[i].grade].push(this.skills[i]);
|
||||
}
|
||||
}
|
||||
if (grade >= this.skill_levels.length) grade = this.skill_levels.length - 1;
|
||||
return this.skill_levels[grade].random();
|
||||
}
|
||||
FAMILY.prototype.query_skills = function (grade) {
|
||||
if (!this.skill_levels) {
|
||||
this.skill_levels = [];
|
||||
for (var i = 0; i < this.skills.length; i++) {
|
||||
if (!this.skill_levels[this.skills[i].grade]) {
|
||||
this.skill_levels[this.skills[i].grade] = [];
|
||||
}
|
||||
this.skill_levels[this.skills[i].grade].push(this.skills[i]);
|
||||
}
|
||||
}
|
||||
if (grade >= this.skill_levels.length) grade = this.skill_levels.length - 1;
|
||||
return this.skill_levels[grade];
|
||||
}
|
||||
FAMILY.prototype.add_gongji = function (me, count) {
|
||||
if (!count) return;
|
||||
me.add_temp("gongji", count);
|
||||
if (count < 0) return;
|
||||
if (!this.tops) this.tops = {};
|
||||
var old = this.tops[me.id];
|
||||
if (!old) this.tops[me.id] = { name: me.name, score: count };
|
||||
else {
|
||||
old.score += count;
|
||||
}
|
||||
}
|
||||
|
||||
648
os/skill/skill.js
Normal file
648
os/skill/skill.js
Normal file
@@ -0,0 +1,648 @@
|
||||
/*global SKILL_TYPES SKILL BASE PROPERTIES WORLD FAMILIES*/
|
||||
|
||||
require("../util/util.js");
|
||||
SKILL = function () {
|
||||
this.id = "";
|
||||
this.name = "";
|
||||
this.type = SKILL_TYPES.SKILL;
|
||||
this.grade = 1;
|
||||
this.score = 0;
|
||||
}
|
||||
SKILL.inherits(BASE);
|
||||
SKILL.prototype.query_attack_action = function (me, target) {
|
||||
if (this.attack_actions)
|
||||
return this.attack_actions.random();
|
||||
return "";
|
||||
}
|
||||
SKILL.prototype.query_dodge_action = function () {
|
||||
if (!this.dodge_actions) {
|
||||
return "";
|
||||
}
|
||||
return this.dodge_actions.random();
|
||||
}
|
||||
SKILL.prototype.query_parry_action = function (me, target, w2) {
|
||||
var w1 = me.query_weapon();
|
||||
w2 = w2 || target.query_weapon();
|
||||
var act;
|
||||
if (w1 && w2) {
|
||||
act = this.weapon_vs_weapon_actions || this.parry_actions;
|
||||
} else if (w1) {
|
||||
act = this.weapon_vs_unarmed_actions || this.parry_actions;
|
||||
} else if (w2) {
|
||||
act = this.unarmed_vs_weapon_actions || this.parry_actions;
|
||||
} else {
|
||||
act = this.parry_actions;
|
||||
}
|
||||
|
||||
if (!act) {
|
||||
act = this.parry_actions = SKILL.get("parry").parry_actions;
|
||||
}
|
||||
|
||||
if (act) {
|
||||
return act.random();
|
||||
}
|
||||
}
|
||||
|
||||
SKILL.prototype.level_exp = function (lv, me) {
|
||||
var grd = this.query_grade(me);
|
||||
return (lv + 1) * (grd + 1) * 5;
|
||||
}
|
||||
SKILL.prototype.query_needexp = function (level, me) {
|
||||
if (level > 100) {
|
||||
var grd = this.query_grade(me);
|
||||
var exp = (100 + level) * (level - 100) / 2;
|
||||
return exp * (grd + 1) * 5;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SKILL.prototype.set_default = function (type) {
|
||||
WORLD.DEFAULT_SKILLS[type] = this;
|
||||
}
|
||||
|
||||
SKILL.prototype.release_prop = function (me, lv) {
|
||||
if (!lv) return;
|
||||
var prop = this.query_prop(lv, me);
|
||||
if (prop) {
|
||||
me.change_prop(prop, false);
|
||||
}
|
||||
prop = this.query_enable_prop(lv, me);
|
||||
if (prop) {
|
||||
for (var item in prop) {
|
||||
if (me.is_enable_skill(this.id, item)) {
|
||||
me.change_prop(prop[item], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
prop = this.query_addin_prop(me, lv);
|
||||
if (prop) {
|
||||
if (this.is_enable(me)) {
|
||||
me.change_prop(prop, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SKILL.prototype.attach_prop = function (me, lv) {
|
||||
if (!lv) return;
|
||||
var prop = this.query_prop(lv, me);
|
||||
if (prop) {
|
||||
me.change_prop(prop, true);
|
||||
}
|
||||
prop = this.query_enable_prop(lv, me);
|
||||
if (prop) {
|
||||
for (var item in prop) {
|
||||
if (me.is_enable_skill(this.id, item)) {
|
||||
me.change_prop(prop[item], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
prop = this.query_addin_prop(me, lv);
|
||||
if (prop) {
|
||||
if (this.is_enable(me)) {
|
||||
me.change_prop(prop, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
SKILL.prototype.query_enable_prop = function (lv) {
|
||||
|
||||
}
|
||||
SKILL.prototype.query_prop = function (lv) {
|
||||
|
||||
}
|
||||
|
||||
SKILL.prototype.query_grade = function (me) {
|
||||
var sk = me.skills[this.id];
|
||||
var lv = this.grade;
|
||||
if (sk) {
|
||||
if (sk.addin)
|
||||
lv += sk.addin.length;
|
||||
if (sk.ref)
|
||||
lv += 1;
|
||||
}
|
||||
|
||||
return lv;
|
||||
}
|
||||
SKILL.prototype.query_color_name = function (me) {
|
||||
|
||||
var desc = level_color[this.query_grade(me)];
|
||||
return "<" + desc + ">" + this.name + "</" + desc + ">";
|
||||
}
|
||||
|
||||
SKILL.prototype.query_addin_prop = function (me, lv) {
|
||||
var sk = me.skills[this.id];
|
||||
if (sk.addin && sk.addin.length) {
|
||||
var prop = {};
|
||||
var grd = this.grade + sk.addin.length;
|
||||
for (let slot of sk.addin) {
|
||||
let item = this.query_slot(slot);
|
||||
if (!item) continue;
|
||||
if (item.prop) {
|
||||
prop[item.prop] = (prop[item.prop] ?? 0)
|
||||
+ parseInt(item.value(lv, grd));
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
SKILL.prototype.is_enable = function (me) {
|
||||
if (this.type !== SKILL_TYPES.SKILL) return true;
|
||||
var skill = me.skills[this.id];
|
||||
for (var i = 0; i < this.can_enables.length; i++) {
|
||||
if (skill[this.can_enables[i]]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
SKILL.prototype.is_enable2 = function (me, baseskill) {
|
||||
var skill = me.skills[this.id];
|
||||
|
||||
return skill ? skill[baseskill] : false;
|
||||
}
|
||||
//激活技能,附加装备的部分属性
|
||||
SKILL.prototype.enable = function (me, type) {
|
||||
if (!this.can_enables || !this.can_enables.contain(type)) return false;
|
||||
if (this.on_enable && this.on_enable(me, type) === false) return false;
|
||||
var lv = me.query_skill(this.id);
|
||||
var prop = this.query_enable_prop(lv);
|
||||
if (prop) {
|
||||
var enable_prop = prop[type];
|
||||
if (enable_prop) {
|
||||
me.change_prop(enable_prop, true);
|
||||
}
|
||||
}
|
||||
//附加进阶属性
|
||||
prop = this.query_addin_prop(me, lv);
|
||||
if (prop) {
|
||||
if (!this.is_enable(me)) {
|
||||
me.change_prop(prop, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//取消激活技能,解除装备的部分属性
|
||||
SKILL.prototype.disenable = function (me, type) {
|
||||
this.on_disenable && this.on_disenable(me, type);
|
||||
var lv = me.query_skill(this.id);
|
||||
var prop = this.query_enable_prop(lv);
|
||||
if (prop) {
|
||||
var enable_prop = prop[type];
|
||||
if (enable_prop) {
|
||||
me.change_prop(enable_prop, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//附加进阶属性
|
||||
prop = this.query_addin_prop(me, lv);
|
||||
if (prop) {
|
||||
if (!this.is_enable(me)) {
|
||||
|
||||
me.change_prop(prop, false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
SKILL.prototype.do_learn = function (me) {
|
||||
if (this.on_learn && this.on_learn(me) === false) return false;
|
||||
if (this.learn_condition) {
|
||||
for (var key in this.learn_condition) {
|
||||
var val = this.learn_condition[key];
|
||||
switch (key) {
|
||||
case "skill":
|
||||
for (var sk in val) {
|
||||
if (me.query_skill(sk, 0) < val[sk] && me.query_skill(sk + "2", 0) < val[sk]) {
|
||||
var sk_base = SKILL.get(sk);
|
||||
|
||||
return me.notify_fail("你的" + sk_base.color_name + "等级不够" + val[sk] + ",无法学习" + this.color_name + "。");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "str1":
|
||||
case "con1":
|
||||
case "dex1":
|
||||
case "int1":
|
||||
if (me.is_player && me[key.replace("1", "")] < val) {
|
||||
return me.notify_fail("你的" + PROPERTIES[key] + "不够" + val + ",无法学习" + this.color_name + "。");
|
||||
}
|
||||
break;
|
||||
case "str":
|
||||
case "con":
|
||||
case "dex":
|
||||
case "int":
|
||||
if (me[key] + me.query_prop(key) < val) {
|
||||
return me.notify_fail("你的" + PROPERTIES[key] + "不够" + val + ",无法学习" + this.color_name + "。");
|
||||
}
|
||||
break;
|
||||
case "gender":
|
||||
if (me.gender !== val) return me.notify_fail("你不是" + (val === 1 ? "男性" : val === 2 ? "女性" : "无性") + ",无法学习" + this.color_name + "。");
|
||||
break;
|
||||
case "desc":
|
||||
break;
|
||||
default:
|
||||
var me_val = me[key] || 0;
|
||||
me_val = me_val + me.query_prop(key);
|
||||
if (!me_val || me_val < val) {
|
||||
|
||||
return me.notify_fail("你的" + PROPERTIES[key] + "不够" + val + ",无法学习" + this.color_name + "。");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.type === SKILL_TYPES.SKILL && this.can_enables) {
|
||||
for (var i = 0; i < this.can_enables.length; i++) {
|
||||
if (!me.query_skill(this.can_enables[i], 0)) {
|
||||
var skill = SKILL.get(this.can_enables[i]);
|
||||
return me.notify_fail("你还不会" + skill.color_name + ",无法学习" + this.color_name + "。");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SKILL.prototype.condition_tostring = function (me) {
|
||||
if (this.learn_condition_string) return this.learn_condition_string;
|
||||
var str = [];
|
||||
if (this.learn_condition) {
|
||||
for (var key in this.learn_condition) {
|
||||
var val = this.learn_condition[key];
|
||||
switch (key) {
|
||||
case "skill":
|
||||
for (var sk in val) {
|
||||
var sk_base = SKILL.get(sk);
|
||||
str.push(sk_base.name + ":" + val[sk] + "级");
|
||||
}
|
||||
break;
|
||||
case "desc":
|
||||
str.push(val);
|
||||
break;
|
||||
case "gender":
|
||||
str.push("性别:" + (val === 1 ? "男" : (val === 2 ? "女" : "无性")));
|
||||
break;
|
||||
default:
|
||||
str.push(PROPERTIES[key] + ":" + val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.learn_condition_string = str.join("\n");
|
||||
return this.learn_condition_string;
|
||||
}
|
||||
SKILL.prototype.item_to_json = function (str, skill_item, me) {
|
||||
str.push('{"id":"');
|
||||
str.push(this.id);
|
||||
|
||||
str.push('","name":"');
|
||||
str.push(this.query_color_name(me));
|
||||
str.push('",grade:', this.query_grade(me));
|
||||
str.push(',"level":');
|
||||
str.push(me.query_skill(this.id));
|
||||
str.push(',"exp":');
|
||||
skill_item.exp = skill_item.exp || 0;
|
||||
str.push(parseInt(skill_item.exp * 100 / this.level_exp(skill_item.level, me)));
|
||||
if (this.can_enables) {
|
||||
str.push(',"can_enables":[');
|
||||
for (var i = 0; i < this.can_enables.length; i++) {
|
||||
if (i > 0) str.push(",");
|
||||
str.push('"');
|
||||
str.push(this.can_enables[i]);
|
||||
str.push('"');
|
||||
}
|
||||
str.push(']');
|
||||
}
|
||||
|
||||
if (skill_item.enable_skill) {
|
||||
str.push(',"enable_skill":"');
|
||||
str.push(skill_item.enable_skill);
|
||||
str.push('"');
|
||||
}
|
||||
str.push('}');
|
||||
}
|
||||
SKILL.prototype.add_exp = function (me, exp) {
|
||||
var skill = me.skills[this.id];
|
||||
if (!skill) {
|
||||
skill = {
|
||||
// id: this.id,
|
||||
level: 0,
|
||||
exp: 0
|
||||
};
|
||||
var str = ['{type:"dialog",dialog:"skills",item:'];
|
||||
this.item_to_json(str, skill, me);
|
||||
str.push("}");
|
||||
me.notify(str.join(""));
|
||||
me.skills[this.id] = skill;
|
||||
if (this.type === SKILL_TYPES.BASE) {
|
||||
me.init_skill();
|
||||
}
|
||||
}
|
||||
var need_exp = this.level_exp(skill.level, me);
|
||||
skill.exp += exp;
|
||||
if (skill.exp >= need_exp) {
|
||||
this.release_prop(me, me.query_skill(this.id));
|
||||
var sum_score = 0;
|
||||
var color_name = this.query_color_name(me);
|
||||
var one_score = this.query_one_score(me);
|
||||
while (skill.exp >= need_exp) {
|
||||
skill.exp -= need_exp;
|
||||
need_exp = this.level_exp(skill.level, me);
|
||||
me.notify("<hiy>你的" + color_name + "等级提升了!</hiy>");
|
||||
skill.level++;
|
||||
if (skill.level > 100)
|
||||
sum_score += one_score;
|
||||
}
|
||||
var lv = me.query_skill(this.id);
|
||||
this.attach_prop(me, lv);
|
||||
me.notify('{type:"dialog",dialog:"skills",id:"' + this.id + '",level:' + lv + ',exp:' + parseInt(skill.exp * 100 / need_exp) + '}');
|
||||
me.recount();
|
||||
me.add_score(sum_score);
|
||||
return true;
|
||||
} else {
|
||||
me.notify('{type:"dialog",dialog:"skills",id:"' + this.id + '",exp:' + parseInt(skill.exp * 100 / need_exp) + '}');
|
||||
}
|
||||
}
|
||||
SKILL.prototype.query_score = function (lv, me) {
|
||||
if (lv <= 100) return 0;
|
||||
return (lv - 100) * this.query_one_score(me);
|
||||
}
|
||||
|
||||
SKILL.prototype.query_one_score = function (me) {
|
||||
var sc = 0;
|
||||
if (this.type === SKILL_TYPES.SKILL) {
|
||||
sc = this.query_grade(me);
|
||||
} else if (this.type === SKILL_TYPES.BASE) {
|
||||
sc = 1;
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
SKILL.prototype.grade_up = function (me, target_skill) {
|
||||
var skill = me.skills[this.id];
|
||||
if (!skill || !(skill.level >= 1000)) return false;
|
||||
|
||||
if (me.remove_skill(this.id) === false) return false;
|
||||
me.notify('{type:"dialog",dialog:"skills",remove:"' + this.id + '"}');
|
||||
var pot = this.query_needexp(skill.level, me);
|
||||
var lv = pot * 2 / 5 / (target_skill.grade + 1);
|
||||
skill = {
|
||||
level: parseInt(Math.pow(lv, 0.5)),
|
||||
exp: 0
|
||||
};
|
||||
me.skills[target_skill.id] = skill;
|
||||
var str = ['{type:"dialog",dialog:"skills",item:'];
|
||||
target_skill.item_to_json(str, skill, me);
|
||||
str.push("}");
|
||||
me.notify(str.join(""));
|
||||
me.add_score(target_skill.query_score(skill.level, me));
|
||||
target_skill.attach_prop(me, skill.level);
|
||||
me.recount();
|
||||
return true;
|
||||
}
|
||||
SKILL.prototype.get_pfm = function (name) {
|
||||
if (this.pfm) {
|
||||
return this.pfm[name];
|
||||
}
|
||||
}
|
||||
SKILL.prototype.set_pfm = function (name, obj) {
|
||||
if (!this.pfm) {
|
||||
this.pfm = {};
|
||||
}
|
||||
this.pfm[name] = obj;
|
||||
}
|
||||
var level_color = ["wht", "hig", "hic", "hiy", "hiz", "hio", "ord"];
|
||||
var level_desc = ["基本技能", "普通技能", "高级技能", "稀有武技", "绝世武功", "绝世神功", "无上神武"];
|
||||
|
||||
SKILL.prototype.create = function (fname) {
|
||||
if (WORLD.SKILLS[this.id]) {
|
||||
console.log("%s [%s] is repeated ", this.id, fname);
|
||||
}
|
||||
this.update(fname);
|
||||
}
|
||||
SKILL.prototype.store = function () {
|
||||
if (this.type === SKILL_TYPES.KNOWLEDGE
|
||||
|| this.type === SKILL_TYPES.BASE
|
||||
) return;
|
||||
for (var i = 0; i < this.can_enables.length; i++) {
|
||||
if (!SKILL[this.can_enables[i]]) SKILL[this.can_enables[i]] = new Array(7);
|
||||
if (!SKILL[this.can_enables[i]][this.grade]) SKILL[this.can_enables[i]][this.grade] = [];
|
||||
SKILL[this.can_enables[i]][this.grade].push(this);
|
||||
}
|
||||
}
|
||||
|
||||
SKILL.prototype.update = function (fname) {
|
||||
WORLD.SKILLS[this.id] = this;
|
||||
var fam = this.family || FAMILIES.NONE;
|
||||
if (!fam.skills2) fam.skills2 = [];
|
||||
if (!fam.skills) fam.skills = [];
|
||||
if (!fam.skills3) fam.skills3 = [];
|
||||
if (!fam.skills4) fam.skills4 = [];
|
||||
var isAddIn = false;
|
||||
var ary = this.source_skill ?
|
||||
(this.is_ultimate ? fam.skills3 : fam.skills2) :
|
||||
(this.is_ultimate ? fam.skills4 : fam.skills);
|
||||
if (this.type === SKILL_TYPES.KNOWLEDGE || this.is_hidden) {
|
||||
if (!fam.skills0) fam.skills0 = [];
|
||||
ary = fam.skills0;
|
||||
}
|
||||
for (var i = 0; i < ary.length; i++) {
|
||||
if (ary[i].id === this.id) {
|
||||
ary[i] = this;
|
||||
isAddIn = true;
|
||||
break;
|
||||
}
|
||||
if (ary[i].grade > this.grade) {
|
||||
ary.splice(i, 0, this);
|
||||
isAddIn = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isAddIn) {
|
||||
ary.push(this);
|
||||
}
|
||||
this.store();
|
||||
|
||||
var desc = level_color[this.grade];
|
||||
this.color_name = "<" + desc + ">" + this.name + "</" + desc + ">";
|
||||
if (this.pfm) {
|
||||
for (var key in this.pfm) {
|
||||
var pfm = this.pfm[key];
|
||||
if (pfm.enable_skill === 'sword' || pfm.enable_skill === 'blade' || pfm.enable_skill === 'whip'
|
||||
|| pfm.enable_skill === 'staff' || pfm.enable_skill === 'club') {
|
||||
pfm.is_weapon = true;
|
||||
}
|
||||
pfm.id = this.id + "/" + key;
|
||||
pfm.pid = key;
|
||||
pfm.__proto__ = PERFORM.prototype;
|
||||
}
|
||||
}
|
||||
}
|
||||
SKILL.get = function (id) {
|
||||
return WORLD.SKILLS[id];
|
||||
}
|
||||
SKILL.prototype.query_desc = function (me, lv) {
|
||||
var str = [];
|
||||
var grd = this.query_grade(me);
|
||||
var cc = level_color[grd];
|
||||
str.push("<" + cc + ">" + this.name + "</" + cc + ">");
|
||||
str.push("\n");
|
||||
if (this.family) {
|
||||
str.push(this.family.name);
|
||||
} else {
|
||||
str.push("公共");
|
||||
}
|
||||
str.push(level_desc[grd]);
|
||||
str.push("\n");
|
||||
|
||||
str.push(this.desc);
|
||||
str.push("\n");
|
||||
var prop = this.query_prop(lv, me);
|
||||
if (prop) {
|
||||
str.push("<");
|
||||
str.push(cc);
|
||||
str.push(">");
|
||||
str.push(UTIL.prop_toString(prop));
|
||||
str.push("</");
|
||||
str.push(cc);
|
||||
str.push(">\n");
|
||||
}
|
||||
prop = this.query_enable_prop(lv, me);
|
||||
var isEnable = this.type === SKILL_TYPES.KNOWLEDGE;
|
||||
if (prop) {
|
||||
for (var item in prop) {
|
||||
var is_enable = me.is_enable_skill(this.id, item);
|
||||
if (is_enable) isEnable = true;
|
||||
str.push("<");
|
||||
str.push(is_enable ? cc : "blk");
|
||||
str.push(">当装备为");
|
||||
str.push(SKILL.get(item).name);
|
||||
str.push("时:\n");
|
||||
str.push(UTIL.prop_toString(prop[item]));
|
||||
str.push("</");
|
||||
str.push(is_enable ? cc : "blk");
|
||||
str.push(">\n");
|
||||
}
|
||||
}
|
||||
var sk = me.skills[this.id];
|
||||
if (sk && sk.addin && sk.addin.length) {
|
||||
str.push("\n<");
|
||||
str.push(isEnable ? cc : "blk");
|
||||
str.push(">");
|
||||
|
||||
let grd = this.grade + sk.addin.length;
|
||||
for (let slot of sk.addin) {
|
||||
let item = this.query_slot(slot);
|
||||
if (item) {
|
||||
str.push("◆");
|
||||
if (item.name) {
|
||||
str.push(item.name);
|
||||
str.push(" ");
|
||||
}
|
||||
str.push(item.format(parseInt(item.value(lv, grd))));
|
||||
str.push("\n");
|
||||
}
|
||||
}
|
||||
str.push("</");
|
||||
str.push(isEnable ? cc : "blk");
|
||||
str.push(">\n");
|
||||
}
|
||||
if (this.pfm) {
|
||||
str.push("<line>绝招</line>\n");
|
||||
for (let item in this.pfm) {
|
||||
var p_item = this.pfm[item];
|
||||
if (!p_item.name) continue;
|
||||
this.query_pfm_desc(me, p_item, str, lv);
|
||||
str.push("\n\n");
|
||||
|
||||
}
|
||||
}
|
||||
if (sk && sk.ref) {
|
||||
var refs = sk.ref.split("/");
|
||||
var sp_skill = SKILL.get(refs[0]);
|
||||
if (sp_skill) {
|
||||
var pfm = sp_skill.get_pfm(refs[1]);
|
||||
if (pfm) {
|
||||
this.query_pfm_desc(me, pfm, str, lv, sp_skill.name);
|
||||
str.push("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return str.join("");
|
||||
}
|
||||
SKILL.prototype.query_slot = function (index) {
|
||||
if (index < 500) {
|
||||
return SKILL.PROPERTIES[index];
|
||||
} else {
|
||||
return this.slots ? this.slots[index - 500] : null;
|
||||
}
|
||||
}
|
||||
SKILL.REF_CD = 2;
|
||||
SKILL.SLOTS = {};
|
||||
SKILL.prototype.query_pfm_desc = function (me, p_item, str, lv, pname) {
|
||||
var canuse = !p_item.check || p_item.check(me, lv) === true;
|
||||
var color = canuse ? "hic" : "red";
|
||||
if (pname) color = 'hir';
|
||||
str.push("<");
|
||||
str.push(color);
|
||||
str.push(">【");
|
||||
if (pname) {
|
||||
str.push(pname);
|
||||
str.push("•");
|
||||
|
||||
}
|
||||
str.push(p_item.name);
|
||||
str.push("】");
|
||||
if (!canuse) {
|
||||
str.push(p_item.use_condition || "");
|
||||
}
|
||||
str.push("</");
|
||||
str.push(color);
|
||||
str.push(">");
|
||||
if (pname) lv = parseInt(lv / 2);
|
||||
str.push("\n内力消耗:");
|
||||
str.push(p_item.query_mp(me, lv));
|
||||
str.push("\t出招时间:");
|
||||
str.push(p_item.query_releasetime(me, lv) / 1000);
|
||||
str.push("秒\t冷却时间:");
|
||||
str.push(p_item.query_distime(me, lv, pname) / 1000);
|
||||
str.push("秒\n");
|
||||
str.push(p_item.query_desc(me, lv));
|
||||
}
|
||||
|
||||
|
||||
PERFORM = function () {
|
||||
this.name = "";
|
||||
}
|
||||
PERFORM.inherits(BASE);
|
||||
|
||||
PERFORM.prototype.query_name = function (me) {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
PERFORM.prototype.change_distime = function (me, id, add_time) {
|
||||
if (me.is_player) {
|
||||
var dis_time = me.temp["pfm/" + id];
|
||||
if (dis_time) {
|
||||
if (add_time)
|
||||
dis_time.e += add_time;
|
||||
else {
|
||||
add_time = -dis_time.time;
|
||||
dis_time.e = 1;
|
||||
}
|
||||
me.notify('{type:"changepfm",id:"' + id + '",time:' + add_time + '}');
|
||||
}
|
||||
} else if (me.auto_skills) {
|
||||
for (var i = 0; i < me.auto_skills.length; i++) {
|
||||
var item = me.auto_skills[i];
|
||||
if (item.pfm === this) {
|
||||
if (add_time)
|
||||
item.release_time += add_time;
|
||||
else
|
||||
item.release_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
49
os/task/events.js
Normal file
49
os/task/events.js
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
EVENTS = function () {
|
||||
|
||||
}
|
||||
EVENTS.inherits(BASE);
|
||||
|
||||
EVENTS.add = function (item) {
|
||||
if (!item || !item.id) return;
|
||||
Object.setPrototypeOf(item, EVENT_BASE);
|
||||
const items = WORLD.USER_EVENTS;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].id == item.id) {
|
||||
items[i] = item;
|
||||
return this.notify(item, 1);
|
||||
}
|
||||
}
|
||||
items.push(item);
|
||||
this.notify(item, 0);
|
||||
}
|
||||
EVENTS.ACTIONS = ['add', 'update', 'finish'];
|
||||
EVENTS.notify = function (item, act) {
|
||||
let users = WORLD.USERS;
|
||||
let msg = `{type: "dialog", dialog: "events",${EVENTS.ACTIONS[act]}:1}`;
|
||||
for (let user of users) {
|
||||
if (!user.socket) continue;
|
||||
if (item.check && !item.check(user))
|
||||
continue;
|
||||
user.send(msg);
|
||||
}
|
||||
}
|
||||
EVENTS.remove = function (id) {
|
||||
if (!id) return;
|
||||
const items = WORLD.USER_EVENTS;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].id == id) {
|
||||
EVENTS.notify(items[i], 2);
|
||||
return items.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const EVENT_BASE = {
|
||||
query_desc: function () {
|
||||
return this.desc;
|
||||
},
|
||||
query_grade: function () {
|
||||
return this.grade;
|
||||
}
|
||||
};
|
||||
48
os/task/playertask.js
Normal file
48
os/task/playertask.js
Normal file
@@ -0,0 +1,48 @@
|
||||
require("../util/util");
|
||||
USERTASK = function () {
|
||||
|
||||
}
|
||||
USERTASK.inherits(BASE);
|
||||
|
||||
USERTASK.prototype.create = function (path) {
|
||||
WORLD.TASKS.push(this);
|
||||
|
||||
this.on_create && this.on_create();
|
||||
}
|
||||
USERTASK.prototype.update = function (path) {
|
||||
this.on_create && this.on_create();
|
||||
for (var i = 0; i < WORLD.TASKS.length; i++) {
|
||||
if (WORLD.TASKS[i].path == path) {
|
||||
WORLD.TASKS[i] = this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
WORLD.TASKS.push(this);
|
||||
}
|
||||
USERTASK.prototype.query_title = function () {
|
||||
|
||||
}
|
||||
USERTASK.prototype.start = function () {
|
||||
|
||||
}
|
||||
USERTASK.prototype.query_desc = function () {
|
||||
|
||||
}
|
||||
USERTASK.prototype.query_state = function () {
|
||||
//0 不显示 1,进行中,2.可领取 3.已完成
|
||||
}
|
||||
USERTASK.RUN = function (id, player) {
|
||||
for (var i = 0; i < WORLD.TASKS.length; i++) {
|
||||
if (WORLD.TASKS[i].id == id) {
|
||||
return WORLD.TASKS[i].start(player);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
USERTASK.GET = function (id) {
|
||||
for (var i = 0; i < WORLD.TASKS.length; i++) {
|
||||
if (WORLD.TASKS[i].id == id) {
|
||||
return WORLD.TASKS[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
36
os/task/task.js
Normal file
36
os/task/task.js
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
TASK = function () {
|
||||
|
||||
}
|
||||
TASK.inherits(BASE);
|
||||
TASK.prototype.create = function () {
|
||||
WORLD.SYSTEMTASKS.push(this);
|
||||
this.startup();
|
||||
}
|
||||
TASK.GET = function (id) {
|
||||
for (var i = 0; i < WORLD.SYSTEMTASKS.length; i++) {
|
||||
if (WORLD.SYSTEMTASKS[i].id == id) {
|
||||
return WORLD.SYSTEMTASKS[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
TASK.prototype.update = function (path) {
|
||||
var oldtask = null;
|
||||
for (var i = 0; i < WORLD.SYSTEMTASKS.length; i++) {
|
||||
if (WORLD.SYSTEMTASKS[i].path == path) {
|
||||
WORLD.SYSTEMTASKS[i].stop();
|
||||
oldtask = WORLD.SYSTEMTASKS[i];
|
||||
WORLD.SYSTEMTASKS[i] = this;
|
||||
}
|
||||
}
|
||||
if (!oldtask) {
|
||||
WORLD.SYSTEMTASKS.push(this);
|
||||
}
|
||||
this.startup(oldtask);
|
||||
}
|
||||
TASK.prototype.startup = function () {
|
||||
|
||||
}
|
||||
TASK.prototype.stop = function () {
|
||||
|
||||
}
|
||||
154
os/util/data.js
Normal file
154
os/util/data.js
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
const fs_sync = require("fs");
|
||||
const fs = fs_sync.promises;
|
||||
|
||||
const DB = __CONFIG.DB;
|
||||
|
||||
module.exports = {
|
||||
close: function () {
|
||||
return DB.close();
|
||||
},
|
||||
getRoles: function (userid, server) {
|
||||
return DB.getRoles(userid, server);
|
||||
},
|
||||
addRole: async function (role) {
|
||||
return await DB.addRole(role);
|
||||
},
|
||||
deleteRole: function (userid, roleid) {
|
||||
return DB.deleteRole(userid, roleid);
|
||||
},
|
||||
saveRole: function (role) {
|
||||
return DB.saveRole(role);
|
||||
},
|
||||
saveRoles: async function (roles) {
|
||||
const dt = new Date();
|
||||
const path = __PATH.DATA + "bak/data" + dt.getFullYear() + "-" + (dt.getMonth() + 1) + "-" + dt.getDate() + "-" + dt.getHours() + ".js";
|
||||
const stream = fs_sync.createWriteStream(path, { flags: 'a' });
|
||||
try {
|
||||
stream.write('[');
|
||||
for (let role of roles) {
|
||||
await DB.saveRole(role);
|
||||
this.localBak(stream, role);
|
||||
|
||||
}
|
||||
stream.write('0]');
|
||||
} catch (error) {
|
||||
console.error('备份数据失败:', error);
|
||||
} finally {
|
||||
stream.end();
|
||||
}
|
||||
|
||||
},
|
||||
localBak: function (stream, role) {
|
||||
stream.write('{id:"');
|
||||
stream.write(role.id);
|
||||
stream.write('",name:"');
|
||||
stream.write(role.name);
|
||||
stream.write('",userid:');
|
||||
stream.write(role.userid.toString());
|
||||
stream.write(',title:"');
|
||||
stream.write(role.title);
|
||||
stream.write('",level:');
|
||||
stream.write(role.level.toString());
|
||||
stream.write(',data:');
|
||||
stream.write(role.data);
|
||||
stream.write('},');
|
||||
},
|
||||
saveRequest: function (recs) {
|
||||
var dt = new Date();
|
||||
var f = dt.getFullYear() + "-" + (dt.getMonth() + 1) + "-" + dt.getDate();
|
||||
var path = __PATH.DATA + "req/request" + f + ".txt";
|
||||
var ary = [];
|
||||
for (var i = 0; i < recs.length; i++) {
|
||||
var r = recs[i];
|
||||
ary.push(r.time);
|
||||
ary.push(" ");
|
||||
ary.push(r.user);
|
||||
ary.push(" ");
|
||||
ary.push(r.cmd);
|
||||
ary.push("\r\n");
|
||||
}
|
||||
return fs.appendFile(path, ary.join(""));
|
||||
},
|
||||
saveLogs: function (logs) {
|
||||
var dt = new Date();
|
||||
var f = dt.getFullYear() + "-" + (dt.getMonth() + 1) + "-" + dt.getDate();
|
||||
var path = __PATH.DATA + "log/log" + f + ".txt";
|
||||
var ary = [];
|
||||
for (var i = 0; i < logs.length; i++) {
|
||||
var r = logs[i];
|
||||
ary.push(r.time);
|
||||
ary.push(" ");
|
||||
ary.push(r.user);
|
||||
ary.push(" ");
|
||||
ary.push(r.cmd);
|
||||
ary.push(" ");
|
||||
ary.push(r.msg);
|
||||
ary.push("\r\n");
|
||||
}
|
||||
return fs.appendFile(path, ary.join(""));
|
||||
},
|
||||
saveData: async function (content) {
|
||||
let path = __PATH.DATA + "data.js";
|
||||
let dt = new Date();
|
||||
var f = dt.getFullYear() + "-" + (dt.getMonth() + 1) + "-" + dt.getDate();
|
||||
let _dst = __PATH.DATA + "/temp/temp" + f + ".js";
|
||||
await fs.copyFile(path, _dst);
|
||||
return fs.writeFile(path, content);
|
||||
}, readData: async function () {
|
||||
let path = __PATH.DATA + "data.js";
|
||||
try {
|
||||
const data = await fs.readFile(path);
|
||||
return JSON.toObject(data);
|
||||
} catch (error) {
|
||||
console.error('数据读取失败', path, error);
|
||||
}
|
||||
},
|
||||
getRoleData: function (userid, id) {
|
||||
|
||||
return DB.getData(userid, id);
|
||||
},
|
||||
change_name: function (id, name) {
|
||||
return DB.updateRoleName(id, name);
|
||||
},
|
||||
change_userid: function (id, fromuserid, touserid) {
|
||||
return DB.updateUserid(id, fromuserid, touserid);
|
||||
},
|
||||
check_file: async function (path) {
|
||||
try {
|
||||
await fs.access(path)
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
initDataDir: async function () {
|
||||
__PATH.BASE_DATA = __PATH.DATA;
|
||||
__PATH.DATA = __PATH.DATA + WORLD.SERVERID + "/";
|
||||
|
||||
if (!await this.check_file(__PATH.DATA)) {
|
||||
console.log('创建备份文件夹....');
|
||||
await fs.mkdir(__PATH.DATA);
|
||||
}
|
||||
var paths = await fs.readdir(__PATH.DEF_DATA);
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var _src = __PATH.DEF_DATA + paths[i];
|
||||
var _dst = __PATH.DATA + paths[i];
|
||||
if (!await this.check_file(_dst)) {
|
||||
var stat = await fs.stat(_src);
|
||||
if (stat.isFile()) {
|
||||
await fs.copyFile(_src, _dst);
|
||||
console.log('创建备份文件 ', _dst, "....");
|
||||
} else {
|
||||
await fs.mkdir(_dst);
|
||||
console.log('创建备份文件夹 ', _dst, "....");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
getServers: function () {
|
||||
return DB.getServers();
|
||||
}
|
||||
};
|
||||
|
||||
406
os/util/util.js
Normal file
406
os/util/util.js
Normal file
@@ -0,0 +1,406 @@
|
||||
|
||||
|
||||
const util = require('util');
|
||||
const JSON5 = require('json5');
|
||||
//nodejs自带的原型继承方法
|
||||
Function.prototype.inherits = function (superCtor) {
|
||||
|
||||
util.inherits(this, superCtor);
|
||||
}
|
||||
Array.prototype.remove = function (item) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] == item) {
|
||||
this.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Array.prototype.contain = function (item) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Array.prototype.random = function (index) {
|
||||
index = index || this.length;
|
||||
return this[Math.floor(Math.random() * this.length)];
|
||||
}
|
||||
JSON.toObject = function (str) {
|
||||
return JSON5.parse(str);
|
||||
|
||||
}
|
||||
UTIL = {
|
||||
empty: function () {
|
||||
},
|
||||
require: function (str) {
|
||||
return require(str);
|
||||
},
|
||||
is_gift: function () {
|
||||
return false;
|
||||
},
|
||||
wrandom: function (me, max, rate = 86400000) {
|
||||
let key = parseInt(me.id[0], 36);
|
||||
if (!(key >= 0)) key = 1;
|
||||
let time = Math.floor(Date.now() / rate) + key;
|
||||
return time % max;
|
||||
},
|
||||
moneyToStr: function (value) {
|
||||
if (!value) return "";
|
||||
var str = [];
|
||||
if (value >= 10000) {
|
||||
str.push(parseInt(value / 10000) + "两<hiy>黄金</hiy>");
|
||||
value = value % 10000;
|
||||
}
|
||||
if (value > 100) {
|
||||
str.push(parseInt(value / 100) + "两<wht>白银</wht>");
|
||||
value = value % 100;
|
||||
}
|
||||
if (value > 0) {
|
||||
str.push(value + "个<yel>铜板</yel>");
|
||||
}
|
||||
return str.join("");
|
||||
},
|
||||
timeSpan: function (time) {
|
||||
let str = [];
|
||||
if (time > 86400000) {
|
||||
str.push(Math.floor(time / 86400000), '天');
|
||||
time = time % 86400000;
|
||||
}
|
||||
if (time > 3600000) {
|
||||
str.push(Math.floor(time / 3600000), '小时');
|
||||
time = time % 3600000;
|
||||
}
|
||||
if (time > 60000) {
|
||||
str.push(Math.floor(time / 60000), '分钟');
|
||||
time = time % 60000;
|
||||
}
|
||||
str.push(Math.floor(time / 1000), '秒');
|
||||
return str.join("");
|
||||
},
|
||||
C_STR: "零一二三四五六七八九",
|
||||
C_STR2: ["", "十", "百", "千", "万", "亿"],
|
||||
C_STR3: ["", "万", "亿"],
|
||||
to_c: function (num) {
|
||||
if (!num) return "";
|
||||
var str = "";
|
||||
var count = 0;
|
||||
var add = 0;//0=0,1=数 2=百十千 3=万亿
|
||||
while (num) {
|
||||
var d = num % 10;
|
||||
if (count) {
|
||||
if (count % 4 == 0 && add != 3) {
|
||||
str = UTIL.C_STR3[count / 4] + str;
|
||||
add = 3;
|
||||
} else if (d && add != 2) {
|
||||
str = UTIL.C_STR2[count % 4] + str;
|
||||
add = 2;
|
||||
}
|
||||
}
|
||||
if (d) {
|
||||
if (d != 1 || num > 10 || count % 4 != 1)
|
||||
str = UTIL.C_STR[d] + str;
|
||||
add = 1;
|
||||
} else if (add == 1) {
|
||||
str = UTIL.C_STR[d] + str;
|
||||
add = 0;
|
||||
}
|
||||
num = parseInt(num / 10);
|
||||
count++;
|
||||
}
|
||||
return str;
|
||||
},
|
||||
htmlEncode: function (str) {
|
||||
if (!str) return str;
|
||||
return str.replace(/>/g, ">")
|
||||
.replace(/</g, "<")
|
||||
},
|
||||
prop_toString: function (prop, sp, count) {
|
||||
if (!prop) return "";
|
||||
var str = [];
|
||||
count = count || 1;
|
||||
for (var item in prop) {
|
||||
switch (item) {
|
||||
case "desc":
|
||||
case "desc1":
|
||||
case "desc2":
|
||||
case "desc3":
|
||||
case "desc4":
|
||||
case "desc5":
|
||||
str.push(prop[item]);
|
||||
break;
|
||||
case "releasetime":
|
||||
case "distime":
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":-" + (prop[item] * count / 1000) + "秒")
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":+" + (-prop[item] * count / 1000) + "秒");
|
||||
break;
|
||||
case "diff_busy":
|
||||
case "busy":
|
||||
case "gjsd":
|
||||
case "diff_downside":
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":+" + (prop[item] * count / 1000) + "秒")
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":" + (prop[item] * count / 1000) + "秒");
|
||||
break;
|
||||
case "expend_mp_per":
|
||||
case "distime_per":
|
||||
case "releasetime_per":
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":-" + (prop[item] * count) + "%")
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":+" + (prop[item] * -count) + "%");
|
||||
break;
|
||||
case "lianxi_per":
|
||||
case "dazuo_per":
|
||||
case "study_per":
|
||||
case "add_sh_per":
|
||||
case "add_bjsh_per":
|
||||
case "busy_per":
|
||||
case "gjsd_per":
|
||||
case "bj_per":
|
||||
case "zj_per":
|
||||
case "ds_per":
|
||||
case "fy_per":
|
||||
case "diff_sh_per":
|
||||
case "diff_sh_per2":
|
||||
case "diff_fy_per":
|
||||
case "diff_fy_per2":
|
||||
case "diff_busy_per":
|
||||
case "mz_per":
|
||||
case "gj_per":
|
||||
case "diff_bj":
|
||||
case "hp_per":
|
||||
case "money_per":
|
||||
case "diff_downside_per":
|
||||
case "recover_per":
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":+" + (prop[item] * count) + "%")
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":" + (prop[item] * count) + "%");
|
||||
break;
|
||||
case "skill":
|
||||
var skills = prop[item];
|
||||
for (var sk in skills) {
|
||||
var sk_base = SKILL.get(sk);
|
||||
if (sk_base)
|
||||
str.push(sk_base.name + ":+" + skills[sk] + "级");
|
||||
}
|
||||
|
||||
break;
|
||||
case "age":
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":-" + prop[item] * count + "岁")
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":+" + (-prop[item]) * count + "岁");
|
||||
break;
|
||||
case "expend_mp":
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":-" + prop[item] * count)
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":+" + (-prop[item]) * count);
|
||||
break;
|
||||
default:
|
||||
let p = PROPERTIES[item];
|
||||
if (p) {
|
||||
prop[item] > 0 ?
|
||||
str.push(PROPERTIES[item] + ":+" + prop[item] * count)
|
||||
:
|
||||
str.push(PROPERTIES[item] + ":" + prop[item] * count);
|
||||
} else {
|
||||
p = SKILL.SLOTS[item];
|
||||
if (p) {
|
||||
str.push(p.format(prop[item] * count));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str.join(sp || "\n");
|
||||
},
|
||||
diff_time: function (next_hour) {
|
||||
//到清理临时temp( 明天5点)的时间
|
||||
next_hour = next_hour || 5;
|
||||
var dt = new Date();
|
||||
var hour = dt.getHours();
|
||||
var day = dt.getDate();
|
||||
if (hour >= next_hour) day = day + 1;
|
||||
dt = new Date(dt.getFullYear(), dt.getMonth(), day, next_hour);
|
||||
return dt - Date.now();
|
||||
},
|
||||
diff_week_time: function (next_hour) {
|
||||
//到清理临时temp( 每周一5点)的时间
|
||||
next_hour = next_hour || 5;
|
||||
var date = new Date();
|
||||
var week = date.getDay();
|
||||
week = week == 0 ? 1 : 8 - week;
|
||||
if (week == 7 && date.getHours() < next_hour) {
|
||||
week = 0;
|
||||
}
|
||||
var next_date = new Date(date.getFullYear(), date.getMonth(), date.getDate() + week, next_hour);
|
||||
|
||||
|
||||
return next_date - Date.now();
|
||||
}, diff_month_time: function (next_hour) {
|
||||
|
||||
//到清理临时temp( 每周一5点)的时间
|
||||
next_hour = next_hour || 5;
|
||||
var date = new Date();
|
||||
|
||||
if (date.getDate() > 1 || date.getHours() >= next_hour) {
|
||||
date = new Date(date.setMonth(date.getMonth() + 1, 1));
|
||||
}
|
||||
|
||||
var next_date = new Date(date.getFullYear(), date.getMonth(), 1, next_hour);
|
||||
// me.send(next_date.getFullYear() + "年" + (date.getMonth() + 1)+ "月" + 1 + "日" + next_hour);
|
||||
|
||||
return next_date - Date.now();
|
||||
},
|
||||
logs: [],
|
||||
log: function (msg) {
|
||||
|
||||
this.logs.push({
|
||||
dt: Date.now,
|
||||
content: msg
|
||||
});
|
||||
},
|
||||
saveLog: function () {
|
||||
if (!this.logs) return;
|
||||
|
||||
var fs = require("fs");
|
||||
var dt = new Date();
|
||||
var path = __PATH.DATA + "log/";
|
||||
if (!fs.existsSync(path)) {
|
||||
fs.mkdirSync(path);
|
||||
}
|
||||
var file = path + (dt.getMonth() + 1) + "-" + dt.getDate() + "-" + dt.getHours() + ".log";
|
||||
fs.writeFileSync(path, JSON.stringify(this.logs));
|
||||
},
|
||||
idstr: "0123456789abcdefghijklmnopqrstuvwxwz",
|
||||
begin: 1490276099978,
|
||||
create_id: function () {
|
||||
var str = [];
|
||||
for (var i = 0; i < 4; i++) {
|
||||
str.push(this.idstr[parseInt(Math.random() * this.idstr.length)]);
|
||||
}
|
||||
str.push(parseInt((Date.now() - this.begin) / 1000).toString(16));
|
||||
return str.join("");
|
||||
},
|
||||
random_name: function (s, t) {
|
||||
t = t || (parseInt(Math.random() * 2) + 1);
|
||||
var str = [];
|
||||
if (t == 2) {
|
||||
var key = parseInt(Math.random() * this.name0.length);
|
||||
if (key % 2 == 1) key -= 1;
|
||||
str.push(this.name0[key++]);
|
||||
str.push(this.name0[key]);
|
||||
} else {
|
||||
str.push(this.name1[parseInt(Math.random() * this.name1.length)]);
|
||||
}
|
||||
if (s == 0) {
|
||||
str.push(this.name2[parseInt(Math.random() * this.name2.length)]);
|
||||
} else {
|
||||
str.push(this.name3[parseInt(Math.random() * this.name3.length)]);
|
||||
}
|
||||
if (parseInt(Math.random() * 4) > 1) {
|
||||
if (s == 0) {
|
||||
str.push(this.name2[parseInt(Math.random() * this.name2.length)]);
|
||||
} else {
|
||||
str.push(this.name3[parseInt(Math.random() * this.name3.length)]);
|
||||
}
|
||||
}
|
||||
return str.join("");
|
||||
},
|
||||
name0: "万俟司马上官欧阳夏侯诸葛闻人东方赫连皇甫尉迟公羊澹台公冶宗政濮阳淳于单于太叔申屠公孙仲孙轩辕令狐锺离宇文长孙慕容鲜于闾丘司徒司空丌官司寇子车颛孙端木巫马公西乐正公良拓拔夹谷谷梁梁丘左丘东门西门",
|
||||
name1: "赵钱孙李周吴郑王冯陈楮卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛奚范彭郎",
|
||||
|
||||
name2: "世舜丞主产仁仇仓仕仞任伋众伸佐佺侃侪促俟信俣修倝倡倧偿储僖僧僳儒俊伟列则刚创前剑助劭势勘参叔吏嗣士壮孺守宽宾宋宗宙宣实宰尊峙峻崇崈川州巡帅庚战才承拯操斋昌晁暠曹曾珺玮珹琒琛琩琮琸瑎玚璟璥瑜生畴矗矢石磊砂碫示社祖祚祥禅稹穆竣竦综缜绪舱舷船蚩襦轼辑轩子杰榜碧葆莱蒲天乐东钢铎铖铠铸铿锋镇键镰馗旭骏骢骥驹驾骄诚诤赐慕端征坚建弓强彦御悍擎攀旷昂晷健冀凯劻啸柴木林森朴骞寒函高魁魏鲛鲲鹰丕乒候冕勰备宪宾密封山峰弼彪彭旁日明昪昴胜汉涵汗浩涛淏清澜浦澉澎澔瀚瀛灏沧虚豪豹辅辈迈邶合部阔雄霆震韩俯颁颇频颔风飒飙飚马亮仑仝代儋利力劼勒卓哲喆展帝弛弢弩彰征律德志忠思振挺掣旲旻昊昮晋晟晸朕朗段殿泰滕炅炜煜煊炎选玄勇君稼黎利贤谊金鑫辉墨欧有友闻问",
|
||||
|
||||
name3: "筠柔竹霭凝晓欢霄枫芸菲寒伊亚宜姬舒影荔枝思丽秀娟英华慧巧美娜静淑惠珠翠雅芝玉萍红娥玲芬芳燕彩春菊勤珍贞莉兰凤洁梅琳素云莲真环雪荣妹霞香月莺媛艳瑞凡佳嘉琼桂娣叶璧璐娅琦晶妍茜秋珊莎锦黛青倩婷姣婉娴瑾颖露瑶怡婵雁蓓纨仪荷丹蓉眉君琴蕊薇菁梦岚苑婕馨瑗琰韵融园艺咏卿聪澜纯毓悦昭冰爽琬茗羽希宁欣飘育滢馥",
|
||||
|
||||
getLunar: function (date) {
|
||||
date = date || new Date();
|
||||
//农历函数开始
|
||||
var lunarInfo = new Array(0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, //1990
|
||||
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, 0x14b63);
|
||||
function lYearDays(y) {
|
||||
var i, sum = 348;
|
||||
for (i = 0x8000; i > 0x8; i >>= 1) sum += (lunarInfo[y - 1900] & i) ? 1 : 0;
|
||||
return (sum + leapDays(y));
|
||||
}
|
||||
function leapDays(y) {
|
||||
if (leapMonth(y)) return ((lunarInfo[y - 1900] & 0x10000) ? 30 : 29);
|
||||
else return (0);
|
||||
}
|
||||
function leapMonth(y) {
|
||||
return (lunarInfo[y - 1900] & 0xf);
|
||||
}
|
||||
function monthDays(y, m) {
|
||||
return ((lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29);
|
||||
}
|
||||
function Lunar(y, m, d) {
|
||||
var i, leap = 0,
|
||||
temp = 0;
|
||||
var offset = (Date.UTC(y, m, d) - Date.UTC(1900, 0, 31)) / 86400000;
|
||||
for (i = 1900; i < 2050 && offset > 0; i++) {
|
||||
temp = lYearDays(i);
|
||||
offset -= temp;
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp;
|
||||
i--;
|
||||
}
|
||||
this.year = i;
|
||||
leap = leapMonth(i);
|
||||
this.isLeap = false;
|
||||
for (i = 1; i < 13 && offset > 0; i++) {
|
||||
if (leap > 0 && i == (leap + 1) && this.isLeap == false) {
|
||||
--i;
|
||||
this.isLeap = true;
|
||||
temp = leapDays(this.year);
|
||||
} else {
|
||||
temp = monthDays(this.year, i);
|
||||
}
|
||||
if (this.isLeap == true && i == (leap + 1)) this.isLeap = false;
|
||||
offset -= temp;
|
||||
}
|
||||
if (offset == 0 && leap > 0 && i == leap + 1) if (this.isLeap) {
|
||||
this.isLeap = false;
|
||||
} else {
|
||||
this.isLeap = true; --i;
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp; --i;
|
||||
}
|
||||
this.month = i;
|
||||
this.day = offset + 1;
|
||||
}
|
||||
|
||||
return new Lunar(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
},
|
||||
isLunar15: function (dt) {
|
||||
let issuc = WORLD.DATA.query_temp('lunar15', 0);
|
||||
if (issuc === 0) {
|
||||
let now = dt || new Date();
|
||||
let hour = now.getHours();
|
||||
var lunar = UTIL.getLunar(now);
|
||||
if ((lunar.day === 14 && hour >= 5) || lunar.day === 15
|
||||
|| (lunar.day === 16 && hour < 5)) {
|
||||
|
||||
WORLD.DATA.set_temp('lunar15', 1, UTIL.diff_time());
|
||||
issuc = 1;
|
||||
} else {
|
||||
WORLD.DATA.set_temp('lunar15', -1, UTIL.diff_time());
|
||||
issuc = -1;
|
||||
}
|
||||
}
|
||||
return issuc > 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
341
os/world.js
Normal file
341
os/world.js
Normal file
@@ -0,0 +1,341 @@
|
||||
|
||||
require("./util/util");
|
||||
const db = require("./util/data");
|
||||
WORLD = {
|
||||
USERS: [],
|
||||
COMMANDS: {},
|
||||
SKILLS: {},
|
||||
ROOMS: {},
|
||||
RUN_ROOMS: [],
|
||||
DEFAULT_SKILLS: {},
|
||||
AREAS: [],
|
||||
TASKS: [],
|
||||
SYSTEMTASKS: [],
|
||||
USER_EVENTS: [],
|
||||
OBJ_STROE: new Map(),
|
||||
NPC_STROE: new Map(),
|
||||
HEARTBEATCOUNT: 0,
|
||||
RECEIVED: [],
|
||||
LOGS: [],
|
||||
SERVERID: 0,
|
||||
SERVERS: [],
|
||||
CONNECT_COUNT: 0,
|
||||
DATA: require('./data'),
|
||||
USERLOGIN: require('./login'),
|
||||
DB: db,
|
||||
SocketCount: 0,
|
||||
LISTENER: require("./ws"),
|
||||
max_connect_count: 1100,
|
||||
max_user_count: 5100,
|
||||
MESSAGE: {
|
||||
stores: new Map(),
|
||||
NOTICES: [],
|
||||
},
|
||||
STATS: {
|
||||
TOPS: [],
|
||||
EXP: [],
|
||||
SCORE: [],
|
||||
WEAPON: [],
|
||||
},
|
||||
status: -1,//-1关闭 0正常 >1 用户等级>连接
|
||||
SocketIn: function () {
|
||||
this.SocketCount++;
|
||||
},
|
||||
connect: function (socket) {
|
||||
if (WORLD.status < 0)
|
||||
return socket.end();
|
||||
if (!WORLD.check_connect(socket))
|
||||
return socket.end();
|
||||
|
||||
socket.user = new USER();
|
||||
|
||||
socket.user.socket = socket;
|
||||
socket.user.wait_input = this.USERLOGIN.check_session.bind(this.USERLOGIN);
|
||||
|
||||
socket.setTimeout(60000);
|
||||
},
|
||||
check_connect: function (socket) {
|
||||
return true;
|
||||
},
|
||||
before_login: function (user) {
|
||||
if (this.status < 0) return false;
|
||||
if (this.status === 0) return true;
|
||||
return this.status <= user.user_level;
|
||||
},
|
||||
disconnect: function (socket) {
|
||||
if (socket.user) {
|
||||
socket.user.socket = null;
|
||||
socket.user.disconnect();
|
||||
}
|
||||
this.SocketCount--;
|
||||
if (socket.oserver) {
|
||||
socket.oserver.disconnect();
|
||||
socket.oserver = null;
|
||||
}
|
||||
}, request: function (request, socket) {
|
||||
if (!request) return;
|
||||
var user = socket.user;
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
if (user.request_count > 20) {
|
||||
return user.send("不要急,慢慢来。");
|
||||
}
|
||||
user.request_count = user.request_count + 1;
|
||||
var time = Date.now();
|
||||
try {
|
||||
user.command(request);
|
||||
} catch (e) {
|
||||
console.log(user.name, "命令错误:", request, e.message, e.stack);
|
||||
WORLD.log(user, request, e.message + e.stack);
|
||||
}
|
||||
WORLD.RECEIVED.push({
|
||||
time: time,
|
||||
cmd: request + " " + (Date.now() - time).toString(),
|
||||
user: user.id
|
||||
});
|
||||
if (WORLD.RECEIVED.length > 1000) {
|
||||
WORLD.saveRequest();
|
||||
}
|
||||
}, saveRequest: function () {
|
||||
db.saveRequest(WORLD.RECEIVED);
|
||||
WORLD.RECEIVED.length = 0;
|
||||
},
|
||||
startup: async function (sid) {
|
||||
if (sid) {
|
||||
sid = parseInt(sid);
|
||||
this.SERVERS = await db.getServers();
|
||||
this.SERVER = this.getServer(sid);
|
||||
} else {
|
||||
this.SERVER = __CONFIG.def_server;
|
||||
}
|
||||
|
||||
if (!this.SERVER) throw "服务器设置错误,无法启动";
|
||||
this.SERVERID = this.SERVER.id;
|
||||
|
||||
await db.initDataDir();
|
||||
loadResource();
|
||||
await this.DATA.load();
|
||||
await this.LISTENER.start(this.SERVER.port);
|
||||
console.log("服务", this.SERVER.name, "(" + this.SERVERID + ")启动");
|
||||
console.log("ws://" + this.SERVER.ip + ":" + this.SERVER.port);
|
||||
this.heart_beat_service = setInterval(WORLD.heart_beat, __CONFIG.HEARTBEAT);
|
||||
|
||||
this.status = __CONFIG.CONNECT_LEVEL ?? 0;
|
||||
this.on_startup();
|
||||
if (this.status > 0)
|
||||
console.log('当前允许级别' + this.status + "账号登陆");
|
||||
},
|
||||
|
||||
|
||||
sendAll: function (msg) {
|
||||
for (var i = 0; i < WORLD.USERS.length; i++) {
|
||||
WORLD.USERS[i].send(msg);
|
||||
}
|
||||
},
|
||||
getUser: function (id) {
|
||||
if (!id) return;
|
||||
for (var i = 0; i < WORLD.USERS.length; i++) {
|
||||
if (WORLD.USERS[i].id == id) return WORLD.USERS[i];
|
||||
}
|
||||
|
||||
}, find_user: function (name) {
|
||||
if (!name) return;
|
||||
for (var i = 0; i < WORLD.USERS.length; i++) {
|
||||
if (WORLD.USERS[i].name == name) return WORLD.USERS[i];
|
||||
}
|
||||
},
|
||||
on_user_login: function (user) {
|
||||
|
||||
},
|
||||
on_user_cross_login: function (user) {
|
||||
|
||||
},
|
||||
on_startup: function () {
|
||||
|
||||
},
|
||||
on_user_quit: function (user) {
|
||||
|
||||
},
|
||||
on_user_relogin: function (user) {
|
||||
|
||||
}
|
||||
,
|
||||
on_heart_beat: function (user) {
|
||||
|
||||
},
|
||||
heart_beat: function () {
|
||||
var avtived_obj = null;
|
||||
try {
|
||||
const dt = Date.now();
|
||||
WORLD.CONNECT_COUNT = 0;
|
||||
for (let i = 0; i < WORLD.USERS.length; i++) {
|
||||
avtived_obj = WORLD.USERS[i];
|
||||
if (avtived_obj.socket) WORLD.CONNECT_COUNT++;
|
||||
avtived_obj.heart_beat(dt);
|
||||
}
|
||||
WORLD.on_heart_beat(dt);
|
||||
for (let i = 0; i < WORLD.RUN_ROOMS.length; i++) {
|
||||
avtived_obj = WORLD.RUN_ROOMS[i];
|
||||
avtived_obj.heart_beat(dt);
|
||||
}
|
||||
WORLD.HEARTBEATCOUNT++;
|
||||
if (WORLD.HEARTBEATCOUNT > 720) {
|
||||
WORLD.HEARTBEATCOUNT = 0;
|
||||
WORLD.save();
|
||||
console.log("数据已备份%d", Date.now() - dt);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(avtived_obj ? (avtived_obj.path ?? avtived_obj.name) : "", "心跳错误:", e, e.stack);
|
||||
WORLD.log(null, e.message, e.stack);
|
||||
}
|
||||
|
||||
},
|
||||
login_out: function (user) {
|
||||
this.on_user_quit(user);
|
||||
if (user.serverid === WORLD.SERVERID) {
|
||||
user.save();
|
||||
}
|
||||
WORLD.USERS.remove(user);
|
||||
|
||||
if (user.socket) {
|
||||
try {
|
||||
user.socket.end();
|
||||
user.socket.destroy();
|
||||
} catch (e) {
|
||||
console.log(e.message, e.stack);
|
||||
}
|
||||
}
|
||||
}, send: function (text) {
|
||||
for (var i = 0; i < this.USERS.length; i++) {
|
||||
this.USERS[i].send(text);
|
||||
}
|
||||
}, log: function (user, cmd, msg) {
|
||||
WORLD.LOGS.push({
|
||||
time: Date.now(),
|
||||
cmd: cmd,
|
||||
user: user ? user.name : "",
|
||||
msg: msg
|
||||
});
|
||||
if (WORLD.LOGS.length > 500) {
|
||||
db.saveLogs(WORLD.LOGS);
|
||||
WORLD.LOGS.length = 0;
|
||||
}
|
||||
}, saveLog: function () {
|
||||
db.saveLogs(WORLD.LOGS);
|
||||
WORLD.LOGS.length = 0;
|
||||
}
|
||||
,
|
||||
is_server: function (user) {
|
||||
return user.serverid == WORLD.SERVERID;
|
||||
},
|
||||
save: async function () {
|
||||
|
||||
var roles = [];
|
||||
for (var i = 0; i < WORLD.USERS.length; i++) {
|
||||
if (WORLD.USERS[i].serverid != WORLD.SERVERID) continue;
|
||||
roles.push(WORLD.USERS[i].getData());
|
||||
}
|
||||
try {
|
||||
console.time('saved');
|
||||
await db.saveRoles(roles);
|
||||
console.log('玩家数据已保存');
|
||||
await this.DATA.save();
|
||||
console.log('全局数据已经保存');
|
||||
await this.saveLog();
|
||||
await this.saveRequest();
|
||||
console.log('日志数据已经保存');
|
||||
console.timeEnd('saved');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('玩家数据保存失败', error.message);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
writeHeapSnapshot: function () {
|
||||
let v8 = UTIL.require('v8');
|
||||
let dt = new Date();
|
||||
let fname = __PATH.DATA + "/" + dt.getFullYear() + "_" + dt.getMonth() + "_"
|
||||
+ dt.getDate() + "_" + dt.getHours() + "_" + dt.getMinutes() + ".heapsnapshot";
|
||||
v8.writeHeapSnapshot(fname);
|
||||
console.log('快照保存到', fname);
|
||||
}
|
||||
,
|
||||
loadLocalData: function () {
|
||||
let data = db.getLocalRoles();
|
||||
if (!data || !data.length) return;
|
||||
console.log("加载上次未保存的本地用户%d", data.length);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let user = new USER();
|
||||
user.loadData(data[i]);
|
||||
this.USERS.push(user);
|
||||
}
|
||||
db.deleteLocalRoles();
|
||||
},
|
||||
on_cross_response: function (id, sid) {
|
||||
//允许跨服
|
||||
},
|
||||
can_cross: function (id) {
|
||||
//允许跨服
|
||||
}, on_user_die: function (me, killer, corpse) {
|
||||
|
||||
}, on_resource_loaded: function () {
|
||||
|
||||
}
|
||||
};
|
||||
function loadResource() {
|
||||
let fs = require("fs");
|
||||
function readdir(basePath, path) {
|
||||
path = path || basePath;
|
||||
let files = fs.readdirSync(path);
|
||||
let count = 0;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
let sub_path = path + files[i];
|
||||
let stat = fs.statSync(sub_path);
|
||||
if (stat.isDirectory()) {
|
||||
count += readdir(basePath, sub_path + "/");
|
||||
} else {
|
||||
let fname = sub_path.replace(basePath, "").replace(".js", "");
|
||||
BASE.CREATE(basePath, fname);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
try {
|
||||
let sum = 0;
|
||||
let count = readdir(__PATH.EXTENDS);
|
||||
console.log("%s %d ", __PATH.EXTENDS, count);
|
||||
sum += count;
|
||||
count = readdir(__PATH.COMMAND);
|
||||
console.log("%s%d ", __PATH.COMMAND, count);
|
||||
sum += count;
|
||||
count = readdir(__PATH.FAMILY);
|
||||
console.log("%s %d ", __PATH.FAMILY, count);
|
||||
sum += count;
|
||||
|
||||
|
||||
count = readdir(__PATH.OBJ);
|
||||
console.log("%s %d ", __PATH.OBJ, count);
|
||||
sum += count;
|
||||
|
||||
count = readdir(__PATH.AREA);
|
||||
console.log("%s %d ", __PATH.AREA, count);
|
||||
sum += count;
|
||||
|
||||
count = readdir(__PATH.SKILL);
|
||||
console.log("%s %d ", __PATH.SKILL, count);
|
||||
sum += count;
|
||||
|
||||
count = readdir(__PATH.MAP);
|
||||
console.log("%s %d ", __PATH.MAP, count);
|
||||
sum += count;
|
||||
count = readdir(__PATH.TASK);
|
||||
console.log("%s %d ", __PATH.TASK, count);
|
||||
sum += count;
|
||||
console.log('资源脚本加载%d', sum);
|
||||
WORLD.on_resource_loaded();
|
||||
} catch (e) {
|
||||
console.log("error: ", e, e.stack);
|
||||
}
|
||||
}
|
||||
49
os/ws.js
Normal file
49
os/ws.js
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
const ws = require("./net-ws");
|
||||
const server = new ws({
|
||||
SSL: false,
|
||||
KEY: "",
|
||||
CERT: "",
|
||||
PASSWORD: ""
|
||||
});
|
||||
server.start = async function (port) {
|
||||
return new Promise((resolve) => {
|
||||
this.listen(port, resolve);
|
||||
});
|
||||
}
|
||||
// WORLD.LISTENER = server;
|
||||
server.onConnect = function (socket) {
|
||||
WORLD.connect(socket);
|
||||
}
|
||||
server.onSocketIn = function (socket) {
|
||||
|
||||
WORLD.SocketIn(socket);
|
||||
|
||||
}
|
||||
server.onReceive = function (msg, socket) {
|
||||
WORLD.request(msg, socket);
|
||||
}
|
||||
server.onClose = function (msg, socket) {
|
||||
console.log("server closed");
|
||||
}
|
||||
server.onClientClose = function (socket, e) {
|
||||
|
||||
WORLD.disconnect(socket);
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
}
|
||||
server.onClientTimeout = function (socket, e) {
|
||||
if (socket && (!socket.user || !socket.user.id)) {
|
||||
socket.end();
|
||||
}
|
||||
}
|
||||
server.onClientError = function (socket, e) {
|
||||
if (socket && socket.user) {
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = server;
|
||||
Reference in New Issue
Block a user