From b7ec6e535d314a64aeaf426e2e4c068cd7c4bb34 Mon Sep 17 00:00:00 2001 From: gumi Date: Mon, 1 Jan 2018 16:09:22 -0500 Subject: release v18.1.1 --- CHANGELOG | 3 +++ deps/attoconf | 2 +- src/char/int_party.cpp | 47 +++++++++++++++++++++++++++++++++++++++ src/map/atcommand.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++------- src/map/intif.cpp | 50 +++++++++++++++++++++++++++++++++++++++++ src/map/intif.hpp | 1 + src/map/map.hpp | 2 ++ src/map/npc-parse.cpp | 8 +++++++ src/map/npc.cpp | 8 +++++-- src/map/script-call.cpp | 9 ++++++++ src/map/script-fun.cpp | 5 ++++- tools/protocol.py | 28 +++++++++++++++++++++++ 12 files changed, 210 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index adcc69d..af0cf28 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +v18.1.1 + - increase party limit to 120 + - add a command to change party leader v17.11.12 - fix a bug that did not decrease the npc counter on npc despawn (REDUX) v16.11.28 diff --git a/deps/attoconf b/deps/attoconf index d33fcf6..7b939e7 160000 --- a/deps/attoconf +++ b/deps/attoconf @@ -1 +1 @@ -Subproject commit d33fcf6cc7380633329fdaf2e7f7543bbdd2490e +Subproject commit 7b939e7e4ce36e8b62b10025e567f871731cbf4d diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp index 5ee65ad..9fdd9bb 100644 --- a/src/char/int_party.cpp +++ b/src/char/int_party.cpp @@ -416,6 +416,20 @@ void mapif_party_optionchanged(Session *s, PartyPair p, AccountId account_id, account_id, p->exp, p->item, flag); } +static +void mapif_party_leaderchanged(Session *s, PartyPair p, AccountId account_id, + int leader) +{ + Packet_Fixed<0x3828> fixed_28; + fixed_28.party_id = p.party_id; + fixed_28.account_id = account_id; + fixed_28.leader = leader; + for (Session *ss : iter_map_sessions()) + { + send_fpacket<0x3828, 11>(ss, fixed_28); + } +} + // パーティ脱退通知 static void mapif_party_leaved(PartyId party_id, AccountId account_id, CharName name) @@ -603,6 +617,23 @@ void mapif_parse_PartyChangeOption(Session *s, PartyId party_id, AccountId accou mapif_party_optionchanged(s, p, account_id, flag); } +static +void mapif_parse_PartyChangeLeader(Session *s, PartyId party_id, AccountId account_id, + int leader) +{ + PartyPair p{party_id, TRY_UNWRAP(party_db.search(party_id), return)}; + + for (int i = 0; i < MAX_PARTY; i++) + { + if (p->member[i].account_id != account_id) + continue; + + mapif_party_leaderchanged(s, p, account_id, leader); + p->member[i].leader = leader; + return; + } +} + // パーティ脱退要求 void mapif_parse_PartyLeave(Session *, PartyId party_id, AccountId account_id) { @@ -777,6 +808,22 @@ RecvResult inter_party_parse_frommap(Session *ms, uint16_t packet_id) lv); break; } + case 0x3026: + { + Packet_Fixed<0x3026> fixed; + rv = recv_fpacket<0x3026, 11>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + PartyId party_id = fixed.party_id; + AccountId account_id = fixed.account_id; + uint8_t leader = fixed.leader; + mapif_parse_PartyChangeLeader(ms, + party_id, + account_id, + leader); + break; + } case 0x3027: { Packet_Head<0x3027> head; diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index ad3529d..2e11227 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -902,8 +902,8 @@ ATCE atcommand_whogroup(Session *s, dumb_ptr sd, AString output; if (pl_gm_level) output = STRPRINTF( - "Name: %s (GM:%d) | Party: '%s'"_fmt, - pl_sd->status_key.name, pl_gm_level, temp0); + "Name: %s (GM:%d) | Party: '%s' (%i)"_fmt, + pl_sd->status_key.name, pl_gm_level, temp0, pl_sd->status.party_id); clif_displaymessage(s, output); count++; } @@ -1019,11 +1019,11 @@ ATCE atcommand_whomapgroup(Session *s, dumb_ptr sd, PartyName temp0 = p_.pmd_pget(&PartyMost::name).copy_or(stringish("None"_s)); AString output; if (pl_gm_level) - output = STRPRINTF("Name: %s (GM:%d) | Party: '%s'"_fmt, - pl_sd->status_key.name, pl_gm_level, temp0); + output = STRPRINTF("Name: %s (GM:%d) | Party: '%s' (%i)"_fmt, + pl_sd->status_key.name, pl_gm_level, temp0, pl_sd->status.party_id); else - output = STRPRINTF("Name: %s | Party: '%s'"_fmt, - pl_sd->status_key.name, temp0); + output = STRPRINTF("Name: %s | Party: '%s' (%i)"_fmt, + pl_sd->status_key.name, temp0, pl_sd->status.party_id); clif_displaymessage(s, output); count++; } @@ -1092,8 +1092,8 @@ ATCE atcommand_whogm(Session *s, dumb_ptr sd, Option p_ = party_search(pl_sd->status.party_id); PartyName temp0 = p_.pmd_pget(&PartyMost::name).copy_or(stringish("None"_s)); output = STRPRINTF( - " Party: '%s'"_fmt, - temp0); + " Party: '%s' (%i)"_fmt, + temp0, pl_sd->status.party_id); clif_displaymessage(s, output); count++; } @@ -3708,6 +3708,46 @@ ATCE atcommand_partyspy(Session *s, dumb_ptr sd, return ATCE::OKAY; } +static +ATCE atcommand_setpartyleader(Session *s, dumb_ptr sd, + ZString message) +{ + CharName character; + PartyName party_name; + int value = 0; + + if (!asplit(message, &party_name, &value, &character)) + return ATCE::USAGE; + + + // name first to avoid error when name begin with a number + Option p_ = party_searchname(party_name); + dumb_ptr pl_sd = map_nick2sd(character); + + // try with party id + if (p_.is_none()) + p_ = party_search(wrap(static_cast(atoi(party_name.c_str())))); + + if (p_.is_none() || pl_sd == nullptr) + return ATCE::EXIST; + + OMATCH_BEGIN (p_) + { + OMATCH_CASE_SOME (p) + { + intif_party_changeleader(p.party_id, pl_sd->status_key.account_id, value < 1 ? 0 : 1); + clif_displaymessage(s, "Party leader changed."_s); + } + OMATCH_CASE_NONE () + { + clif_displaymessage(s, "Incorrect party name, or no one from the party is online."_s); + return ATCE::EXIST; + } + } + OMATCH_END (); + return ATCE::OKAY; +} + static ATCE atcommand_enablenpc(Session *s, dumb_ptr, ZString message) @@ -5295,6 +5335,9 @@ Map atcommand_info = {"party"_s, {""_s, 99, atcommand_party, "Create a new party"_s}}, + {"setpartyleader"_s, {" "_s, + 40, atcommand_setpartyleader, + "Change the leader of a party"_s}}, {"mapexit"_s, {""_s, 99, atcommand_mapexit, "Try to kill the server kindly"_s}}, diff --git a/src/map/intif.cpp b/src/map/intif.cpp index d08b94f..fc34a64 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -234,6 +234,18 @@ void intif_party_changeoption(PartyId party_id, AccountId account_id, int exp, i send_fpacket<0x3023, 14>(char_session, fixed_23); } +void intif_party_changeleader(PartyId party_id, AccountId account_id, int leader) +{ + if (!char_session) + return; + + Packet_Fixed<0x3026> fixed_26; + fixed_26.party_id = party_id; + fixed_26.account_id = account_id; + fixed_26.leader = leader; + send_fpacket<0x3026, 11>(char_session, fixed_26); +} + // パーティ脱退要求 void intif_party_leave(PartyId party_id, AccountId account_id) { @@ -488,6 +500,34 @@ void intif_parse_PartyOptionChanged(Session *, const Packet_Fixed<0x3823>& fixed fixed.item, fixed.flag); } +static +void intif_parse_PartyLeaderChanged(Session *, const Packet_Fixed<0x3828>& fixed) +{ + int i; + PartyPair p = TRY_UNWRAP(party_search(fixed.party_id), return); + + for (i = 0; i < MAX_PARTY; i++) + { + PartyMember *m = &p->member[i]; + + if (m->account_id == fixed.account_id) + { + dumb_ptr sd = map_id2sd(wrap(unwrap(fixed.account_id))); + m->leader = (fixed.leader > 0 ? 1 : 0); + + if (sd != nullptr) + { + AString msg = STRPRINTF("You are %s a leader of %s."_fmt, + fixed.leader > 0 ? "now"_s : "no longer"_s, p->name); + clif_displaymessage(sd->sess, msg); + } + break; + } + } + + clif_party_info(p, nullptr); +} + // パーティ脱退通知 static void intif_parse_PartyMemberLeaved(Session *, const Packet_Fixed<0x3824>& fixed) @@ -693,6 +733,16 @@ RecvResult intif_parse(Session *s, uint16_t packet_id) intif_parse_PartyMessage(s, head, repeat); break; } + case 0x3828: + { + Packet_Fixed<0x3828> fixed; + rv = recv_fpacket<0x3828, 11>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + intif_parse_PartyLeaderChanged(s, fixed); + break; + } default: return RecvResult::Error; } diff --git a/src/map/intif.hpp b/src/map/intif.hpp index ac68040..a9d66fa 100644 --- a/src/map/intif.hpp +++ b/src/map/intif.hpp @@ -45,6 +45,7 @@ void intif_request_partyinfo(PartyId party_id); void intif_party_addmember(PartyId party_id, AccountId account_id); void intif_party_changeoption(PartyId party_id, AccountId account_id, int exp, int item); +void intif_party_changeleader(PartyId party_id, AccountId account_id, int leader); void intif_party_leave(PartyId party_id, AccountId accound_id); void intif_party_changemap(dumb_ptr sd, int online); void intif_party_message(PartyId party_id, AccountId account_id, XString mes); diff --git a/src/map/map.hpp b/src/map/map.hpp index 897787e..44c5bfb 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -340,6 +340,8 @@ struct npc_data : block_list Opt0 option; short flag; + bool deletion_pending; + std::list eventqueuel; Array eventtimer; short arenaflag; diff --git a/src/map/npc-parse.cpp b/src/map/npc-parse.cpp index 99e6267..47b851c 100644 --- a/src/map/npc-parse.cpp +++ b/src/map/npc-parse.cpp @@ -164,6 +164,8 @@ bool npc_load_warp(ast::npc::Warp& warp) nd->warp.xs = xs; nd->warp.ys = ys; + nd->deletion_pending = false; + npc_warp++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::WARP; @@ -226,6 +228,8 @@ bool npc_load_shop(ast::npc::Shop& shop) nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; + nd->deletion_pending = false; + npc_shop++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::SHOP; @@ -454,6 +458,8 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; + nd->deletion_pending = false; + npc_script++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::SCRIPT; @@ -562,6 +568,8 @@ bool npc_load_script_map(ast::script::ScriptBody& body, ast::npc::ScriptMap& scr nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; + nd->deletion_pending = false; + npc_script++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::SCRIPT; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 32a5a54..a7cbf5d 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -358,7 +358,7 @@ void npc_eventtimer(TimerData *, tick_t, BlockId id, NpcEvent data) data); return; }); - if ((nd = ev->nd) == nullptr) + if ((nd = ev->nd) == nullptr || nd->deletion_pending == true) { if (battle_config.error_log) PRINTF("npc_event: event not found [%s]\n"_fmt, @@ -611,7 +611,7 @@ int npc_event(dumb_ptr sd, NpcEvent eventname, ev.pos = ev2->pos; } - if ((nd = ev.nd) == nullptr) + if ((nd = ev.nd) == nullptr || nd->deletion_pending == true) { if (!mob_kill && battle_config.error_log) PRINTF("npc_event: event not found [%s]\n"_fmt, @@ -1078,6 +1078,10 @@ void npc_propagate_update(dumb_ptr nd) void npc_free(dumb_ptr nd) { + if (nd == nullptr || nd->deletion_pending == true) + return; + + nd->deletion_pending = true; clif_clearchar(nd, BeingRemoveWhy::GONE); npc_propagate_update(nd); map_deliddb(nd); diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp index d54e234..7c7d4e6 100644 --- a/src/map/script-call.cpp +++ b/src/map/script-call.cpp @@ -383,6 +383,9 @@ void pop_stack(struct script_stack *stack, int start, int end) static ByteCode get_com(ScriptPointer *script) { + if (script == nullptr) + return ByteCode::NOP; + if (static_cast(script->peek()) >= 0x80) { // synthetic! Does not advance pos yet. @@ -742,10 +745,16 @@ void run_func(ScriptState *st) static void run_script_main(ScriptState *st, Borrowed rootscript) { + if (st == nullptr) + return; + int cmdcount = script_config.check_cmdcount; int gotocount = script_config.check_gotocount; struct script_stack *stack = st->stack; + if (stack == nullptr) + return; + st->defsp = stack->stack_datav.size(); int rerun_pos = st->scriptp.pos; diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 2036782..8aa8b5c 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -1130,8 +1130,9 @@ void builtin_destroy(ScriptState *st) return; nd = nd->is_script(); - //assert(nd->disposable == true); we don't care about it anymore npc_free(nd); + st->oid = BlockId(); + if (!HARG(0)) st->state = ScriptEndState::END; } @@ -1196,6 +1197,8 @@ void builtin_puppet(ScriptState *st) nd->npc_subtype = NpcSubtype::SCRIPT; npc_script++; + nd->deletion_pending = false; + nd->n = map_addnpc(nd->bl_m, nd); map_addblock(nd); diff --git a/tools/protocol.py b/tools/protocol.py index 1a87263..0c64e6f 100755 --- a/tools/protocol.py +++ b/tools/protocol.py @@ -5830,6 +5830,20 @@ def build_context(): 3. logged out ''', ) + char_map.r(0x3026, 'party change leader', + fixed=[ + at(0, u16, 'packet id'), + at(2, party_id, 'party id'), + at(6, account_id, 'account id'), + at(10, u8, 'leader'), + ], + fixed_size=11, + pre=[], + post=[0x3828], + desc=''' + Explicitly request a change of party leader. + ''', + ) char_map.r(0x3027, 'party message remote begin', head=[ at(0, u16, 'packet id'), @@ -6108,6 +6122,20 @@ def build_context(): Actually send a party message to other map servers. ''', ) + char_map.s(0x3828, 'party change leader notify', + fixed=[ + at(0, u16, 'packet id'), + at(2, party_id, 'party id'), + at(6, account_id, 'account id'), + at(10, u8, 'leader'), + ], + fixed_size=11, + pre=[0x3026], + post=[], + desc=''' + Party leader was changed. + ''', + ) # TOC_MISC # any client -- cgit v1.2.3-60-g2f50