diff options
Diffstat (limited to 'src/map/pc.cpp')
-rw-r--r-- | src/map/pc.cpp | 978 |
1 files changed, 334 insertions, 644 deletions
diff --git a/src/map/pc.cpp b/src/map/pc.cpp index ada5b9f..6fa35b0 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -37,36 +37,42 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" -#include "../net/timer.hpp" +#include "../mmo/cxxstdio_enums.hpp" -#include "../mmo/utils.hpp" +#include "../net/timer.hpp" +#include "../net/timestamp-utils.hpp" #include "../proto2/char-map.hpp" #include "atcommand.hpp" #include "battle.hpp" +#include "battle_conf.hpp" #include "chrif.hpp" #include "clif.hpp" +#include "globals.hpp" #include "intif.hpp" #include "itemdb.hpp" #include "magic-stmt.hpp" #include "map.hpp" +#include "map_conf.hpp" #include "npc.hpp" #include "party.hpp" #include "path.hpp" -#include "script.hpp" +#include "script-call.hpp" #include "skill.hpp" #include "storage.hpp" #include "trade.hpp" +#include "quest.hpp" #include "../poison.hpp" namespace tmwa { +namespace map +{ // PVP順位計算の間隔 constexpr std::chrono::milliseconds PVP_CALCRANK_INTERVAL = 1_s; @@ -120,7 +126,7 @@ int sp_coefficient_0 = 100; // coefficients for each weapon type // (not all used) static //const -earray<interval_t, ItemLook, ItemLook::SINGLE_HANDED_COUNT> aspd_base_0 //= +earray<interval_t, ItemLook, ItemLook::COUNT> aspd_base_0 //= {{ 650_ms, 700_ms, @@ -254,10 +260,6 @@ earray<EPOS, EQUIP, EQUIP::COUNT> equip_pos //= EPOS::ARROW, }}; -// TODO use DMap<> -static -std::map<AccountId, GmLevel> gm_accountm; - static int pc_checkoverhp(dumb_ptr<map_session_data> sd); static @@ -287,16 +289,12 @@ int pc_iskiller(dumb_ptr<map_session_data> src, { nullpo_retz(src); - if (src->bl_type != BL::PC) + if (src->bl_type != BL::PC || target->bl_type != BL::PC) return 0; - if (src->special_state.killer) + if ((src->state.pvpchannel == 1) && (target->state.pvpchannel == 1) && !src->bl_m->flag.get(MapFlag::NOPVP)) return 1; - - if (target->bl_type != BL::PC) - return 0; - if (target->special_state.killable) + if ((src->state.pvpchannel > 1) && (target->state.pvpchannel == src->state.pvpchannel)) // this one does not respect NOPVP return 1; - return 0; } @@ -319,6 +317,33 @@ int distance(int x0, int y0, int x1, int y1) } static +void pc_pvp_timer(TimerData *, tick_t, BlockId id) +{ + dumb_ptr<map_session_data> sd = map_id2sd(id); + + assert (sd != nullptr); + assert (sd->bl_type == BL::PC); +} + +int pc_setpvptimer(dumb_ptr<map_session_data> sd, interval_t val) +{ + nullpo_retz(sd); + + sd->pvp_timer = Timer(gettick() + val, + std::bind(pc_pvp_timer, ph::_1, ph::_2, + sd->bl_id)); + return 0; +} + +int pc_delpvptimer(dumb_ptr<map_session_data> sd) +{ + nullpo_retz(sd); + + sd->pvp_timer.cancel(); + return 0; +} + +static void pc_invincible_timer(TimerData *, tick_t, BlockId id) { dumb_ptr<map_session_data> sd = map_id2sd(id); @@ -377,7 +402,6 @@ int pc_setrestartvalue(dumb_ptr<map_session_data> sd, int type) clif_updatestatus(sd, SP::SP); sd->heal_xp = 0; // [Fate] Set gainable xp for healing this player to 0 - return 0; } @@ -464,7 +488,7 @@ void pc_makesavestatus(dumb_ptr<map_session_data> sd) // セーブ禁止マップだったので指定位置に移動 if (sd->bl_m->flag.get(MapFlag::NOSAVE)) { - map_local *m = sd->bl_m; + P<map_local> m = sd->bl_m; if (m->save.map_ == "SavePoint"_s) sd->status.last_point = sd->status.save_point; else @@ -505,12 +529,7 @@ EPOS pc_equippoint(dumb_ptr<map_session_data> sd, IOff0 n) { nullpo_retr(EPOS::ZERO, sd); - if (!sd->inventory_data[n]) - return EPOS::ZERO; - - EPOS ep = sd->inventory_data[n]->equip; - - return ep; + return sd->inventory_data[n].pmd_pget(&item_data::equip).copy_or(EPOS::ZERO); } static @@ -521,7 +540,11 @@ int pc_setinventorydata(dumb_ptr<map_session_data> sd) for (IOff0 i : IOff0::iter()) { ItemNameId id = sd->status.inventory[i].nameid; - sd->inventory_data[i] = itemdb_search(id); + // If you think you understand this line, you're wrong. + // It does not do what you think it does. Rather, you need to + // understand it in the context in which it is used. Despite this, + // it is quite common for elements to be None. + sd->inventory_data[i] = Some(itemdb_search(id)); } return 0; } @@ -531,40 +554,8 @@ int pc_calcweapontype(dumb_ptr<map_session_data> sd) { nullpo_retz(sd); - if (sd->weapontype1 != ItemLook::NONE - && sd->weapontype2 == ItemLook::NONE) - sd->status.weapon = sd->weapontype1; - if (sd->weapontype1 == ItemLook::NONE - && sd->weapontype2 != ItemLook::NONE) - sd->status.weapon = sd->weapontype2; - else if (sd->weapontype1 == ItemLook::BLADE - && sd->weapontype2 == ItemLook::BLADE) - sd->status.weapon = ItemLook::DUAL_BLADE; - else if (sd->weapontype1 == ItemLook::_2 - && sd->weapontype2 == ItemLook::_2) - sd->status.weapon = ItemLook::DUAL_2; - else if (sd->weapontype1 == ItemLook::_6 - && sd->weapontype2 == ItemLook::_6) - sd->status.weapon = ItemLook::DUAL_6; - else if ((sd->weapontype1 == ItemLook::BLADE - && sd->weapontype2 == ItemLook::_2) - || (sd->weapontype1 == ItemLook::_2 - && sd->weapontype2 == ItemLook::BLADE)) - sd->status.weapon = ItemLook::DUAL_12; - else if ( - (sd->weapontype1 == ItemLook::BLADE - && sd->weapontype2 == ItemLook::_6) - || (sd->weapontype1 == ItemLook::_6 - && sd->weapontype2 == ItemLook::BLADE)) - sd->status.weapon = ItemLook::DUAL_16; - else if ( - (sd->weapontype1 == ItemLook::_2 - && sd->weapontype2 == ItemLook::_6) - || (sd->weapontype1 == ItemLook::_6 - && sd->weapontype2 == ItemLook::_2)) - sd->status.weapon = ItemLook::DUAL_26; - else - sd->status.weapon = sd->weapontype1; + // TODO now that there is no calculation here, store only once + sd->status.weapon = sd->weapontype1; return 0; } @@ -588,27 +579,30 @@ int pc_setequipindex(dumb_ptr<map_session_data> sd) sd->equip_index_maybe[j] = i; if (bool(sd->status.inventory[i].equip & EPOS::WEAPON)) { - if (sd->inventory_data[i]) - sd->weapontype1 = sd->inventory_data[i]->look; - else - sd->weapontype1 = ItemLook::NONE; + OMATCH_BEGIN (sd->inventory_data[i]) + { + OMATCH_CASE_SOME (sdidi) + { + sd->weapontype1 = sdidi->look; + } + OMATCH_CASE_NONE () + { + sd->weapontype1 = ItemLook::NONE; + } + } + OMATCH_END (); } if (bool(sd->status.inventory[i].equip & EPOS::SHIELD)) { - if (sd->inventory_data[i]) + OMATCH_BEGIN_SOME (sdidi, sd->inventory_data[i]) { - if (sd->inventory_data[i]->type == ItemType::WEAPON) + if (sdidi->type == ItemType::WEAPON) { if (sd->status.inventory[i].equip == EPOS::SHIELD) - sd->weapontype2 = sd->inventory_data[i]->look; - else - sd->weapontype2 = ItemLook::NONE; + assert(0 && "unreachable - offhand weapons are not supported"); } - else - sd->weapontype2 = ItemLook::NONE; } - else - sd->weapontype2 = ItemLook::NONE; + OMATCH_END (); } } } @@ -620,21 +614,18 @@ int pc_setequipindex(dumb_ptr<map_session_data> sd) static int pc_isequip(dumb_ptr<map_session_data> sd, IOff0 n) { - struct item_data *item; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; //転生や養子の場合の元の職業を算出する nullpo_retz(sd); - item = sd->inventory_data[n]; sc_data = battle_get_sc_data(sd); - GmLevel gm_all_equipment = GmLevel::from(static_cast<uint32_t>(battle_config.gm_all_equipment)); + GmLevel gm_all_equipment = battle_config.gm_all_equipment; if (gm_all_equipment && pc_isGM(sd).satisfies(gm_all_equipment)) return 1; - if (item == nullptr) - return 0; + P<struct item_data> item = TRY_UNWRAP(sd->inventory_data[n], return 0); if (item->sex != SEX::NEUTRAL && sd->status.sex != item->sex) return 0; if (item->elv > 0 && sd->status.base_level < item->elv) @@ -648,12 +639,11 @@ int pc_isequip(dumb_ptr<map_session_data> sd, IOff0 n) * char鯖から送られてきたステータスを設定 *------------------------------------------ */ -int pc_authok(AccountId id, int login_id2, TimeT connect_until_time, +int pc_authok(AccountId id, int login_id2, short tmw_version, const CharKey *st_key, const CharData *st_data) { dumb_ptr<map_session_data> sd = nullptr; - PartyPair p; tick_t tick = gettick(); sd = map_id2sd(account_to_block(id)); @@ -681,7 +671,7 @@ int pc_authok(AccountId id, int login_id2, TimeT connect_until_time, sd->state.connect_new = 1; sd->bl_prev = sd->bl_next = nullptr; - sd->weapontype1 = sd->weapontype2 = ItemLook::NONE; + sd->weapontype1 = ItemLook::NONE; sd->speed = DEFAULT_WALK_SPEED; sd->state.dead_sit = 0; sd->dir = DIR::S; @@ -727,21 +717,6 @@ int pc_authok(AccountId id, int login_id2, TimeT connect_until_time, // sd->sc_data[i].timer = nullptr; sd->sc_data[i].val1 = 0; } - sd->sc_count = 0; - { - Option old_option = sd->status.option; - sd->status.option = Option::ZERO; - - // This would leak information. - // It's better to make it obvious that players can see you. - if (false && bool(old_option & Option::INVISIBILITY)) - is_atcommand(sd->sess, sd, "@invisible"_s, GmLevel()); - - if (bool(old_option & Option::HIDE)) - is_atcommand(sd->sess, sd, "@hide"_s, GmLevel()); - // atcommand_hide might already send it, but also might not - clif_changeoption(sd); - } // パーティー関係の初期化 sd->party_sended = 0; @@ -757,9 +732,24 @@ int pc_authok(AccountId id, int login_id2, TimeT connect_until_time, pc_setpos(sd, sd->status.last_point.map_, sd->status.last_point.x, sd->status.last_point.y, BeingRemoveWhy::GONE); + { + Opt0 old_option = sd->status.option; + sd->status.option = Opt0::ZERO; + + // This would leak information. + // It's better to make it obvious that players can see you. + if (false && bool(old_option & Opt0::INVISIBILITY)) + is_atcommand(sd->sess, sd, "@invisible"_s, GmLevel()); + + if (bool(old_option & Opt0::HIDE)) + is_atcommand(sd->sess, sd, "@hide"_s, GmLevel()); + // atcommand_hide might already send it, but also might not + clif_changeoption(sd); + } + // パーティ、ギルドデータの要求 if (sd->status.party_id - && !(p = party_search(sd->status.party_id))) + && party_search(sd->status.party_id).is_none()) party_request_info(sd->status.party_id); // pvpの設定 @@ -793,27 +783,21 @@ int pc_authok(AccountId id, int login_id2, TimeT connect_until_time, sd->auto_ban_info.in_progress = 0; // Initialize antispam vars - sd->chat_reset_due = TimeT(); + sd->chat_reset_due = tick_t(); sd->chat_lines_in = sd->chat_total_repeats = 0; - sd->chat_repeat_reset_due = TimeT(); + sd->chat_repeat_reset_due = tick_t(); sd->chat_lastmsg = RString(); for (tick_t& t : sd->flood_rates) t = tick_t(); - sd->packet_flood_reset_due = TimeT(); + sd->packet_flood_reset_due = tick_t(); sd->packet_flood_in = 0; - // message of the limited time of the account - if (connect_until_time) - { - timestamp_seconds_buffer buffer; - stamp_time(buffer, &connect_until_time); - AString tmpstr = STRPRINTF("Your account time limit is: %s"_fmt, buffer); - - clif_wis_message(sd->sess, wisp_server_name, tmpstr); - } pc_calcstatus(sd, 1); + npc_event_doall_l(stringish<ScriptLabel>("OnPCLoginEvent"_s), sd->bl_id, nullptr); + // Init Quest Log + clif_sendallquest(sd); return 0; } @@ -830,7 +814,7 @@ void pc_show_motd(dumb_ptr<map_session_data> sd) clif_displaymessage(sd->sess, "This server is Free Software, for details type @source in chat or use the tmwa-source tool"_s); sd->state.seen_motd = true; - io::ReadFile in(motd_txt); + io::ReadFile in(map_conf.motd_txt); if (in.is_open()) { AString buf; @@ -865,7 +849,8 @@ int pc_calc_skillpoint(dumb_ptr<map_session_data> sd) nullpo_retz(sd); - for (i = 0; i < skill_pool_skills_size; i++) { + for (i = 0; i < skill_pool_skills.size(); i++) + { int lv = sd->status.skill[skill_pool_skills[i]].lv; if (lv) skill_points += ((lv * (lv - 1)) >> 1) - 1; @@ -940,6 +925,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) int bl; int aspd_rate, refinedef = 0; int str, dstr, dex; + int b_pvpchannel = 0; nullpo_retz(sd); @@ -968,6 +954,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) b_mdef = sd->mdef; b_mdef2 = sd->mdef2; b_base_atk = sd->base_atk; + if (!pc_isdead(sd) && sd->state.pvpchannel == 1) + b_pvpchannel = sd->state.pvpchannel; sd->max_weight = max_weight_base_0 + sd->status.attrs[ATTR::STR] * 300; @@ -976,11 +964,11 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->weight = 0; for (IOff0 i : IOff0::iter()) { - if (!sd->status.inventory[i].nameid - || sd->inventory_data[i] == nullptr) + if (!sd->status.inventory[i].nameid) continue; + P<struct item_data> sdidi = TRY_UNWRAP(sd->inventory_data[i], continue); sd->weight += - sd->inventory_data[i]->weight * + sdidi->weight * sd->status.inventory[i].amount; } // used to fill cart @@ -1005,7 +993,6 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->status.max_hp = 0; sd->status.max_sp = 0; sd->attackrange = 0; - sd->attackrange_ = 0; sd->matk1 = 0; sd->matk2 = 0; sd->speed = DEFAULT_WALK_SPEED; @@ -1016,13 +1003,9 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->arrow_atk = 0; sd->arrow_hit = 0; sd->arrow_range = 0; - sd->nhealhp = sd->nhealsp = sd->nshealhp = sd->nshealsp = sd->nsshealhp = - sd->nsshealsp = 0; + sd->nhealhp = sd->nhealsp = 0; really_memzero_this(&sd->special_state); - sd->watk_ = 0; //二刀流用(仮) - sd->watk_2 = 0; - sd->aspd_rate = 100; sd->speed_rate = 100; sd->hprecov_rate = 100; @@ -1038,8 +1021,6 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->double_add_rate = sd->perfect_hit_add = 0; sd->hp_drain_rate = sd->hp_drain_per = sd->sp_drain_rate = sd->sp_drain_per = 0; - sd->hp_drain_rate_ = sd->hp_drain_per_ = sd->sp_drain_rate_ = - sd->sp_drain_per_ = 0; sd->spellpower_bonus_target = 0; @@ -1057,13 +1038,14 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) || sd->equip_index_maybe[EQUIP::LEGS] == index)) continue; - if (sd->inventory_data[index]) + OMATCH_BEGIN_SOME (sdidi, sd->inventory_data[index]) { sd->spellpower_bonus_target += - sd->inventory_data[index]->magic_bonus; + sdidi->magic_bonus; // used to apply cards } + OMATCH_END (); } #ifdef USE_ASTRAL_SOUL_SKILL @@ -1092,31 +1074,15 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) && (sd->equip_index_maybe[EQUIP::TORSO] == index || sd->equip_index_maybe[EQUIP::LEGS] == index)) continue; - if (sd->inventory_data[index]) + OMATCH_BEGIN_SOME (sdidi, sd->inventory_data[index]) { - sd->def += sd->inventory_data[index]->def; - if (sd->inventory_data[index]->type == ItemType::WEAPON) + sd->def += sdidi->def; + if (sdidi->type == ItemType::WEAPON) { if (i == EQUIP::SHIELD && sd->status.inventory[index].equip == EPOS::SHIELD) { - //二刀流用データ入力 - sd->watk_ += sd->inventory_data[index]->atk; - sd->watk_2 = 0; - - sd->attackrange_ += sd->inventory_data[index]->range; - sd->state.lr_flag = 1; - { - argrec_t arg[2] = - { - {"@slotId"_s, static_cast<int>(i)}, - {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, - }; - run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, BlockId(), - arg); - } - sd->state.lr_flag = 0; + assert(0 && "unreachable - offhand weapons are not supported"); } else { @@ -1124,66 +1090,62 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) argrec_t arg[2] = { {"@slotId"_s, static_cast<int>(i)}, - {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, + {"@itemId"_s, unwrap<ItemNameId>(sdidi->nameid)}, }; - sd->watk += sd->inventory_data[index]->atk; + sd->watk += sdidi->atk; - sd->attackrange += sd->inventory_data[index]->range; - run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), + sd->attackrange += sdidi->range; + run_script_l(ScriptPointer(borrow(*sdidi->equip_script), 0), sd->bl_id, BlockId(), arg); } } - else if (sd->inventory_data[index]->type == ItemType::ARMOR) + else if (sdidi->type == ItemType::ARMOR) { argrec_t arg[2] = { {"@slotId"_s, static_cast<int>(i)}, - {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, + {"@itemId"_s, unwrap<ItemNameId>(sdidi->nameid)}, }; - sd->watk += sd->inventory_data[index]->atk; - run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), + sd->watk += sdidi->atk; + run_script_l(ScriptPointer(borrow(*sdidi->equip_script), 0), sd->bl_id, BlockId(), arg); } } + OMATCH_END (); } if (battle_is_unarmed(sd)) { sd->watk += skill_power(sd, SkillID::TMW_BRAWLING) / 3; // +66 for 200 sd->watk2 += skill_power(sd, SkillID::TMW_BRAWLING) >> 3; // +25 for 200 - sd->watk_ += skill_power(sd, SkillID::TMW_BRAWLING) / 3; // +66 for 200 - sd->watk_2 += skill_power(sd, SkillID::TMW_BRAWLING) >> 3; // +25 for 200 } IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW]; if (aidx.ok()) { IOff0 index = aidx; - if (sd->inventory_data[index]) + OMATCH_BEGIN_SOME (sdidi, sd->inventory_data[index]) { //まだ属性が入っていない argrec_t arg[2] = { {"@slotId"_s, static_cast<int>(EQUIP::ARROW)}, - {"@itemId"_s, unwrap<ItemNameId>(sd->inventory_data[index]->nameid)}, + {"@itemId"_s, unwrap<ItemNameId>(sdidi->nameid)}, }; - sd->state.lr_flag = 2; - run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), + sd->state.lr_flag_is_arrow_2 = 1; + run_script_l(ScriptPointer(borrow(*sdidi->equip_script), 0), sd->bl_id, BlockId(), arg); - sd->state.lr_flag = 0; - sd->arrow_atk += sd->inventory_data[index]->atk; + sd->state.lr_flag_is_arrow_2 = 0; + sd->arrow_atk += sdidi->atk; } + OMATCH_END (); } sd->def += (refinedef + 50) / 100; if (sd->attackrange < 1) sd->attackrange = 1; - if (sd->attackrange_ < 1) - sd->attackrange_ = 1; - if (sd->attackrange < sd->attackrange_) - sd->attackrange = sd->attackrange_; if (sd->status.weapon == ItemLook::BOW) sd->attackrange += sd->arrow_range; sd->double_rate += sd->double_add_rate; @@ -1201,9 +1163,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) for (ATTR attr : ATTRs) sd->paramc[attr] = std::max(0, sd->status.attrs[attr] + sd->paramb[attr] + sd->parame[attr]); - if (sd->status.weapon == ItemLook::BOW - || sd->status.weapon == ItemLook::_13 - || sd->status.weapon == ItemLook::_14) + if (sd->status.weapon == ItemLook::BOW) { str = sd->paramc[ATTR::DEX]; dex = sd->paramc[ATTR::STR]; @@ -1291,20 +1251,11 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->mdef2 = 1; // 二刀流 ASPD 修正 - if (sd->status.weapon < ItemLook::SINGLE_HANDED_COUNT) + { sd->aspd += aspd_base_0[sd->status.weapon] - (sd->paramc[ATTR::AGI] * 4 + sd->paramc[ATTR::DEX]) * aspd_base_0[sd->status.weapon] / 1000; - else - sd->aspd += ( - (aspd_base_0[sd->weapontype1] - - (sd->paramc[ATTR::AGI] * 4 + sd->paramc[ATTR::DEX]) - * aspd_base_0[sd->weapontype1] / 1000) - + (aspd_base_0[sd->weapontype2] - - (sd->paramc[ATTR::AGI] * 4 + sd->paramc[ATTR::DEX]) - * aspd_base_0[sd->weapontype2] / 1000) - ) - * 140 / 200; + } aspd_rate = sd->aspd_rate; @@ -1366,7 +1317,6 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) } // スキルやステータス異常による残りのパラメータ補正 - if (sd->sc_count) { // ATK/DEF変化形 if (sd->sc_data[StatusChange::SC_POISON].timer) // 毒状態 @@ -1401,7 +1351,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) if (sd->attack_spell_override) sd->aspd = sd->attack_spell_delay; - sd->aspd = std::max(sd->aspd, static_cast<interval_t>(battle_config.max_aspd)); + sd->aspd = std::max(sd->aspd, battle_config.max_aspd); sd->amotion = sd->aspd; sd->dmotion = std::chrono::milliseconds(800 - sd->paramc[ATTR::AGI] * 4); sd->dmotion = std::max(sd->dmotion, 400_ms); @@ -1478,6 +1428,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) clif_updatestatus(sd, SP::HP); if (b_sp != sd->status.sp) clif_updatestatus(sd, SP::SP); + if (b_pvpchannel != sd->state.pvpchannel) + sd->state.pvpchannel = b_pvpchannel; return 0; } @@ -1498,122 +1450,116 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val) case SP::INT: case SP::DEX: case SP::LUK: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->parame[sp_to_attr(type)] += val; break; #if 0 case SP::ATK1: - if (!sd->state.lr_flag) + if (!sd->state.lr_flag_is_arrow_2) sd->watk += val; - else if (sd->state.lr_flag == 1) - sd->watk_ += val; break; #endif #if 0 case SP::ATK2: - if (!sd->state.lr_flag) + if (!sd->state.lr_flag_is_arrow_2) sd->watk2 += val; - else if (sd->state.lr_flag == 1) - sd->watk_2 += val; break; #endif #if 0 case SP::BASE_ATK: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->base_atk += val; break; #endif #if 0 case SP::MATK1: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->matk1 += val; break; #endif #if 0 case SP::MATK2: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->matk2 += val; break; #endif #if 0 case SP::DEF1: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->def += val; break; #endif case SP::MDEF1: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->mdef += val; break; #if 0 case SP::MDEF2: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->mdef += val; break; #endif case SP::HIT: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->hit += val; else sd->arrow_hit += val; break; case SP::FLEE1: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->flee += val; break; #if 0 case SP::FLEE2: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->flee2 += val * 10; break; #endif case SP::CRITICAL: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->critical += val * 10; else sd->arrow_cri += val * 10; break; case SP::MAXHP: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->status.max_hp += val; break; case SP::MAXSP: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->status.max_sp += val; break; case SP::MAXHPRATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->hprate += val; break; #if 0 case SP::MAXSPRATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->sprate += val; break; #endif #if 0 case SP::SPRATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->dsprate += val; break; #endif case SP::ATTACKRANGE: - if (!sd->state.lr_flag) + if (!sd->state.lr_flag_is_arrow_2) sd->attackrange += val; - else if (sd->state.lr_flag == 1) - sd->attackrange_ += val; - else if (sd->state.lr_flag == 2) + else sd->arrow_range += val; break; #if 0 case SP::ADD_SPEED: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->speed -= val; break; #endif #if 0 case SP::SPEED_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) { if (sd->speed_rate > 100 - val) sd->speed_rate = 100 - val; @@ -1621,17 +1567,17 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val) break; #endif case SP::SPEED_ADDRATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->speed_add_rate = sd->speed_add_rate * (100 - val) / 100; break; #if 0 case SP::ASPD: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->aspd -= val * 10; break; #endif case SP::ASPD_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) { if (sd->aspd_rate > 100 - val) sd->aspd_rate = 100 - val; @@ -1639,99 +1585,99 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val) break; #if 0 case SP::ASPD_ADDRATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->aspd_add_rate = sd->aspd_add_rate * (100 - val) / 100; break; #endif case SP::HP_RECOV_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->hprecov_rate += val; break; #if 0 case SP::SP_RECOV_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->sprecov_rate += val; break; #endif case SP::CRITICAL_DEF: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->critical_def += val; break; #if 0 case SP::DOUBLE_RATE: - if (sd->state.lr_flag == 0 && sd->double_rate < val) + if (!sd->state.lr_flag_is_arrow_2 && sd->double_rate < val) sd->double_rate = val; break; #endif case SP::DOUBLE_ADD_RATE: - if (sd->state.lr_flag == 0) + if (!sd->state.lr_flag_is_arrow_2) sd->double_add_rate += val; break; #if 0 case SP::MATK_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->matk_rate += val; break; #endif #if 0 case SP::ATK_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->atk_rate += val; break; #endif #if 0 case SP::PERFECT_HIT_RATE: - if (sd->state.lr_flag != 2 && sd->perfect_hit < val) + if (!sd->state.lr_flag_is_arrow_2 && sd->perfect_hit < val) sd->perfect_hit = val; break; #endif #if 0 case SP::PERFECT_HIT_ADD_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->perfect_hit_add += val; break; #endif #if 0 case SP::CRITICAL_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->critical_rate += val; break; #endif #if 0 case SP::HIT_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->hit_rate += val; break; #endif #if 0 case SP::FLEE_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->flee_rate += val; break; #endif #if 0 case SP::FLEE2_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->flee2_rate += val; break; #endif case SP::DEF_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->def_rate += val; break; case SP::DEF2_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->def2_rate += val; break; #if 0 case SP::MDEF_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->mdef_rate += val; break; #endif #if 0 case SP::MDEF2_RATE: - if (sd->state.lr_flag != 2) + if (!sd->state.lr_flag_is_arrow_2) sd->mdef2_rate += val; break; #endif @@ -1758,29 +1704,19 @@ int pc_bonus2(dumb_ptr<map_session_data> sd, SP type, int type2, int val) switch (type) { case SP::HP_DRAIN_RATE: - if (!sd->state.lr_flag) + if (!sd->state.lr_flag_is_arrow_2) { sd->hp_drain_rate += type2; sd->hp_drain_per += val; } - else if (sd->state.lr_flag == 1) - { - sd->hp_drain_rate_ += type2; - sd->hp_drain_per_ += val; - } break; #if 0 case SP::SP_DRAIN_RATE: - if (!sd->state.lr_flag) + if (!sd->state.lr_flag_is_arrow_2) { sd->sp_drain_rate += type2; sd->sp_drain_per += val; } - else if (sd->state.lr_flag == 1) - { - sd->sp_drain_rate_ += type2; - sd->sp_drain_per_ += val; - } break; #endif default: @@ -1971,7 +1907,6 @@ int pc_remove_items(dumb_ptr<map_session_data> player, ItemNameId item_id, int c PickupFail pc_additem(dumb_ptr<map_session_data> sd, Item *item_data, int amount) { - struct item_data *data; int w; MAP_LOG_PC(sd, "PICKUP %d %d"_fmt, item_data->nameid, amount); @@ -1981,7 +1916,7 @@ PickupFail pc_additem(dumb_ptr<map_session_data> sd, Item *item_data, if (!item_data->nameid || amount <= 0) return PickupFail::BAD_ITEM; - data = itemdb_search(item_data->nameid); + P<struct item_data> data = itemdb_search(item_data->nameid); if ((w = data->weight * amount) + sd->weight > sd->max_weight) return PickupFail::TOO_HEAVY; @@ -2013,7 +1948,7 @@ PickupFail pc_additem(dumb_ptr<map_session_data> sd, Item *item_data, sd->status.inventory[i].equip = EPOS::ZERO; sd->status.inventory[i].amount = amount; - sd->inventory_data[i] = data; + sd->inventory_data[i] = Some(data); clif_additem(sd, i, amount, PickupFail::OKAY); } else @@ -2037,18 +1972,18 @@ int pc_delitem(dumb_ptr<map_session_data> sd, IOff0 n, int amount, int type) trade_tradecancel(sd); if (!sd->status.inventory[n].nameid || amount <= 0 - || sd->status.inventory[n].amount < amount - || sd->inventory_data[n] == nullptr) + || sd->status.inventory[n].amount < amount) return 1; + P<struct item_data> sdidn = TRY_UNWRAP(sd->inventory_data[n], return 1); sd->status.inventory[n].amount -= amount; - sd->weight -= sd->inventory_data[n]->weight * amount; + sd->weight -= sdidn->weight * amount; if (sd->status.inventory[n].amount <= 0) { if (bool(sd->status.inventory[n].equip)) pc_unequipitem(sd, n, CalcStatus::NOW); sd->status.inventory[n] = Item{}; - sd->inventory_data[n] = nullptr; + sd->inventory_data[n] = None; } if (!(type & 1)) clif_delitem(sd, n, amount); @@ -2097,8 +2032,6 @@ int pc_dropitem(dumb_ptr<map_session_data> sd, IOff0 n, int amount) static int can_pick_item_up_from(dumb_ptr<map_session_data> self, BlockId other_id) { - PartyPair p = party_search(self->status.party_id); - /* From ourselves or from no-one? */ if (!self || self->bl_id == other_id || !other_id) return 1; @@ -2114,9 +2047,10 @@ int can_pick_item_up_from(dumb_ptr<map_session_data> self, BlockId other_id) return 1; /* From a party member? */ + Option<PartyPair> p = party_search(self->status.party_id); if (self->status.party_id && self->status.party_id == other->status.party_id - && p && p->item != 0) + && p.pmd_pget(&PartyMost::item).copy_or(0) != 0) return 1; /* From someone who is far away? */ @@ -2192,16 +2126,13 @@ int pc_takeitem(dumb_ptr<map_session_data> sd, dumb_ptr<flooritem_data> fitem) static int pc_isUseitem(dumb_ptr<map_session_data> sd, IOff0 n) { - struct item_data *item; ItemNameId nameid; nullpo_retz(sd); - item = sd->inventory_data[n]; + P<struct item_data> item = TRY_UNWRAP(sd->inventory_data[n], return 0); nameid = sd->status.inventory[n].nameid; - if (item == nullptr) - return 0; if (itemdb_type(nameid) != ItemType::USE) return 0; @@ -2223,7 +2154,9 @@ int pc_useitem(dumb_ptr<map_session_data> sd, IOff0 n) nullpo_retr(1, sd); - if (n.ok() && sd->inventory_data[n]) + if (!n.ok()) + return 0; + OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[n]) { amount = sd->status.inventory[n].amount; if (!sd->status.inventory[n].nameid @@ -2234,12 +2167,13 @@ int pc_useitem(dumb_ptr<map_session_data> sd, IOff0 n) return 1; } - const ScriptBuffer *script = sd->inventory_data[n]->use_script.get(); + P<const ScriptBuffer> script = borrow(*sdidn->use_script); clif_useitemack(sd, n, amount - 1, 1); pc_delitem(sd, n, 1, 1); run_script(ScriptPointer(script, 0), sd->bl_id, BlockId()); } + OMATCH_END (); return 0; } @@ -2277,18 +2211,19 @@ int pc_setpos(dumb_ptr<map_session_data> sd, mapname_ = mapname_org; - map_local *m = map_mapname2mapid(mapname_); - if (!m) + Option<P<map_local>> m_ = map_mapname2mapid(mapname_); + if (m_.is_none()) { if (sd->mapname_) { IP4Address ip; int port; - if (map_mapname2ipport(mapname_, &ip, &port) == 0) + if (map_mapname2ipport(mapname_, borrow(ip), borrow(port)) == 0) { skill_stop_dancing(sd, 1); clif_clearchar(sd, clrtype); map_delblock(sd); + // *cringe* sd->mapname_ = mapname_; sd->bl_x = x; sd->bl_y = y; @@ -2310,6 +2245,7 @@ int pc_setpos(dumb_ptr<map_session_data> sd, #endif return 1; } + P<map_local> m = TRY_UNWRAP(m_, abort()); if (x < 0 || x >= m->xs || y < 0 || y >= m->ys) x = y = 0; @@ -2353,35 +2289,6 @@ int pc_setpos(dumb_ptr<map_session_data> sd, } /*========================================== - * PCのランダムワープ - *------------------------------------------ - */ -int pc_randomwarp(dumb_ptr<map_session_data> sd, BeingRemoveWhy type) -{ - int x, y, i = 0; - - nullpo_retz(sd); - - map_local *m = sd->bl_m; - - if (sd->bl_m->flag.get(MapFlag::NOTELEPORT)) // テレポート禁止 - return 0; - - do - { - x = random_::in(1, m->xs - 2); - y = random_::in(1, m->ys - 2); - } - while (bool(read_gatp(m, x, y) & MapCell::UNWALKABLE) - && (i++) < 1000); - - if (i < 1000) - pc_setpos(sd, m->name_, x, y, type); - - return 0; -} - -/*========================================== * *------------------------------------------ */ @@ -2504,8 +2411,8 @@ void pc_walk(TimerData *, tick_t tick, BlockId id, unsigned char data) if (sd->status.party_id) { // パーティのHP情報通知検査 - PartyPair p = party_search(sd->status.party_id); - if (p) + Option<PartyPair> p = party_search(sd->status.party_id); + if (p.is_some()) { int p_flag = 0; map_foreachinmovearea(std::bind(party_send_hp_check, ph::_1, sd->status.party_id, &p_flag), @@ -2631,72 +2538,6 @@ void pc_touch_all_relevant_npcs(dumb_ptr<map_session_data> sd) sd->areanpc_id = BlockId(); } -/*========================================== - * - *------------------------------------------ - */ -int pc_movepos(dumb_ptr<map_session_data> sd, int dst_x, int dst_y) -{ - int moveblock; - int dx, dy; - - struct walkpath_data wpd; - - nullpo_retz(sd); - - if (path_search(&wpd, sd->bl_m, sd->bl_x, sd->bl_y, dst_x, dst_y, 0)) - return 1; - - sd->dir = sd->head_dir = map_calc_dir(sd, dst_x, dst_y); - - dx = dst_x - sd->bl_x; - dy = dst_y - sd->bl_y; - - moveblock = (sd->bl_x / BLOCK_SIZE != dst_x / BLOCK_SIZE - || sd->bl_y / BLOCK_SIZE != dst_y / BLOCK_SIZE); - - map_foreachinmovearea(std::bind(clif_pcoutsight, ph::_1, sd), - sd->bl_m, - sd->bl_x - AREA_SIZE, sd->bl_y - AREA_SIZE, - sd->bl_x + AREA_SIZE, sd->bl_y + AREA_SIZE, - dx, dy, - BL::NUL); - - if (moveblock) - map_delblock(sd); - sd->bl_x = dst_x; - sd->bl_y = dst_y; - if (moveblock) - map_addblock(sd); - - map_foreachinmovearea(std::bind(clif_pcinsight, ph::_1, sd), - sd->bl_m, - sd->bl_x - AREA_SIZE, sd->bl_y - AREA_SIZE, - sd->bl_x + AREA_SIZE, sd->bl_y + AREA_SIZE, - -dx, -dy, - BL::NUL); - - if (sd->status.party_id) - { // パーティのHP情報通知検査 - PartyPair p = party_search(sd->status.party_id); - if (p) - { - int flag = 0; - map_foreachinmovearea(std::bind(party_send_hp_check, ph::_1, sd->status.party_id, &flag), - sd->bl_m, - sd->bl_x - AREA_SIZE, sd->bl_y - AREA_SIZE, - sd->bl_x + AREA_SIZE, sd->bl_y + AREA_SIZE, - -dx, -dy, - BL::PC); - if (flag) - sd->party_hp = -1; - } - } - - pc_touch_all_relevant_npcs(sd); - return 0; -} - // // 武器戦闘 // @@ -2764,8 +2605,8 @@ void pc_attack_timer(TimerData *, tick_t tick, BlockId id) if (sd->opt1 != Opt1::ZERO) return; - Option *opt = battle_get_option(bl); - if (opt != nullptr && bool(*opt & Option::REAL_ANY_HIDE)) + Opt0 *opt = battle_get_option(bl); + if (opt != nullptr && bool(*opt & Opt0::REAL_ANY_HIDE)) return; if (!battle_config.skill_delay_attack_enable) @@ -2824,7 +2665,7 @@ void pc_attack_timer(TimerData *, tick_t tick, BlockId id) sd->attackabletime = tick + (sd->aspd * 2); } if (sd->attackabletime <= tick) - sd->attackabletime = tick + static_cast<interval_t>(battle_config.max_aspd) * 2; + sd->attackabletime = tick + battle_config.max_aspd * 2; } } @@ -3017,6 +2858,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, } } + // Double Xp Weekends + base_exp = (base_exp * static_cast<double>(battle_config.base_exp_rate) / 100.); + if (base_exp <= 0) + base_exp = 0; + else if (base_exp > 1000000000) + base_exp = 1000000000; sd->status.base_exp += base_exp; // [Fate] Adjust experience points that healers can extract from this character @@ -3024,7 +2871,6 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, { const int max_heal_xp = 20 + (sd->status.base_level * sd->status.base_level); - sd->heal_xp += base_exp; if (sd->heal_xp > max_heal_xp) sd->heal_xp = max_heal_xp; @@ -3047,6 +2893,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, } } + // Double Xp Weekends + job_exp = (job_exp * static_cast<double>(battle_config.job_exp_rate) / 100.); + if (job_exp <= 0) + job_exp = 0; + else if (job_exp > 1000000000) + job_exp = 1000000000; sd->status.job_exp += job_exp; if (sd->status.job_exp < 0) sd->status.job_exp = 0; @@ -3247,94 +3099,6 @@ int pc_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) } /*========================================== - * /resetlvl - *------------------------------------------ - */ -int pc_resetlvl(dumb_ptr<map_session_data> sd, int type) -{ - nullpo_retz(sd); - - for (SkillID i : erange(SkillID(1), MAX_SKILL)) - { - sd->status.skill[i].lv = 0; - } - - if (type == 1) - { - sd->status.skill_point = 0; - sd->status.base_level = 1; - sd->status.job_level = 1; - sd->status.base_exp = 0; - sd->status.job_exp = 0; - sd->status.option = Option::ZERO; - - for (ATTR attr : ATTRs) - sd->status.attrs[attr] = 1; - } - - if (type == 2) - { - sd->status.skill_point = 0; - sd->status.base_level = 1; - sd->status.job_level = 1; - sd->status.base_exp = 0; - sd->status.job_exp = 0; - } - if (type == 3) - { - sd->status.base_level = 1; - sd->status.base_exp = 0; - } - if (type == 4) - { - sd->status.job_level = 1; - sd->status.job_exp = 0; - } - - clif_updatestatus(sd, SP::STATUSPOINT); - clif_updatestatus(sd, SP::STR); - clif_updatestatus(sd, SP::AGI); - clif_updatestatus(sd, SP::VIT); - clif_updatestatus(sd, SP::INT); - clif_updatestatus(sd, SP::DEX); - clif_updatestatus(sd, SP::LUK); - clif_updatestatus(sd, SP::BASELEVEL); - clif_updatestatus(sd, SP::JOBLEVEL); - clif_updatestatus(sd, SP::STATUSPOINT); - clif_updatestatus(sd, SP::NEXTBASEEXP); - clif_updatestatus(sd, SP::NEXTJOBEXP); - clif_updatestatus(sd, SP::SKILLPOINT); - - clif_updatestatus(sd, SP::USTR); // Updates needed stat points - Valaris - clif_updatestatus(sd, SP::UAGI); - clif_updatestatus(sd, SP::UVIT); - clif_updatestatus(sd, SP::UINT); - clif_updatestatus(sd, SP::UDEX); - clif_updatestatus(sd, SP::ULUK); // End Addition - - for (EQUIP i : EQUIPs) - { - // unequip items that can't be equipped by base 1 [Valaris] - IOff0 *idx = &sd->equip_index_maybe[i]; - if ((*idx).ok()) - { - if (!pc_isequip(sd, *idx)) - { - pc_unequipitem(sd, *idx, CalcStatus::LATER); - *idx = IOff0::from(-1); - } - } - } - - clif_skillinfoblock(sd); - pc_calcstatus(sd, 0); - - MAP_LOG_STATS(sd, "STATRESET"_fmt); - - return 0; -} - -/*========================================== * /resetstate *------------------------------------------ */ @@ -3435,9 +3199,12 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, if (sd->status.party_id) { // on-the-fly party hp updates [Valaris] - PartyPair p = party_search(sd->status.party_id); - if (p) + Option<PartyPair> p_ = party_search(sd->status.party_id); + OMATCH_BEGIN_SOME (p, p_) + { clif_party_hp(p, sd); + } + OMATCH_END (); } // end addition [Valaris] return 0; @@ -3728,8 +3495,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) } break; case SP::SEX: - // this is a really bad idea - sd->sex = static_cast<SEX>(val); + chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff()); break; case SP::WEIGHT: sd->weight = val; @@ -3755,7 +3521,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) case SP::INT: case SP::DEX: case SP::LUK: - sd->status.attrs[sp_to_attr(type)] = val; + pc_statusup2(sd, type, (val - sd->status.attrs[sp_to_attr(type)])); break; } clif_updatestatus(sd, type); @@ -3803,9 +3569,12 @@ int pc_heal(dumb_ptr<map_session_data> sd, int hp, int sp) if (sd->status.party_id) { // on-the-fly party hp updates [Valaris] - PartyPair p = party_search(sd->status.party_id); - if (p) + Option<PartyPair> p_ = party_search(sd->status.party_id); + OMATCH_BEGIN_SOME (p, p_) + { clif_party_hp(p, sd); + } + OMATCH_END (); } // end addition [Valaris] return hp + sp; @@ -3933,75 +3702,6 @@ int pc_itemheal_effect(dumb_ptr<map_session_data> sd, int hp, int sp) } /*========================================== - * HP/SP回復 - *------------------------------------------ - */ -int pc_percentheal(dumb_ptr<map_session_data> sd, int hp, int sp) -{ - nullpo_retz(sd); - - if (pc_checkoverhp(sd)) - { - if (hp > 0) - hp = 0; - } - if (pc_checkoversp(sd)) - { - if (sp > 0) - sp = 0; - } - if (hp) - { - if (hp >= 100) - { - sd->status.hp = sd->status.max_hp; - } - else if (hp <= -100) - { - sd->status.hp = 0; - pc_damage(nullptr, sd, 1); - } - else - { - sd->status.hp += sd->status.max_hp * hp / 100; - if (sd->status.hp > sd->status.max_hp) - sd->status.hp = sd->status.max_hp; - if (sd->status.hp <= 0) - { - sd->status.hp = 0; - pc_damage(nullptr, sd, 1); - hp = 0; - } - } - } - if (sp) - { - if (sp >= 100) - { - sd->status.sp = sd->status.max_sp; - } - else if (sp <= -100) - { - sd->status.sp = 0; - } - else - { - sd->status.sp += sd->status.max_sp * sp / 100; - if (sd->status.sp > sd->status.max_sp) - sd->status.sp = sd->status.max_sp; - if (sd->status.sp < 0) - sd->status.sp = 0; - } - } - if (hp) - clif_updatestatus(sd, SP::HP); - if (sp) - clif_updatestatus(sd, SP::SP); - - return 0; -} - -/*========================================== * 見た目変更 *------------------------------------------ */ @@ -4044,21 +3744,6 @@ int pc_changelook(dumb_ptr<map_session_data> sd, LOOK type, int val) } /*========================================== - * 付属品(鷹,ペコ,カート)設定 - *------------------------------------------ - */ -int pc_setoption(dumb_ptr<map_session_data> sd, Option type) -{ - nullpo_retz(sd); - - sd->status.option = type; - clif_changeoption(sd); - pc_calcstatus(sd, 0); - - return 0; -} - -/*========================================== * script用変数の値を読む *------------------------------------------ */ @@ -4088,11 +3773,8 @@ ZString pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg) { nullpo_retr(ZString(), sd); - RString *s = sd->regstrm.search(reg); - if (s) - return *s; - - return ZString(); + Option<P<RString>> s = sd->regstrm.search(reg); + return s.map([](P<RString> s_) -> ZString { return *s_; }).copy_or(""_s); } /*========================================== @@ -4119,14 +3801,37 @@ void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, RString str) int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg) { int i; - + int quest_shift = 0; + int quest_mask = 0; nullpo_retz(sd); + QuestId questid; + XString var = reg; + VarName vr; assert (sd->status.global_reg_num < GLOBAL_REG_NUM); + Option<P<struct quest_data>> quest_data_ = questdb_searchname(var); + OMATCH_BEGIN_SOME(quest_data, quest_data_) + { + questid = quest_data->questid; + reg = quest_data->quest_vr; + vr = quest_data->quest_var; + quest_shift = quest_data->quest_shift; + quest_mask = quest_data->quest_mask; + } + OMATCH_END (); for (i = 0; i < sd->status.global_reg_num; i++) { if (sd->status.global_reg[i].str == reg) - return sd->status.global_reg[i].value; + { + if (questid) + { + return ((sd->status.global_reg[i].value & (((1 << quest_mask) - 1) << (quest_shift * quest_mask))) >> (quest_shift * quest_mask)); + } + else + { + return sd->status.global_reg[i].value; + } + } } return 0; @@ -4139,8 +3844,13 @@ int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg) int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; - + int quest_shift = 0; + int quest_mask = 0; + int bitval = val; nullpo_retz(sd); + QuestId questid; + XString var = reg; + VarName vr; //PC_DIE_COUNTERがスクリプトなどで変更された時の処理 if (reg == stringish<VarName>("PC_DIE_COUNTER"_s) && sd->die_counter != val) @@ -4148,6 +3858,17 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) sd->die_counter = val; pc_calcstatus(sd, 0); } + Option<P<struct quest_data>> quest_data_ = questdb_searchname(var); + OMATCH_BEGIN_SOME(quest_data, quest_data_) + { + questid = quest_data->questid; + reg = quest_data->quest_vr; + vr = quest_data->quest_var; + quest_shift = quest_data->quest_shift; + quest_mask = quest_data->quest_mask; + assert (((1 << quest_mask) - 1) >= val); + } + OMATCH_END (); assert (sd->status.global_reg_num < GLOBAL_REG_NUM); if (val == 0) { @@ -4155,9 +3876,18 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { if (sd->status.global_reg[i].str == reg) { - sd->status.global_reg[i] = - sd->status.global_reg[sd->status.global_reg_num - 1]; - sd->status.global_reg_num--; + if (questid) + { + bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask))); + clif_sendquest(sd, questid, val); + } + sd->status.global_reg[i].value = bitval; + if (sd->status.global_reg[i].value == 0) + { + sd->status.global_reg[i] = + sd->status.global_reg[sd->status.global_reg_num - 1]; + sd->status.global_reg_num--; + } break; } } @@ -4167,14 +3897,24 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { if (sd->status.global_reg[i].str == reg) { - sd->status.global_reg[i].value = val; + if (questid) + { + bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask))); + clif_sendquest(sd, questid, val); + } + sd->status.global_reg[i].value = bitval; return 0; } } if (sd->status.global_reg_num < GLOBAL_REG_NUM) { sd->status.global_reg[i].str = reg; - sd->status.global_reg[i].value = val; + if (questid) + { + bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask))); + clif_sendquest(sd, questid, val); + } + sd->status.global_reg[i].value = bitval; sd->status.global_reg_num++; return 0; } @@ -4400,7 +4140,6 @@ int pc_signal_advanced_equipment_change(dumb_ptr<map_session_data> sd, IOff0 n) int pc_equipitem(dumb_ptr<map_session_data> sd, IOff0 n, EPOS) { ItemNameId nameid; - struct item_data *id; //ソス]ソスソスソスソスソス{ソスqソスフ場合ソスフ鯉ソスソスフ職ソスニゑソスソスZソスoソスソスソスソス nullpo_retz(sd); @@ -4412,9 +4151,8 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, IOff0 n, EPOS) } nameid = sd->status.inventory[n].nameid; - id = sd->inventory_data[n]; - if (!id) // can't actually happen - the only caller checks this. - return 0; + // can't actually happen - the only caller checks this. + P<struct item_data> id = TRY_UNWRAP(sd->inventory_data[n], return 0); EPOS pos = pc_equippoint(sd, n); if (battle_config.battle_log) @@ -4475,17 +4213,18 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, IOff0 n, EPOS) ItemNameId view_i; ItemLook view_l = ItemLook::NONE; // TODO: This is ugly. - if (sd->inventory_data[n]) + OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[n]) { - bool look_not_weapon = sd->inventory_data[n]->look == ItemLook::NONE; + bool look_not_weapon = sdidn->look == ItemLook::NONE; bool equip_is_weapon = bool(sd->status.inventory[n].equip & EPOS::WEAPON); assert (look_not_weapon != equip_is_weapon); if (look_not_weapon) - view_i = sd->inventory_data[n]->nameid; + view_i = sdidn->nameid; else - view_l = sd->inventory_data[n]->look; + view_l = sdidn->look; } + OMATCH_END (); if (bool(sd->status.inventory[n].equip & EPOS::WEAPON)) { @@ -4495,25 +4234,27 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, IOff0 n, EPOS) } if (bool(sd->status.inventory[n].equip & EPOS::SHIELD)) { - if (sd->inventory_data[n]) + OMATCH_BEGIN (sd->inventory_data[n]) { - if (sd->inventory_data[n]->type == ItemType::WEAPON) + OMATCH_CASE_SOME (sdidn) { - sd->status.shield = ItemNameId(); - if (sd->status.inventory[n].equip == EPOS::SHIELD) - sd->weapontype2 = view_l; + if (sdidn->type == ItemType::WEAPON) + { + sd->status.shield = ItemNameId(); + if (sd->status.inventory[n].equip == EPOS::SHIELD) + assert(0 && "unreachable - offhand weapons are not supported"); + } + else if (sdidn->type == ItemType::ARMOR) + { + sd->status.shield = view_i; + } } - else if (sd->inventory_data[n]->type == ItemType::ARMOR) + OMATCH_CASE_NONE () { - sd->status.shield = view_i; - sd->weapontype2 = ItemLook::NONE; + sd->status.shield = ItemNameId(); } } - else - { - sd->status.shield = ItemNameId(); - sd->weapontype2 = ItemLook::NONE; - } + OMATCH_END (); pc_calcweapontype(sd); clif_changelook(sd, LOOK::SHIELD, unwrap<ItemNameId>(sd->status.shield)); } @@ -4563,14 +4304,14 @@ int pc_unequipitem(dumb_ptr<map_session_data> sd, IOff0 n, CalcStatus type) if (bool(sd->status.inventory[n].equip & EPOS::WEAPON)) { sd->weapontype1 = ItemLook::NONE; - sd->status.weapon = sd->weapontype2; + // when reading the diff, think twice about this + sd->status.weapon = ItemLook::NONE; pc_calcweapontype(sd); pc_set_weapon_look(sd); } if (bool(sd->status.inventory[n].equip & EPOS::SHIELD)) { sd->status.shield = ItemNameId(); - sd->weapontype2 = ItemLook::NONE; pc_calcweapontype(sd); clif_changelook(sd, LOOK::SHIELD, unwrap<ItemNameId>(sd->status.shield)); } @@ -4728,8 +4469,7 @@ void pc_calc_pvprank_sub(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> sd2 int pc_calc_pvprank(dumb_ptr<map_session_data> sd) { nullpo_retz(sd); - map_local *m = sd->bl_m; - nullpo_retz(m); + P<map_local> m = sd->bl_m; if (!(m->flag.get(MapFlag::PVP))) return 0; @@ -4816,15 +4556,12 @@ int pc_divorce(dumb_ptr<map_session_data> sd) } p_sd->status.partner_id = CharId(); sd->status.partner_id = CharId(); - - if (sd->npc_flags.divorce) - { - sd->npc_flags.divorce = 0; - map_scriptcont(sd, sd->npc_id); - } } else + { + sd->status.partner_id = CharId(); chrif_send_divorce(sd->status_key.char_id); + } return 0; } @@ -4857,10 +4594,6 @@ dumb_ptr<map_session_data> pc_get_partner(dumb_ptr<map_session_data> sd) * SP回復量計算 *------------------------------------------ */ -static -tick_t natural_heal_tick, natural_heal_prev_tick; -static -interval_t natural_heal_diff_tick; static interval_t pc_spheal(dumb_ptr<map_session_data> sd) @@ -4918,12 +4651,12 @@ int pc_natural_heal_hp(dumb_ptr<map_session_data> sd) return 0; } - if (sd->hp_sub >= static_cast<interval_t>(battle_config.natural_healhp_interval)) + if (sd->hp_sub >= battle_config.natural_healhp_interval) { bonus = sd->nhealhp; - while (sd->hp_sub >= static_cast<interval_t>(battle_config.natural_healhp_interval)) + while (sd->hp_sub >= battle_config.natural_healhp_interval) { - sd->hp_sub -= static_cast<interval_t>(battle_config.natural_healhp_interval); + sd->hp_sub -= battle_config.natural_healhp_interval; if (sd->status.hp + bonus <= sd->status.max_hp) sd->status.hp += bonus; else @@ -4936,28 +4669,7 @@ int pc_natural_heal_hp(dumb_ptr<map_session_data> sd) if (bhp != sd->status.hp) clif_updatestatus(sd, SP::HP); - if (sd->nshealhp > 0) - { - if (sd->inchealhptick >= static_cast<interval_t>(battle_config.natural_heal_skill_interval) - && sd->status.hp < sd->status.max_hp) - { - bonus = sd->nshealhp; - while (sd->inchealhptick >= static_cast<interval_t>(battle_config.natural_heal_skill_interval)) - { - sd->inchealhptick -= static_cast<interval_t>(battle_config.natural_heal_skill_interval); - if (sd->status.hp + bonus <= sd->status.max_hp) - sd->status.hp += bonus; - else - { - bonus = sd->status.max_hp - sd->status.hp; - sd->status.hp = sd->status.max_hp; - sd->hp_sub = sd->inchealhptick = interval_t::zero(); - } - } - } - } - else - sd->inchealhptick = interval_t::zero(); + sd->inchealhptick = interval_t::zero(); return 0; } @@ -4985,12 +4697,12 @@ int pc_natural_heal_sp(dumb_ptr<map_session_data> sd) else sd->inchealsptick = interval_t::zero(); - if (sd->sp_sub >= static_cast<interval_t>(battle_config.natural_healsp_interval)) + if (sd->sp_sub >= battle_config.natural_healsp_interval) { bonus = sd->nhealsp; - while (sd->sp_sub >= static_cast<interval_t>(battle_config.natural_healsp_interval)) + while (sd->sp_sub >= battle_config.natural_healsp_interval) { - sd->sp_sub -= static_cast<interval_t>(battle_config.natural_healsp_interval); + sd->sp_sub -= battle_config.natural_healsp_interval; if (sd->status.sp + bonus <= sd->status.max_sp) sd->status.sp += bonus; else @@ -5004,28 +4716,7 @@ int pc_natural_heal_sp(dumb_ptr<map_session_data> sd) if (bsp != sd->status.sp) clif_updatestatus(sd, SP::SP); - if (sd->nshealsp > 0) - { - if (sd->inchealsptick >= static_cast<interval_t>(battle_config.natural_heal_skill_interval) - && sd->status.sp < sd->status.max_sp) - { - bonus = sd->nshealsp; - while (sd->inchealsptick >= static_cast<interval_t>(battle_config.natural_heal_skill_interval)) - { - sd->inchealsptick -= static_cast<interval_t>(battle_config.natural_heal_skill_interval); - if (sd->status.sp + bonus <= sd->status.max_sp) - sd->status.sp += bonus; - else - { - bonus = sd->status.max_sp - sd->status.sp; - sd->status.sp = sd->status.max_sp; - sd->sp_sub = sd->inchealsptick = interval_t::zero(); - } - } - } - } - else - sd->inchealsptick = interval_t::zero(); + sd->inchealsptick = interval_t::zero(); return 0; } @@ -5147,8 +4838,6 @@ void pc_setsavepoint(dumb_ptr<map_session_data> sd, MapName mapname, int x, int *------------------------------------------ */ static -int last_save_fd, save_flag; -static void pc_autosave_sub(dumb_ptr<map_session_data> sd) { nullpo_retv(sd); @@ -5175,7 +4864,7 @@ void pc_autosave(TimerData *, tick_t) if (save_flag == 0) last_save_fd = -1; - interval_t interval = autosave_time / (clif_countusers() + 1); + interval_t interval = map_conf.autosave_time / (clif_countusers() + 1); if (interval <= interval_t::zero()) interval = 1_ms; Timer(gettick() + interval, @@ -5228,7 +4917,7 @@ void do_init_pc(void) pc_natural_heal, NATURAL_HEAL_INTERVAL ).detach(); - Timer(gettick() + autosave_time, + Timer(gettick() + map_conf.autosave_time, pc_autosave ).detach(); } @@ -5240,15 +4929,15 @@ void pc_cleanup(dumb_ptr<map_session_data> sd) void pc_invisibility(dumb_ptr<map_session_data> sd, int enabled) { - if (enabled && !bool(sd->status.option & Option::INVISIBILITY)) + if (enabled && !bool(sd->status.option & Opt0::INVISIBILITY)) { clif_clearchar(sd, BeingRemoveWhy::WARPED); - sd->status.option |= Option::INVISIBILITY; + sd->status.option |= Opt0::INVISIBILITY; clif_status_change(sd, StatusChange::CLIF_OPTION_SC_INVISIBILITY, 1); } else if (!enabled) { - sd->status.option &= ~Option::INVISIBILITY; + sd->status.option &= ~Opt0::INVISIBILITY; clif_status_change(sd, StatusChange::CLIF_OPTION_SC_INVISIBILITY, 0); pc_setpos(sd, sd->bl_m->name_, sd->bl_x, sd->bl_y, BeingRemoveWhy::WARPED); } @@ -5280,4 +4969,5 @@ int pc_logout(dumb_ptr<map_session_data> sd) // [fate] Player logs out MAP_LOG_STATS(sd, "LOGOUT"_fmt); return 0; } +} // namespace map } // namespace tmwa |