diff options
-rw-r--r-- | src/map/clif.cpp | 10 | ||||
-rw-r--r-- | src/map/npc-parse.cpp | 5 | ||||
-rw-r--r-- | src/map/npc.cpp | 34 | ||||
-rw-r--r-- | src/map/pc.cpp | 189 | ||||
-rw-r--r-- | src/map/pc.hpp | 2 | ||||
-rw-r--r-- | src/map/script-call.cpp | 2 | ||||
-rw-r--r-- | src/map/script-fun.cpp | 21 | ||||
-rw-r--r-- | src/mmo/clif.t.hpp | 2 | ||||
-rw-r--r-- | src/mmo/enums.hpp | 1 |
9 files changed, 202 insertions, 64 deletions
diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 31ecaf8..81ae02f 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -913,7 +913,15 @@ void clif_npc0078(dumb_ptr<npc_data> nd, Buffer& buf) fixed_78.pos.x = nd->bl_x; fixed_78.pos.y = nd->bl_y; fixed_78.pos.dir = nd->dir; - fixed_78.sex = nd->sex; + + // ManaPlus uses a different sex enum for npcs... + if (nd->sex == SEX::FEMALE) + fixed_78.sex = SEX::UNSPECIFIED; + else if (nd->sex == SEX::MALE) + fixed_78.sex = SEX::NEUTRAL; + else if (nd->sex == SEX::NEUTRAL) + fixed_78.sex = SEX::__OTHER; + buf = create_fpacket<0x0078, 54>(fixed_78); } diff --git a/src/map/npc-parse.cpp b/src/map/npc-parse.cpp index 164d793..99e6267 100644 --- a/src/map/npc-parse.cpp +++ b/src/map/npc-parse.cpp @@ -142,6 +142,7 @@ bool npc_load_warp(ast::npc::Warp& warp) nd->bl_id = npc_get_new_npc_id(); nd->n = map_addnpc(m, nd); + nd->sex = SEX::UNSPECIFIED; nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = m; nd->bl_x = x; @@ -208,6 +209,7 @@ bool npc_load_shop(ast::npc::Shop& shop) } } + nd->sex = SEX::UNSPECIFIED; nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = m; nd->bl_x = x; @@ -435,6 +437,7 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s nd->name = script_none.name.data; + nd->sex = SEX::UNSPECIFIED; nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = borrow(undefined_gat); nd->bl_x = 0; @@ -542,7 +545,7 @@ bool npc_load_script_map(ast::script::ScriptBody& body, ast::npc::ScriptMap& scr } nd->name = script_map.name.data; - + nd->sex = SEX::UNSPECIFIED; nd->bl_prev = nd->bl_next = nullptr; nd->bl_m = m; nd->bl_x = x; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 47bf820..3eb13b3 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -366,6 +366,12 @@ void npc_eventtimer(TimerData *, tick_t, BlockId id, NpcEvent data) return; } + if (nd->scr.parent && map_id2bl(nd->scr.parent) == nullptr) + { + npc_free(nd); + return; + } + if (nd->scr.event_needs_map) { int xs = nd->scr.xs; @@ -436,6 +442,12 @@ void npc_timerevent(TimerData *, tick_t tick, BlockId id, interval_t data) assert (nd->npc_subtype == NpcSubtype::SCRIPT); assert (nd->scr.next_event != nd->scr.timer_eventv.end()); + if (nd->scr.parent && map_id2bl(nd->scr.parent) == nullptr) + { + npc_free(nd); + return; + } + nd->scr.timertick = tick; const auto te = nd->scr.next_event; // nd->scr.timerid = nullptr; @@ -606,6 +618,13 @@ int npc_event(dumb_ptr<map_session_data> sd, NpcEvent eventname, eventname); return 0; } + + if (nd->scr.parent && map_id2bl(nd->scr.parent) == nullptr) + { + npc_free(nd); + return 0; + } + if (sd) { if (nd->scr.event_needs_map) @@ -774,7 +793,13 @@ int npc_click(dumb_ptr<map_session_data> sd, BlockId id) npc_event_dequeue(sd); break; case NpcSubtype::SCRIPT: - sd->npc_pos = run_script(ScriptPointer(script_or_parent(nd->is_script()), 0), sd->bl_id, id); + dumb_ptr<npc_data_script> nds = nd->is_script(); + if (nds->scr.parent && map_id2bl(nds->scr.parent) == nullptr) + { + npc_free(nds); + return 1; + } + sd->npc_pos = run_script(ScriptPointer(script_or_parent(nds), 0), sd->bl_id, id); break; } @@ -808,6 +833,13 @@ int npc_scriptcont(dumb_ptr<map_session_data> sd, BlockId id) return 0; } + if (nd->is_script()->scr.parent && + map_id2bl(nd->is_script()->scr.parent) == nullptr) + { + npc_free(nd); + return 0; + } + sd->npc_pos = run_script(ScriptPointer(script_or_parent(nd->is_script()), sd->npc_pos), sd->bl_id, id); return 0; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index d65297b..63b1497 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -3535,6 +3535,16 @@ int pc_readparam(dumb_ptr<block_list> bl, SP type) case SP::ELTTYPE: val = static_cast<int>(battle_get_element(bl).element); break; + case SP::INVISIBLE: + if (sd) + val = bool(sd->status.option & Opt0::INVISIBILITY); + if (nd) + val = bool(nd->flag & 1); + break; + case SP::HIDDEN: + if (sd) + val = bool(sd->status.option & Opt0::HIDE); + break; } return val; @@ -3544,17 +3554,33 @@ int pc_readparam(dumb_ptr<block_list> bl, SP type) * script用PCステータス設定 *------------------------------------------ */ -int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) +int pc_setparam(dumb_ptr<block_list> bl, SP type, int val) { - int i = 0, up_level = 50; + nullpo_retz(bl); + dumb_ptr<map_session_data> sd; + dumb_ptr<npc_data> nd; + dumb_ptr<mob_data> md; - nullpo_retz(sd); + if (bl->bl_type == BL::PC) + sd = bl->is_player(); + else if (bl->bl_type == BL::MOB) + md = bl->is_mob(); + else if (bl->bl_type == BL::NPC) + nd = bl->is_npc(); + else + return 0; + + int i = 0; switch (type) { case SP::BASELEVEL: + nullpo_retz(sd); + // TODO: mob mutation if (val > sd->status.base_level) { + if (val > MAX_LEVEL) + val = MAX_LEVEL; for (i = 1; i <= (val - sd->status.base_level); i++) sd->status.status_point += (sd->status.base_level + i + 14) / 4; @@ -3569,46 +3595,56 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) pc_heal(sd, sd->status.max_hp, sd->status.max_sp); break; case SP::JOBLEVEL: - up_level -= 40; - if (val >= sd->status.job_level) + nullpo_retz(sd); + if (val > sd->status.job_level) { - if (val > up_level) - val = up_level; + if (val > MAX_LEVEL) + val = MAX_LEVEL; sd->status.skill_point += (val - sd->status.job_level); - sd->status.job_level = val; - sd->status.job_exp = 0; - clif_updatestatus(sd, SP::JOBLEVEL); - clif_updatestatus(sd, SP::NEXTJOBEXP); - clif_updatestatus(sd, SP::JOBEXP); clif_updatestatus(sd, SP::SKILLPOINT); - pc_calcstatus(sd, 0); clif_misceffect(sd, 1); } - else - { - sd->status.job_level = val; - sd->status.job_exp = 0; - clif_updatestatus(sd, SP::JOBLEVEL); - clif_updatestatus(sd, SP::NEXTJOBEXP); - clif_updatestatus(sd, SP::JOBEXP); - pc_calcstatus(sd, 0); - } - clif_updatestatus(sd, type); + sd->status.job_level = val; + sd->status.job_exp = 0; + clif_updatestatus(sd, SP::JOBLEVEL); + clif_updatestatus(sd, SP::NEXTJOBEXP); + clif_updatestatus(sd, SP::JOBEXP); + pc_calcstatus(sd, 0); break; case SP::CLASS: - sd->status.species = wrap<Species>(val); - clif_changelook(sd, LOOK::BASE, val); + // TODO: mob class change + if (sd) + { + sd->status.species = wrap<Species>(val); + clif_changelook(sd, LOOK::BASE, val); + } + else if (nd) + { + if (unwrap<Species>(nd->npc_class) != val) + { + nd->npc_class = wrap<Species>(val); + npc_enable(nd->name, 0); + npc_enable(nd->name, 1); + } + } return 0; case SP::SKILLPOINT: + nullpo_retz(sd); sd->status.skill_point = val; + clif_updatestatus(sd, type); break; case SP::STATUSPOINT: + nullpo_retz(sd); sd->status.status_point = val; + clif_updatestatus(sd, type); break; case SP::ZENY: + nullpo_retz(sd); sd->status.zeny = val; + clif_updatestatus(sd, type); break; case SP::BASEEXP: + nullpo_retz(sd); if (pc_nextbaseexp(sd) > 0) { sd->status.base_exp = val; @@ -3616,8 +3652,10 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) sd->status.base_exp = 0; pc_checkbaselevelup(sd); } + clif_updatestatus(sd, type); break; case SP::JOBEXP: + nullpo_retz(sd); if (pc_nextjobexp(sd) > 0) { sd->status.job_exp = val; @@ -3625,48 +3663,69 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) sd->status.job_exp = 0; pc_checkjoblevelup(sd); } + clif_updatestatus(sd, type); break; case SP::SEX: - switch (val) - { - case 0: - sd->sex = sd->status.sex = SEX::FEMALE; - break; - case 1: - sd->sex = sd->status.sex = SEX::MALE; - break; - default: - sd->sex = sd->status.sex = SEX::NEUTRAL; - break; - } - for (IOff0 j : IOff0::iter()) { - if (sd->status.inventory[j].nameid - && bool(sd->status.inventory[j].equip) - && !pc_isequip(sd, j)) - pc_unequipitem(sd, j, CalcStatus::LATER); + SEX sex = SEX::NEUTRAL; + if (val == 0) + sex = SEX::FEMALE; + if (val == 1) + sex = SEX::MALE; + + if (nd) + { + nd->sex = sex; + npc_enable(nd->name, 0); + npc_enable(nd->name, 1); + } + else if (sd) + { + sd->sex = sd->status.sex = sex; + for (IOff0 j : IOff0::iter()) + { + if (sd->status.inventory[j].nameid + && bool(sd->status.inventory[j].equip) + && !pc_isequip(sd, j)) + pc_unequipitem(sd, j, CalcStatus::LATER); + } + pc_calcstatus(sd, 0); + chrif_save(sd); + clif_fixpcpos(sd); + } } - pc_calcstatus(sd, 0); - chrif_save(sd); - clif_fixpcpos(sd); break; case SP::WEIGHT: + nullpo_retz(sd); sd->weight = val; + clif_updatestatus(sd, type); break; case SP::MAXWEIGHT: + nullpo_retz(sd); sd->max_weight = val; + clif_updatestatus(sd, type); break; case SP::HP: + nullpo_retz(sd); + // TODO: mob mutation sd->status.hp = val; + clif_updatestatus(sd, type); break; case SP::MAXHP: + nullpo_retz(sd); + // TODO: mob mutation sd->status.max_hp = val; + clif_updatestatus(sd, type); break; case SP::SP: + nullpo_retz(sd); sd->status.sp = val; + clif_updatestatus(sd, type); break; case SP::MAXSP: + nullpo_retz(sd); sd->status.max_sp = val; + clif_updatestatus(sd, type); break; case SP::STR: case SP::AGI: @@ -3674,25 +3733,43 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) case SP::INT: case SP::DEX: case SP::LUK: + nullpo_retz(sd); + // TODO: mob mutation pc_statusup2(sd, type, (val - sd->status.attrs[sp_to_attr(type)])); break; case SP::PARTNER: - dumb_ptr<block_list> p_bl; - if (val < 2000000 && val >= 150000) + if (sd) { - dumb_ptr<map_session_data> p_sd = nullptr; - if ((p_sd = map_nick2sd(map_charid2nick(wrap<CharId>(val)))) != nullptr) - p_bl = map_id2bl(p_sd->bl_id); + dumb_ptr<block_list> p_bl; + if (val < 2000000 && val >= 150000) + { + dumb_ptr<map_session_data> p_sd = nullptr; + if ((p_sd = map_nick2sd(map_charid2nick(wrap<CharId>(val)))) != nullptr) + p_bl = map_id2bl(p_sd->bl_id); + } + else + p_bl = map_id2bl(wrap<BlockId>(val)); + if (val < 1) + pc_divorce(sd); + else + p_bl ? pc_marriage(sd, p_bl->is_player()) : 0; } + break; + case SP::INVISIBLE: + if (sd) + pc_invisibility(sd, (val > 0) ? 1 : 0); + else if (nd) + npc_enable(nd->name, (val > 0) ? false : true); + break; + case SP::HIDDEN: + nullpo_retz(sd); + if (val == 1) + sd->status.option |= Opt0::HIDE; else - p_bl = map_id2bl(wrap<BlockId>(val)); - if (val < 1) - pc_divorce(sd); - else - p_bl ? pc_marriage(sd, p_bl->is_player()) : 0; + sd->status.option &= ~Opt0::HIDE; + clif_changeoption(sd); break; } - clif_updatestatus(sd, type); return 0; } diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 0f04698..2e63c26 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -143,7 +143,7 @@ int pc_itemheal(dumb_ptr<map_session_data> sd, int hp, int sp); int pc_changelook(dumb_ptr<map_session_data>, LOOK, int); int pc_readparam(dumb_ptr<block_list>, SP); -int pc_setparam(dumb_ptr<map_session_data>, SP, int); +int pc_setparam(dumb_ptr<block_list>, SP, int); int pc_readreg(dumb_ptr<block_list>, SIR); void pc_setreg(dumb_ptr<block_list>, SIR, int); ZString pc_readregstr(dumb_ptr<block_list> sd, SIR reg); diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp index 085d90a..2e90432 100644 --- a/src/map/script-call.cpp +++ b/src/map/script-call.cpp @@ -219,7 +219,7 @@ void set_reg(dumb_ptr<block_list> sd, VariableCode type, SIR reg, struct script_ if (type == VariableCode::PARAM) { int val = vd.get_if<ScriptDataInt>()->numi; - pc_setparam(sd->is_player(), reg.sp(), val); + pc_setparam(sd, reg.sp(), val); return; } assert (type == VariableCode::VARIABLE); diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index beabef3..b73a8fc 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -90,6 +90,8 @@ static void builtin_mes(ScriptState *st) { dumb_ptr<map_session_data> sd = script_rid2sd(st); + if (sd == nullptr) + return; sd->state.npc_dialog_mes = 1; RString mes = HARG(0) ? conv_str(st, &AARG(0)) : ""_s; clif_scriptmes(sd, st->oid, mes); @@ -327,6 +329,8 @@ void builtin_close(ScriptState *st) } st->state = ScriptEndState::END; dumb_ptr<map_session_data> sd = script_rid2sd(st); + if (sd == nullptr) + return; if (sd->state.npc_dialog_mes) clif_scriptclose(sd, st->oid); else @@ -338,6 +342,8 @@ void builtin_close2(ScriptState *st) { st->state = ScriptEndState::STOP; dumb_ptr<map_session_data> sd = script_rid2sd(st); + if (sd == nullptr) + return; if (sd->state.npc_dialog_mes) clif_scriptclose(sd, st->oid); else @@ -1121,6 +1127,13 @@ void builtin_puppet(ScriptState *st) { int x, y; + NpcName npc = stringish<NpcName>(ZString(conv_str(st, &AARG(3)))); + if (npc_name2id(npc) != nullptr) + { + push_int<ScriptDataInt>(st->stack, 0); + return; + } + dumb_ptr<block_list> bl = map_id2bl(st->oid); dumb_ptr<npc_data_script> parent_nd = bl->is_npc()->is_script(); dumb_ptr<npc_data_script> nd; @@ -1137,8 +1150,8 @@ void builtin_puppet(ScriptState *st) nd->scr.event_needs_map = false; // PlayerName::SpellName - NpcName npc = stringish<NpcName>(ZString(conv_str(st, &AARG(3)))); nd->name = npc; + nd->sex = SEX::UNSPECIFIED; // Dynamically set location nd->bl_m = m; @@ -3813,7 +3826,10 @@ void builtin_get(ScriptState *st) } if (bl == nullptr) + { + push_int<ScriptDataInt>(st->stack, -1); return; + } int var = pc_readparam(bl, reg.sp()); push_int<ScriptDataInt>(st->stack, var); return; @@ -3869,9 +3885,8 @@ void builtin_get(ScriptState *st) if (!bl) { - PRINTF("builtin_get: no block list attached %s!\n"_fmt, conv_str(st, &AARG(1))); if (postfix == '$') - push_str<ScriptDataStr>(st->stack, conv_str(st, &AARG(1))); + push_str<ScriptDataStr>(st->stack, ""_s); else push_int<ScriptDataInt>(st->stack, 0); return; diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp index c1b222f..c23842e 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -474,6 +474,8 @@ enum class SP : uint16_t BL_ID = 1077, BL_TYPE = 1078, CHAR_ID = 1079, + INVISIBLE = 1080, + HIDDEN = 1081, }; constexpr diff --git a/src/mmo/enums.hpp b/src/mmo/enums.hpp index 9a8f8ea..2564ec9 100644 --- a/src/mmo/enums.hpp +++ b/src/mmo/enums.hpp @@ -115,6 +115,7 @@ enum class SEX : uint8_t // TODO switch to Option<SEX> where appropriate. UNSPECIFIED = 2, NEUTRAL = 3, + __OTHER = 4, // used in ManaPlus only }; inline char sex_to_char(SEX sex) |