summaryrefslogtreecommitdiff
path: root/src/map/pc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/pc.cpp')
-rw-r--r--src/map/pc.cpp978
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