summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/map/clif.cpp10
-rw-r--r--src/map/npc-parse.cpp5
-rw-r--r--src/map/npc.cpp34
-rw-r--r--src/map/pc.cpp189
-rw-r--r--src/map/pc.hpp2
-rw-r--r--src/map/script-call.cpp2
-rw-r--r--src/map/script-fun.cpp21
-rw-r--r--src/mmo/clif.t.hpp2
-rw-r--r--src/mmo/enums.hpp1
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)