From 887dc62bbddd350371fec471aecca8e6e0e56813 Mon Sep 17 00:00:00 2001 From: Hello TMW Date: Thu, 15 Dec 2022 15:38:47 +0000 Subject: Hello=). Someone said its up to GMs to deal with users exploiting their servers. --- src/map/clif.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/map/clif.cpp b/src/map/clif.cpp index f71feb6..0eb2b8c 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -6083,6 +6083,17 @@ AString clif_validate_chat(dumb_ptr sd, ChatType type, XString WARN_MALFORMED_MSG(sd, "exceeded maximum message length"_s); return AString(); } + // Try to grasp max allowed message for global accounting for CharName + if (type == ChatType::Global && \ + (buf.size() >= (battle_config.chat_maxline - (2+sizeof(CharName)))) || \ + buf.size() >= 486) // 486 is hard clamp if battle_config.chat_maxline too small, etc + { + WARN_MALFORMED_MSG(sd, "exceeded maximum Global message length"_s); + AString hack_msg = STRPRINTF("[GM] %s attempted oversized Global chat message"_fmt, + sd->status_key.name); + tmw_GmHackMsg(hack_msg); // alert GMs about possible exploit attempt. + return AString(); + } // Step beyond the separator. for older clients if (type == ChatType::Global && sd->client_version < wrap(6)) -- cgit v1.2.3-60-g2f50 From 67bf4970c20f18a55cab7adde58ef346f3d2ad1e Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Fri, 16 Dec 2022 11:21:49 +0100 Subject: mobs critical_def + 10 drops + storage 500 --- src/map/atcommand.cpp | 4 +-- src/map/battle.cpp | 2 ++ src/map/mob.cpp | 9 +++++ src/map/mob.hpp | 4 +-- src/map/script-fun.cpp | 29 +++++++++++++++ src/map/script-fun.t.hpp | 93 ++++++++++++++++++++++++++---------------------- src/mmo/consts.hpp | 6 ++-- 7 files changed, 98 insertions(+), 49 deletions(-) diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index f5ca72d..d7d47c9 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1852,7 +1852,7 @@ ATCE atcommand_mobinfo(Session *s, dumb_ptr sd, clif_displaymessage(s, STRPRINTF("Monster ID: %i, English Name: %s, Japanese Name: %s"_fmt, mob_id, get_mob_db(mob_id).name, get_mob_db(mob_id).jname)); clif_displaymessage(s, STRPRINTF("Level: %i, HP: %i, SP: %i, Base EXP: %i, JEXP: %i"_fmt, get_mob_db(mob_id).lv, get_mob_db(mob_id).max_hp, get_mob_db(mob_id).max_sp, get_mob_db(mob_id).base_exp, get_mob_db(mob_id).job_exp)); - clif_displaymessage(s, STRPRINTF("Range1: %i, ATK1: %i, ATK2: %i, DEF: %i, MDEF: %i"_fmt, get_mob_db(mob_id).range, get_mob_db(mob_id).atk1, get_mob_db(mob_id).atk2, get_mob_db(mob_id).def, get_mob_db(mob_id).mdef)); + clif_displaymessage(s, STRPRINTF("Range1: %i, ATK1: %i, ATK2: %i, DEF: %i, MDEF: %i, CRITICAL_DEF: %i"_fmt, get_mob_db(mob_id).range, get_mob_db(mob_id).atk1, get_mob_db(mob_id).atk2, get_mob_db(mob_id).def, get_mob_db(mob_id).mdef, get_mob_db(mob_id).critical_def)); clif_displaymessage(s, STRPRINTF("Stats: STR: %i, AGI: %i, VIT: %i, INT: %i, DEX:, %i LUK:, %i"_fmt, get_mob_db(mob_id).attrs[ATTR::STR], get_mob_db(mob_id).attrs[ATTR::AGI], get_mob_db(mob_id).attrs[ATTR::VIT], get_mob_db(mob_id).attrs[ATTR::INT], get_mob_db(mob_id).attrs[ATTR::DEX], get_mob_db(mob_id).attrs[ATTR::LUK])); clif_displaymessage(s, STRPRINTF("Range2: %i, Range3: %i, Scale: %i, Race: %i, Element: %i, Element Level: %i, Mode: %i"_fmt, get_mob_db(mob_id).range2, get_mob_db(mob_id).range3, get_mob_db(mob_id).size, get_mob_db(mob_id).race, get_mob_db(mob_id).element.element, get_mob_db(mob_id).element.level, get_mob_db(mob_id).mode)); clif_displaymessage(s, STRPRINTF("Speed: %i, Adelay: %i, Amotion: %i, Dmotion: %i"_fmt, get_mob_db(mob_id).speed.count(), get_mob_db(mob_id).adelay.count(), get_mob_db(mob_id).amotion.count(), get_mob_db(mob_id).dmotion.count())); @@ -1922,7 +1922,7 @@ ATCE atcommand_mobinfo(Session *s, dumb_ptr sd, str[strpos] = '\0'; int drop_rate2 = 10000/drop_rate; - clif_displaymessage(s, STRPRINTF("Drop ID %i: %i, Item Name: %s, Drop Chance: %s%% (1:%i)"_fmt,i+1, get_mob_db(mob_id).dropitem[i].nameid, item_name, str, drop_rate2)); + clif_displaymessage(s, STRPRINTF("Drop ID %i: %i, Item Name: %s, Drop Chance: %s%% (1:%i)"_fmt,i, get_mob_db(mob_id).dropitem[i].nameid, item_name, str, drop_rate2)); } else break; diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 52be591..3b7c6b2 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -1592,6 +1592,8 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr src, if (tsd && tsd->critical_def) cri = cri * (100 - tsd->critical_def) / 100; + else if (tmd && tmd->stats[mob_stat::CRITICAL_DEF]) + cri = cri * (100 - tmd->stats[mob_stat::CRITICAL_DEF]) / 100; // ダブルアタックが発動していない | Double Attack is not activated // 判定(スキルの場合は無視) | Judgment (ignored for skills) diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 0f273a8..715a9cb 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -173,6 +173,7 @@ earray mutation_value //= 2, // mob_stat::DEF 2, // mob_stat::MDEF 2, // mob_stat::SPEED + 2, // mob_stat::CRITICAL_DEF }}; // The mutation scale indicates how far `up' we can go, with 256 indicating 100% Note that this may stack with multiple @@ -194,6 +195,7 @@ earray mutation_scale //= 48, // mob_stat::DEF 48, // mob_stat::MDEF 80, // mob_stat::SPEED + 128, // mob_stat::CRITICAL_DEF }}; // The table below indicates the `average' value for each of the statistics, or -1 if there is none. @@ -220,6 +222,7 @@ earray mutation_base //= -1, // mob_stat::DEF 20, // mob_stat::MDEF -1, // mob_stat::SPEED + -1, // mob_stat::CRITICAL_DEF }}; /*======================================== @@ -361,6 +364,7 @@ void mob_init(dumb_ptr md) md->stats[mob_stat::ADELAY] = get_mob_db(mob_class).adelay.count(); md->stats[mob_stat::DEF] = get_mob_db(mob_class).def; md->stats[mob_stat::MDEF] = get_mob_db(mob_class).mdef; + md->stats[mob_stat::CRITICAL_DEF] = get_mob_db(mob_class).critical_def; md->stats[mob_stat::SPEED] = get_mob_db(mob_class).speed.count(); md->stats[mob_stat::XP_BONUS] = MOB_XP_BONUS_BASE; @@ -3495,6 +3499,7 @@ bool mob_readdb(ZString filename) lstripping(&mdbv.atk2), lstripping(&mdbv.def), lstripping(&mdbv.mdef), + lstripping(&mdbv.critical_def), lstripping(&mdbv.attrs[ATTR::STR]), lstripping(&mdbv.attrs[ATTR::AGI]), lstripping(&mdbv.attrs[ATTR::VIT]), @@ -3527,6 +3532,10 @@ bool mob_readdb(ZString filename) lstripping(&mdbv.dropitem[6].p.num), lstripping(&mdbv.dropitem[7].nameid), lstripping(&mdbv.dropitem[7].p.num), + lstripping(&mdbv.dropitem[8].nameid), + lstripping(&mdbv.dropitem[8].p.num), + lstripping(&mdbv.dropitem[9].nameid), + lstripping(&mdbv.dropitem[9].p.num), &ignore, &ignore, &ignore, diff --git a/src/map/mob.hpp b/src/map/mob.hpp index 47da095..3aa7fc5 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -43,7 +43,7 @@ namespace map #define JAPANESE_NAME stringish("--ja--"_s) #define MOB_THIS_MAP stringish("this"_s) -#define MaxDrops 8 +#define MaxDrops 10 #define MinMobID 1001 #define MaxMobID 2000 @@ -69,7 +69,7 @@ struct mob_db_ int max_hp, max_sp; int base_exp, job_exp; int atk1, atk2; - int def, mdef; + int def, mdef, critical_def; earray attrs; int range, range2, range3; // always 1 diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index e42dcd2..9ee76a2 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -2700,6 +2700,9 @@ void builtin_mobinfo(ScriptState *st) case MobInfo::MDEF: info = get_mob_db(mob_id).mdef; break; + case MobInfo::CRITICAL_DEF: + info = get_mob_db(mob_id).critical_def; + break; case MobInfo::STR: info = get_mob_db(mob_id).attrs[ATTR::STR]; break; @@ -2757,6 +2760,19 @@ void builtin_mobinfo(ScriptState *st) case MobInfo::MUTATION_POWER: info = get_mob_db(mob_id).mutation_power; break; + case MobInfo::DROPID0: + info = unwrap(get_mob_db(mob_id).dropitem[0].nameid); + break; + case MobInfo::DROPNAME0: + { + Option> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[0].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT0: + info = get_mob_db(mob_id).dropitem[0].p.num; + break; case MobInfo::DROPID1: info = unwrap(get_mob_db(mob_id).dropitem[0].nameid); break; @@ -2861,6 +2877,19 @@ void builtin_mobinfo(ScriptState *st) case MobInfo::DROPPERCENT8: info = get_mob_db(mob_id).dropitem[7].p.num; break; + case MobInfo::DROPID9: + info = unwrap(get_mob_db(mob_id).dropitem[7].nameid); + break; + case MobInfo::DROPNAME9: + { + Option> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[7].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT9: + info = get_mob_db(mob_id).dropitem[7].p.num; + break; default: PRINTF("builtin_mobinfo: unknown request\n"_fmt); push_int(st->stack, -1); diff --git a/src/map/script-fun.t.hpp b/src/map/script-fun.t.hpp index d0c753b..6cc2683 100644 --- a/src/map/script-fun.t.hpp +++ b/src/map/script-fun.t.hpp @@ -41,49 +41,56 @@ enum class MobInfo : uint8_t ATK2 = 10, DEF = 11, MDEF = 12, - STR = 13, - AGI = 14, - VIT = 15, - INT = 16, - DEX = 17, - LUK = 18, - RANGE2 = 19, - RANGE3 = 20, - SCALE = 21, - RACE = 22, - ELEMENT = 23, - ELEMENT_LVL = 24, - MODE = 25, - SPEED = 26, - ADELAY = 27, - AMOTION = 28, - DMOTION = 29, - MUTATION_NUM = 30, - MUTATION_POWER = 31, - DROPID1 = 32, - DROPNAME1 = 33, - DROPPERCENT1 = 34, - DROPID2 = 35, - DROPNAME2 = 36, - DROPPERCENT2 = 37, - DROPID3 = 38, - DROPNAME3 = 39, - DROPPERCENT3 = 40, - DROPID4 = 41, - DROPNAME4 = 42, - DROPPERCENT4 = 43, - DROPID5 = 44, - DROPNAME5 = 45, - DROPPERCENT5 = 46, - DROPID6 = 47, - DROPNAME6 = 48, - DROPPERCENT6 = 49, - DROPID7 = 50, - DROPNAME7 = 51, - DROPPERCENT7 = 52, - DROPID8 = 53, - DROPNAME8 = 54, - DROPPERCENT8 = 55, + CRITICAL_DEF = 13, + STR = 14, + AGI = 15, + VIT = 16, + INT = 17, + DEX = 18, + LUK = 19, + RANGE2 = 20, + RANGE3 = 21, + SCALE = 22, + RACE = 23, + ELEMENT = 24, + ELEMENT_LVL = 25, + MODE = 26, + SPEED = 27, + ADELAY = 28, + AMOTION = 29, + DMOTION = 30, + MUTATION_NUM = 31, + MUTATION_POWER = 32, + DROPID0 = 33, + DROPNAME0 = 34, + DROPPERCENT0 = 35, + DROPID1 = 36, + DROPNAME1 = 37, + DROPPERCENT1 = 38, + DROPID2 = 39, + DROPNAME2 = 40, + DROPPERCENT2 = 41, + DROPID3 = 42, + DROPNAME3 = 43, + DROPPERCENT3 = 44, + DROPID4 = 45, + DROPNAME4 = 46, + DROPPERCENT4 = 47, + DROPID5 = 48, + DROPNAME5 = 49, + DROPPERCENT5 = 50, + DROPID6 = 51, + DROPNAME6 = 52, + DROPPERCENT6 = 53, + DROPID7 = 54, + DROPNAME7 = 55, + DROPPERCENT7 = 56, + DROPID8 = 57, + DROPNAME8 = 58, + DROPPERCENT8 = 59, + DROPID9 = 60, + DROPNAME9 = 61, + DROPPERCENT9 = 62, }; enum class MobInfo_DropArrays : uint8_t diff --git a/src/mmo/consts.hpp b/src/mmo/consts.hpp index 5445186..d56facd 100644 --- a/src/mmo/consts.hpp +++ b/src/mmo/consts.hpp @@ -36,7 +36,9 @@ constexpr int MAX_MAP_PER_SERVER = 512; constexpr int MAX_INVENTORY = 100; constexpr int MAX_AMOUNT = 30000; constexpr int MAX_ZENY = 1000000000; // 1G zeny -constexpr int TRADE_MAX = 10; +constexpr int TRADE_MAX = 12; +// M+ 1.9.3.23 only supports 12 items in trade window it will make the trade with more but brings error messages for every item above 12. +// So I let it 12 for now until ManaVerse (with cuocos fix) is the only client. constexpr int GLOBAL_REG_NUM = 96; constexpr size_t ACCOUNT_REG_NUM = 16; @@ -44,7 +46,7 @@ constexpr size_t ACCOUNT_REG2_NUM = 16; constexpr interval_t DEFAULT_WALK_SPEED = 150_ms; constexpr interval_t MIN_WALK_SPEED = interval_t::zero(); constexpr interval_t MAX_WALK_SPEED = 1_s; -constexpr int MAX_STORAGE = 300; +constexpr int MAX_STORAGE = 500; constexpr int MAX_PARTY = 120; #define MIN_HAIR_STYLE battle_config.min_hair_style -- cgit v1.2.3-60-g2f50 From 23d0fda8f2c6687447086632be908da684fb4021 Mon Sep 17 00:00:00 2001 From: Jesusaves Date: Thu, 22 Dec 2022 19:42:46 -0300 Subject: Fix a typo --- src/map/map.t.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp index d685c01..4336411 100644 --- a/src/map/map.t.hpp +++ b/src/map/map.t.hpp @@ -71,6 +71,7 @@ enum class mob_stat DEF, MDEF, SPEED, + CRITICAL_DEF, // These must come last: // [Fate] Encoded as base to 1024: 1024 means 100% XP_BONUS, -- cgit v1.2.3-60-g2f50 From faa336a7f64059f4fb376a386a4a716acd48a9b3 Mon Sep 17 00:00:00 2001 From: Jesusaves Date: Fri, 23 Dec 2022 12:54:04 -0300 Subject: mesn was missing, but now the three minimum functions are here! --- src/map/script-fun.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 9ee76a2..1788570 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -131,6 +131,23 @@ void builtin_mesq(ScriptState *st) clif_scriptmes(sd, st->oid, RString(mesq)); } +static +void builtin_mesn(ScriptState *st) +{ + dumb_ptr sd = script_rid2sd(st); + dumb_ptr nd; + nd = map_id_is_npc(st->oid); + script_nullpo_end(nd, "npc not found"); + script_nullpo_end(sd, "player not found"); + sd->state.npc_dialog_mes = 1; + RString mes = HARG(0) ? conv_str(st, &AARG(0)) : RString(nd->name.xislice_h(std::find(nd->name.begin(), nd->name.end(), '#'))); // strnpcinf + MString mesq; + mesq += "["_s; + mesq += mes; + mesq += "]"_s; + clif_scriptmes(sd, st->oid, RString(mesq)); +} + static void builtin_clear(ScriptState *st) { @@ -5553,6 +5570,7 @@ BuiltinFunction builtin_functions[] = { BUILTIN(mes, "?"_s, '\0'), BUILTIN(mesq, "?"_s, '\0'), + BUILTIN(mesn, "?"_s, '\0'), BUILTIN(clear, ""_s, '\0'), BUILTIN(goto, "L"_s, '\0'), BUILTIN(callfunc, "F"_s, '\0'), -- cgit v1.2.3-60-g2f50 From 60acf021bf412235cd5be550977bd8242c3bba2f Mon Sep 17 00:00:00 2001 From: Jesusalva Jesusalva Date: Fri, 6 Jan 2023 23:39:54 +0000 Subject: Make clear we do NOT accept AGPL contributions. --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1582527 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +We do NOT accept AGPL contributions. -- cgit v1.2.3-60-g2f50 From fd1b3431e44905b29d6313fb172240198f80f27a Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Sun, 22 Jan 2023 17:19:24 +0000 Subject: bSpeedCap --- src/map/map.hpp | 2 +- src/map/pc.cpp | 12 ++++++++++++ src/mmo/clif.t.hpp | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/map/map.hpp b/src/map/map.hpp index eddbfad..af074ba 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -188,7 +188,7 @@ struct map_session_data : block_list, SessionData MapName mapname_; Session *sess; // use this, you idiots! short to_x, to_y; - interval_t speed; + interval_t speed, speed_cap; Opt1 opt1; Opt2 opt2; Opt3 opt3; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 9e76ecf..9fd23b9 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1174,6 +1174,7 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->matk1 = 0; sd->matk2 = 0; sd->speed = DEFAULT_WALK_SPEED; + sd->speed_cap = interval_t::zero(); sd->hprate = 100; sd->sprate = 100; sd->dsprate = 100; @@ -1528,6 +1529,10 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->speed_rate != 100) sd->speed = sd->speed * sd->speed_rate / 100; sd->speed = std::max(sd->speed, 1_ms); + if (sd->speed_cap < interval_t::zero()) + sd->speed_cap = interval_t::zero(); + if (sd->speed < sd->speed_cap) + sd->speed = sd->speed_cap; /* Magic speed */ if (sd->attack_spell_override || first & 8) @@ -1829,6 +1834,12 @@ int pc_bonus(dumb_ptr sd, SP type, int val) case SP::DEAF: sd->special_state.deaf = 1; break; + case SP::SPEED_CAP: + if (!sd->state.lr_flag_is_arrow_2) + // lowest cap is taken others are ignored + if (sd->speed_cap < interval_t(val)) + sd->speed_cap = interval_t(val); + break; default: if (battle_config.error_log) PRINTF("pc_bonus: unknown type %d %d !\n"_fmt, @@ -1840,6 +1851,7 @@ int pc_bonus(dumb_ptr sd, SP type, int val) /*========================================== * ソスソス ソスソスソスiソスノゑソスソスソスソス\ソスヘ難ソスソスフボソス[ソスiソスXソスン抵ソス + * sos sos sos sos sos i sos no sos sos sos sos\ *------------------------------------------ */ int pc_bonus2(dumb_ptr sd, SP type, int type2, int val) diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp index 33a6f3c..830c5bd 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -472,6 +472,8 @@ enum class SP : uint16_t MUTE_PARTY = 1084, MUTE_GUILD = 1085, AUTOMOD = 1086, + + SPEED_CAP = 1087, }; constexpr -- cgit v1.2.3-60-g2f50 From caa16ae67a575078c4129ead6136a8f4db95ad36 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 9 Feb 2023 15:34:27 +0000 Subject: bAllStats, bAgiVit, bAgiDexStr, bDeadlyStrikeRate, bDeadlyStrikeAddRate --- src/map/atcommand.cpp | 12 ++- src/map/battle.cpp | 256 +++++++++++++++++++++++++++----------------------- src/map/map.hpp | 4 +- src/map/pc.cpp | 36 ++++++- src/mmo/clif.t.hpp | 8 ++ 5 files changed, 190 insertions(+), 126 deletions(-) diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index d7d47c9..b537431 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -2570,12 +2570,22 @@ ATCE atcommand_character_stats_full(Session *s, dumb_ptr, clif_displaymessage(s, output); output = STRPRINTF("PERFECT_HIT_RATE: %d | PERFECT_HIT_ADD_RATE: %d | CRITICAL: %d | CRITICAL_RATE: %d | HIT: %d | HIT_RATE: %d"_fmt, pl_sd->perfect_hit, - pl_sd->perfect_hit_add, + pl_sd->perfect_hit_add_rate, pl_sd->critical, pl_sd->critical_rate, pl_sd->hit, pl_sd->hit_rate); clif_displaymessage(s, output); + output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d"_fmt, + pl_sd->deadly_strike, + pl_sd->deadly_strike_add_rate); + clif_displaymessage(s, output); + output = STRPRINTF("arrow_atk: %d | arrow_cri: %d | arrow_hit: %d | arrow_range: %d"_fmt, + pl_sd->arrow_atk, + pl_sd->arrow_cri, + pl_sd->arrow_hit, + pl_sd->arrow_range); + clif_displaymessage(s, output); output = STRPRINTF("HP_DRAIN_RATE: %d | HP_DRAIN_RATE per: %d | SP_DRAIN_RATE: %d | SP_DRAIN_RATE per: %d"_fmt, pl_sd->hp_drain_rate, pl_sd->hp_drain_per, diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 3b7c6b2..eaa37a0 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -1469,7 +1469,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr src, ATK dmg_lv = ATK::ZERO; eptr sc_data, t_sc_data; int watk; - bool da = false; + bool da = false, ds = false; int ac_flag = 0; int target_distance; @@ -1482,7 +1482,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr src, sd->state.attack_type = BF::WEAPON; // 攻撃タイプは武器攻撃 | Attack type is weapon attack - // ターゲット + // ターゲット | target if (target->bl_type == BL::PC) // 対象がPCなら | If the target is a PC tsd = target->is_player(); // tsdに代入(tmdはNULL) | Assign to tsd (tmd is NULL) else if (target->bl_type == BL::MOB) // 対象がMobなら | If the target is a mob @@ -1575,143 +1575,154 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr src, if (atkmin > atkmax && !(sd->state.arrow_atk)) atkmin = atkmax; // 弓は最低が上回る場合あり | Bow may exceed minimum - if (sd->double_rate > 0 && skill_num == SkillID::ZERO && skill_lv >= 0) - da = random_::chance({sd->double_rate, 100}); - - if (!da) - { // ダブルアタックが発動していない | Double Attack is not activated - // クリティカル計算 | critical calculation - cri = battle_get_critical(src); - - if (sd->state.arrow_atk) - cri += sd->arrow_cri; - cri -= battle_get_luk(target) * 3; - if (ac_flag) - cri = 1000; - } - - if (tsd && tsd->critical_def) - cri = cri * (100 - tsd->critical_def) / 100; - else if (tmd && tmd->stats[mob_stat::CRITICAL_DEF]) - cri = cri * (100 - tmd->stats[mob_stat::CRITICAL_DEF]) / 100; + if (tmd && !bool(t_mode & MobMode::BOSS)) // deadly strike works only on mobs but not on mobs with boss flag + if (sd->deadly_strike > 0) + ds = random_::chance({sd->deadly_strike, 100}); - // ダブルアタックが発動していない | Double Attack is not activated - // 判定(スキルの場合は無視) | Judgment (ignored for skills) - if (!da && skill_num == SkillID::ZERO && skill_lv >= 0 - && random_::chance({cri, 1000})) + if (!ds) // no double, crit and normal damage calculation needed if it is a deadly strike { - damage += atkmax; - if (sd->atk_rate != 100) - { - damage = (damage * sd->atk_rate) / 100; - } - if (sd->state.arrow_atk) - damage += sd->arrow_atk; - type = DamageType::CRITICAL; - } - else - { - int vitbonusmax; + if (sd->double_rate > 0 && skill_num == SkillID::ZERO && skill_lv >= 0) + da = random_::chance({sd->double_rate, 100}); - if (atkmax > atkmin) - damage += random_::in(atkmin, atkmax); - else - damage += atkmin; - if (sd->atk_rate != 100) + if (!da) { - damage = (damage * sd->atk_rate) / 100; + // ダブルアタックが発動していない | Double Attack is not activated + // クリティカル計算 | critical calculation + cri = battle_get_critical(src); + + if (sd->state.arrow_atk) + cri += sd->arrow_cri; + cri -= battle_get_luk(target) * 3; + if (ac_flag) + cri = 1000; } - if (sd->state.arrow_atk) + if (tsd && tsd->critical_def) + cri = cri * (100 - tsd->critical_def) / 100; + else if (tmd && tmd->stats[mob_stat::CRITICAL_DEF]) + cri = cri * (100 - tmd->stats[mob_stat::CRITICAL_DEF]) / 100; + + // ダブルアタックが発動していない | Double Attack is not activated + // 判定(スキルの場合は無視) | Judgment (ignored for skills) + if (!da && skill_num == SkillID::ZERO && skill_lv >= 0 + && random_::chance({cri, 1000})) { - if (sd->arrow_atk > 0) - damage += random_::in(0, sd->arrow_atk); - hitrate += sd->arrow_hit; + damage += atkmax; + if (sd->atk_rate != 100) + { + damage = (damage * sd->atk_rate) / 100; + } + if (sd->state.arrow_atk) + damage += sd->arrow_atk; + type = DamageType::CRITICAL; } - - if (skill_num != SkillID::ZERO && skill_num != SkillID::NEGATIVE) + else { - flag = (flag & ~BF::SKILLMASK) | BF::SKILL; - } + int vitbonusmax; - { - // 対 象の防御力によるダメージの減少 | Decreased damage due to target's defense - // ディバインプロテクション(ここでいいのかな?) | Divine Protection (maybe here?) - if (def1 < 1000000) - { // DEF, VIT無視 | DEF, VIT ignore - int t_def; - target_count = - 1 + battle_counttargeted(target, src, - battle_config.vit_penaly_count_lv); - if (battle_config.vit_penaly_type > 0) - { - if (target_count >= battle_config.vit_penaly_count) + if (atkmax > atkmin) + damage += random_::in(atkmin, atkmax); + else + damage += atkmin; + if (sd->atk_rate != 100) + { + damage = (damage * sd->atk_rate) / 100; + } + + if (sd->state.arrow_atk) + { + if (sd->arrow_atk > 0) + damage += random_::in(0, sd->arrow_atk); + hitrate += sd->arrow_hit; + } + + if (skill_num != SkillID::ZERO && skill_num != SkillID::NEGATIVE) + { + flag = (flag & ~BF::SKILLMASK) | BF::SKILL; + } + + { + // 対 象の防御力によるダメージの減少 | Decreased damage due to target's defense + // ディバインプロテクション(ここでいいのかな?) | Divine Protection (maybe here?) + if (def1 < 1000000) + { // DEF, VIT無視 | DEF, VIT ignore + int t_def; + target_count = + 1 + battle_counttargeted(target, src, + battle_config.vit_penaly_count_lv); + if (battle_config.vit_penaly_type > 0) { - if (battle_config.vit_penaly_type == 1) + if (target_count >= battle_config.vit_penaly_count) { - def1 = - (def1 * - (100 - - (target_count - - (battle_config.vit_penaly_count - - 1)) * battle_config.vit_penaly_num)) / - 100; - def2 = - (def2 * - (100 - - (target_count - - (battle_config.vit_penaly_count - - 1)) * battle_config.vit_penaly_num)) / - 100; - t_vit = - (t_vit * - (100 - - (target_count - - (battle_config.vit_penaly_count - - 1)) * battle_config.vit_penaly_num)) / - 100; - } - else if (battle_config.vit_penaly_type == 2) - { - def1 -= - (target_count - - (battle_config.vit_penaly_count - - 1)) * battle_config.vit_penaly_num; - def2 -= - (target_count - - (battle_config.vit_penaly_count - - 1)) * battle_config.vit_penaly_num; - t_vit -= - (target_count - - (battle_config.vit_penaly_count - - 1)) * battle_config.vit_penaly_num; + if (battle_config.vit_penaly_type == 1) + { + def1 = + (def1 * + (100 - + (target_count - + (battle_config.vit_penaly_count - + 1)) * battle_config.vit_penaly_num)) / + 100; + def2 = + (def2 * + (100 - + (target_count - + (battle_config.vit_penaly_count - + 1)) * battle_config.vit_penaly_num)) / + 100; + t_vit = + (t_vit * + (100 - + (target_count - + (battle_config.vit_penaly_count - + 1)) * battle_config.vit_penaly_num)) / + 100; + } + else if (battle_config.vit_penaly_type == 2) + { + def1 -= + (target_count - + (battle_config.vit_penaly_count - + 1)) * battle_config.vit_penaly_num; + def2 -= + (target_count - + (battle_config.vit_penaly_count - + 1)) * battle_config.vit_penaly_num; + t_vit -= + (target_count - + (battle_config.vit_penaly_count - + 1)) * battle_config.vit_penaly_num; + } + if (def1 < 0) + def1 = 0; + if (def2 < 1) + def2 = 1; + if (t_vit < 1) + t_vit = 1; } - if (def1 < 0) - def1 = 0; - if (def2 < 1) - def2 = 1; - if (t_vit < 1) - t_vit = 1; } - } - t_def = def2 * 8 / 10; - vitbonusmax = (t_vit / 20) * (t_vit / 20) - 1; + t_def = def2 * 8 / 10; + vitbonusmax = (t_vit / 20) * (t_vit / 20) - 1; - { { - damage = damage * (100 - def1) / 100; - damage -= t_def; - if (vitbonusmax > 0) - damage -= random_::in(0, vitbonusmax); + { + damage = damage * (100 - def1) / 100; + damage -= t_def; + if (vitbonusmax > 0) + damage -= random_::in(0, vitbonusmax); + } } } } } + // 精錬ダメージの追加 | Add refining damage + { // DEF, VIT無視 | DEF, VIT ignore + damage += battle_get_atk2(src); + } } - // 精錬ダメージの追加 | Add refining damage - { // DEF, VIT無視 | DEF, VIT ignore - damage += battle_get_atk2(src); - } + else + if (sd->state.arrow_atk) + hitrate += sd->arrow_hit; // 0未満だった場合1に補正 | Corrected to 1 if less than 0 if (damage < 1) @@ -1743,6 +1754,15 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr src, if (damage < 0) damage = 0; + if (ds) + { + damage = tmd->hp; + //type = DamageType::DEADLY; + // M+ does not support this value on package 0x008a it lags a bit and displays an error message. + // This can be implemented if ManaVerse is the only supported client so long DamageType::CRITICAL will do + type = DamageType::CRITICAL; + } + // 右手,短剣のみ | right hand, dagger only if (da) { // ダブルアタックが発動しているか | Is double attack activated? diff --git a/src/map/map.hpp b/src/map/map.hpp index af074ba..a4295fd 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -259,10 +259,10 @@ struct map_session_data : block_list, SessionData int aspd_rate, speed_rate, hprecov_rate, sprecov_rate, critical_def, double_rate; int matk_rate; - int perfect_hit; + int perfect_hit, deadly_strike; int critical_rate, hit_rate, flee_rate, flee2_rate, def_rate, def2_rate, mdef_rate, mdef2_rate; - int double_add_rate, speed_add_rate, aspd_add_rate, perfect_hit_add; + int double_add_rate, speed_add_rate, aspd_add_rate, perfect_hit_add_rate, deadly_strike_add_rate; short hp_drain_rate, hp_drain_per, sp_drain_rate, sp_drain_per; int die_counter; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 9fd23b9..3e8cd6e 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1193,11 +1193,11 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->double_rate = 0; sd->atk_rate = sd->matk_rate = 100; sd->arrow_cri = 0; - sd->perfect_hit = 0; + sd->perfect_hit = sd->deadly_strike = 0; sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100; sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100; sd->speed_add_rate = sd->aspd_add_rate = 100; - sd->double_add_rate = sd->perfect_hit_add = 0; + sd->double_add_rate = sd->perfect_hit_add_rate = sd->deadly_strike_add_rate = 0; sd->hp_drain_rate = sd->hp_drain_per = sd->sp_drain_rate = sd->sp_drain_per = 0; @@ -1328,7 +1328,8 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->status.weapon == ItemLook::BOW) sd->attackrange += sd->arrow_range; sd->double_rate += sd->double_add_rate; - sd->perfect_hit += sd->perfect_hit_add; + sd->perfect_hit += sd->perfect_hit_add_rate; + sd->deadly_strike += sd->deadly_strike_add_rate; if (sd->speed_add_rate != 100) sd->speed_rate += sd->speed_add_rate - 100; if (sd->aspd_add_rate != 100) @@ -1797,7 +1798,7 @@ int pc_bonus(dumb_ptr sd, SP type, int val) break; case SP::PERFECT_HIT_ADD_RATE: if (!sd->state.lr_flag_is_arrow_2) - sd->perfect_hit_add += val; + sd->perfect_hit_add_rate += val; break; case SP::CRITICAL_RATE: if (!sd->state.lr_flag_is_arrow_2) @@ -1836,10 +1837,35 @@ int pc_bonus(dumb_ptr sd, SP type, int val) break; case SP::SPEED_CAP: if (!sd->state.lr_flag_is_arrow_2) - // lowest cap is taken others are ignored + // highest value (slowest speed) is taken others are ignored if (sd->speed_cap < interval_t(val)) sd->speed_cap = interval_t(val); break; + case SP::ALL_STATS: + sd->parame[ATTR::STR] += val; + sd->parame[ATTR::AGI] += val; + sd->parame[ATTR::VIT] += val; + sd->parame[ATTR::INT] += val; + sd->parame[ATTR::DEX] += val; + sd->parame[ATTR::LUK] += val; + break; + case SP::AGI_VIT: + sd->parame[ATTR::AGI] += val; + sd->parame[ATTR::VIT] += val; + break; + case SP::AGI_DEX_STR: + sd->parame[ATTR::AGI] += val; + sd->parame[ATTR::DEX] += val; + sd->parame[ATTR::STR] += val; + break; + case SP::DEADLY_STRIKE_RATE: + if (!sd->state.lr_flag_is_arrow_2 && sd->deadly_strike < val) + sd->deadly_strike = val; + break; + case SP::DEADLY_STRIKE_ADD_RATE: + if (!sd->state.lr_flag_is_arrow_2) + sd->deadly_strike_add_rate += val; + break; default: if (battle_config.error_log) PRINTF("pc_bonus: unknown type %d %d !\n"_fmt, diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp index 830c5bd..e92c349 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -153,6 +153,7 @@ enum class DamageType : uint8_t DOUBLED = 0x08, CRITICAL = 0x0a, FLEE2 = 0x0b, + DEADLY = 0x0c, }; enum class LOOK : uint8_t @@ -474,6 +475,13 @@ enum class SP : uint16_t AUTOMOD = 1086, SPEED_CAP = 1087, + + ALL_STATS = 1088, + AGI_VIT = 1089, + AGI_DEX_STR = 1090, + + DEADLY_STRIKE_RATE = 1091, + DEADLY_STRIKE_ADD_RATE = 1092, }; constexpr -- cgit v1.2.3-60-g2f50 From 7980f4d21956314e284448f7dcedd58f9c23b355 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Mon, 3 Apr 2023 01:58:15 +0000 Subject: Item mode --- src/ast/item.cpp | 1 + src/ast/item.hpp | 2 ++ src/map/clif.cpp | 11 +++++++++++ src/map/itemdb.cpp | 1 + src/map/itemdb.hpp | 2 ++ src/map/npc.cpp | 7 ++++++- src/map/storage.cpp | 6 ++++++ src/mmo/enums.hpp | 15 +++++++++++++++ src/mmo/extract_enums.hpp | 3 +++ 9 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/ast/item.cpp b/src/ast/item.cpp index d27e231..623f5c6 100644 --- a/src/ast/item.cpp +++ b/src/ast/item.cpp @@ -142,6 +142,7 @@ namespace item SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), item.wlv); SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), item.elv); SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), item.view); + SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), item.mode); item.use_script = TRY(lex_script(lr)); item.equip_script = TRY(lex_script(lr)); ItemOrComment rv = std::move(item); diff --git a/src/ast/item.hpp b/src/ast/item.hpp index c772655..90d51a1 100644 --- a/src/ast/item.hpp +++ b/src/ast/item.hpp @@ -63,6 +63,8 @@ namespace item Spanned wlv; Spanned elv; Spanned view; + Spanned mode; + ast::script::ScriptBody use_script; ast::script::ScriptBody equip_script; }; diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 0eb2b8c..e81a510 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -4617,6 +4617,11 @@ RecvResult clif_parse_DropItem(Session *s, dumb_ptr sd) clif_displaymessage(sd->sess, "Can't drop items here."_s); return rv; } + if (bool(itemdb_search(sd->status.inventory[fixed.ioff2.unshift()].nameid)->mode & ItemMode::NO_DROP)) + { + clif_displaymessage(sd->sess, "This item can't be dropped."_s); + return rv; + } if (sd->npc_id || sd->opt1 != Opt1::ZERO) { @@ -4895,6 +4900,12 @@ RecvResult clif_parse_TradeAddItem(Session *s, dumb_ptr sd) if (fixed.zeny_or_ioff2.index != 0 && !fixed.zeny_or_ioff2.ok()) return RecvResult::Error; + if (fixed.zeny_or_ioff2.ok()) + if (bool(itemdb_search(sd->status.inventory[fixed.zeny_or_ioff2.unshift()].nameid)->mode & ItemMode::NO_TRADE)) + { + clif_displaymessage(sd->sess, "This item can't be traded."_s); + return rv; + } trade_tradeadditem(sd, fixed.zeny_or_ioff2, fixed.amount); return rv; diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index 7b23503..fa675d2 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -201,6 +201,7 @@ bool itemdb_readdb(ZString filename) idv.wlv = item.wlv.data; idv.elv = item.elv.data; idv.look = item.view.data; + idv.mode = item.mode.data; idv.use_script = compile_script(STRPRINTF("use script %d"_fmt, idv.nameid), item.use_script, true); idv.equip_script = compile_script(STRPRINTF("equip script %d"_fmt, idv.nameid), item.equip_script, true); diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 19f40a8..10805f5 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -50,6 +50,8 @@ struct item_data ItemLook look; int elv; int wlv; + ItemMode mode; + std::unique_ptr use_script; std::unique_ptr equip_script; }; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 4d9a8d1..ee2f30c 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -993,6 +993,12 @@ int npc_selllist(dumb_ptr sd, if (!nameid || sd->status.inventory[item_list[i].ioff2.unshift()].amount < item_list[i].count) return 1; + if (bool(itemdb_search(nameid)->mode & ItemMode::NO_SELL_TO_NPC)) + { + //clif_displaymessage(sd->sess, "This item can't be sold to an NPC."_s); + // M+ already outputs "Unable to sell unsellable item." on return value 3. + return 3; + } if (sd->trade_partner) return 2; // cant sell while trading z += static_cast(itemdb_value_sell(nameid)) * item_list[i].count; @@ -1009,7 +1015,6 @@ int npc_selllist(dumb_ptr sd, } return 0; - } static diff --git a/src/map/storage.cpp b/src/map/storage.cpp index 1327146..54398f3 100644 --- a/src/map/storage.cpp +++ b/src/map/storage.cpp @@ -186,6 +186,12 @@ int storage_storageadd(dumb_ptr sd, IOff0 index, int amount) if (amount < 1 || amount > sd->status.inventory[index].amount) return 0; + if (bool(itemdb_search(sd->status.inventory[index].nameid)->mode & ItemMode::NO_STORAGE)) + { + clif_displaymessage(sd->sess, "This item can't be stored."_s); + return 0; + } + // log_tostorage(sd, index, 0); if (storage_additem(sd, stor, &sd->status.inventory[index], amount) == 0) { diff --git a/src/mmo/enums.hpp b/src/mmo/enums.hpp index 2564ec9..12c82ca 100644 --- a/src/mmo/enums.hpp +++ b/src/mmo/enums.hpp @@ -107,6 +107,20 @@ enum class ItemLook : uint16_t COUNT = 17, }; +namespace e +{ +enum class ItemMode : uint8_t +{ + NONE = 0, + NO_DROP = 1, + NO_TRADE = 2, + NO_SELL_TO_NPC = 4, + NO_STORAGE = 8, +}; +ENUM_BITWISE_OPERATORS(ItemMode) +} +using e::ItemMode; + enum class SEX : uint8_t { FEMALE = 0, @@ -117,6 +131,7 @@ enum class SEX : uint8_t NEUTRAL = 3, __OTHER = 4, // used in ManaPlus only }; + inline char sex_to_char(SEX sex) { diff --git a/src/mmo/extract_enums.hpp b/src/mmo/extract_enums.hpp index 0e8ac4c..14e7b17 100644 --- a/src/mmo/extract_enums.hpp +++ b/src/mmo/extract_enums.hpp @@ -35,6 +35,7 @@ enum class EPOS : uint16_t; enum class Opt1 : uint16_t; enum class Opt2 : uint16_t; enum class Opt0 : uint16_t; +enum class ItemMode : uint8_t; inline bool impl_extract(XString str, EPOS *iv) { return extract_as_int(str, iv); } @@ -44,6 +45,8 @@ inline bool impl_extract(XString str, Opt2 *iv) { return extract_as_int(str, iv); } inline bool impl_extract(XString str, Opt0 *iv) { return extract_as_int(str, iv); } +inline +bool impl_extract(XString str, ItemMode *iv) { return extract_as_int(str, iv); } } // namespace e enum class ItemLook : uint16_t; -- cgit v1.2.3-60-g2f50 From b261d1a65d264dadd3b0e25ac1a99fa5cbe29eeb Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Tue, 4 Apr 2023 17:36:30 +0200 Subject: SC_COOLDOWN_UPMARMU --- src/map/script-fun.cpp | 1 + src/map/skill.cpp | 2 ++ src/mmo/skill.t.hpp | 1 + 3 files changed, 4 insertions(+) diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 1788570..fd3f798 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3888,6 +3888,7 @@ void builtin_sc_start(ScriptState *st) case StatusChange::SC_COOLDOWN_AR: case StatusChange::SC_COOLDOWN_ENCH: case StatusChange::SC_COOLDOWN_KOY: + case StatusChange::SC_COOLDOWN_UPMARMU: break; default: diff --git a/src/map/skill.cpp b/src/map/skill.cpp index cdaa0ba..0fcf505 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -764,6 +764,7 @@ void skill_status_change_end(dumb_ptr bl, StatusChange type, TimerDa case StatusChange::SC_COOLDOWN_AR: case StatusChange::SC_COOLDOWN_ENCH: case StatusChange::SC_COOLDOWN_KOY: + case StatusChange::SC_COOLDOWN_UPMARMU: break; /* option2 */ @@ -1041,6 +1042,7 @@ int skill_status_effect(dumb_ptr bl, StatusChange type, case StatusChange::SC_COOLDOWN_AR: case StatusChange::SC_COOLDOWN_ENCH: case StatusChange::SC_COOLDOWN_KOY: + case StatusChange::SC_COOLDOWN_UPMARMU: break; case StatusChange::SC_FLYING_BACKPACK: updateflag = SP::WEIGHT; diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp index 1509852..782980c 100644 --- a/src/mmo/skill.t.hpp +++ b/src/mmo/skill.t.hpp @@ -59,6 +59,7 @@ enum class StatusChange : uint16_t SC_COOLDOWN_AR = 75, // Frillyar cooldown SC_COOLDOWN_ENCH = 76, // Enchanter cooldown SC_COOLDOWN_KOY = 77, // Koyntety cooldown + SC_COOLDOWN_UPMARMU = 78, // Upmarmu cooldown SC_POISON = 132, // bad; actually used -- cgit v1.2.3-60-g2f50 From 2a192a61bbccded0a4ae2ac0cef12e8138202fcf Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Sat, 10 Jun 2023 06:08:06 +0000 Subject: Backport Maxlvl --- src/map/pc.cpp | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 3e8cd6e..5196f16 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -149,49 +149,60 @@ earray aspd_base_0 //= static const int exp_table_0[MAX_LEVEL] = { - // 1 .. 9 + // 1 .. 10 9, 16, 25, 36, 77, 112, 153, 200, 253, - // 10 .. 19 + // 11 .. 20 320, 385, 490, 585, 700, 830, 970, 1120, 1260, 1420, - // 20 .. 29 + // 21 .. 30 1620, 1860, 1990, 2240, 2504, 2950, 3426, 3934, 4474, 6889, - // 30 .. 39 + // 31 .. 40 7995, 9174, 10425, 11748, 13967, 15775, 17678, 19677, 21773, 30543, - // 40 .. 49 + // 41 .. 50 34212, 38065, 42102, 46323, 53026, 58419, 64041, 69892, 75973, 102468, - // 50 .. 59 + // 51 .. 60 115254, 128692, 142784, 157528, 178184, 196300, 215198, 234879, 255341, 330188, - // 60 .. 69 + // 61 .. 70 365914, 403224, 442116, 482590, 536948, 585191, 635278, 687211, 740988, 925400, - // 70 .. 79 + // 71 .. 80 1473746, 1594058, 1718928, 1848355, 1982340, 2230113, 2386162, 2547417, 2713878, 3206160, - // 80 .. 89 + // 81 .. 90 3681024, 4022472, 4377024, 4744680, 5125440, 5767272, 6204000, 6655464, 7121664, 7602600, - // 90 .. 99 + // 91 .. 100 9738720, 11649960, 13643520, 18339300, 23836800, 35658000, 48687000, 58135000, 99999999, 103000000, - // 100 .. 109 + // 101 .. 110 107000000, 112000000, 116000000, 121000000, 125000000, 130000000, 134000000, 139000000, 145000000, 152200000, - // 110 .. 119 + // 111 .. 120 160840000, 171200000, 191930000, 202290000, 214720000, 229640000, 247550000, 283370000, 301280000, 322770000, - // 120 .. 129 + // 121 .. 130 348560000, 379500000, 417450000, 459195000, 505114500, 555625950, 622301064, 696977191, 780614454, 880533104, - // 130 .. 135 - 993241342, 1120376234, 1263784392, 1425548794, 1608019039, - 2147483647, 0 + // 131 .. 140 + 993241342, 1120376234, 1263784392, 1425548794, 1588019039, + 1680000000, 1780000000, 1890000000, 2010000000, 2140000000, + // 141 + 0 }; +// The old table contained a bug, actually max level was 136 and not 135 but to reach level 136 you must hit exactly the value 2147483647 +// else and overflow occurs and you lose all the progress of that level and start with level 135 at 0% again. +// I made a buffer that is great enough now I guess its 7483647 while looking through all gm logs I saw the highest values ever where 300%. +// A Xakelbael killed on 300% exp one time tabbed gives around 6 mil so I have a little buffer on top of that as well, it won't make it for +// 400% exp but since this will most likely never happen and the chance that one will make his lvl up with Xakelbael one time tabbed +// is extremely rare as well. + // 130 .. 135 + //993241342, 1120376234, 1263784392, 1425548794, 1608019039, + //2147483647, 0 // is this *actually* used anywhere? static const -- cgit v1.2.3-60-g2f50 From 28f1cdc73799c43f4112f524a64fa6d3b26ba696 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 3 Aug 2023 04:21:22 +0000 Subject: weapon base attack delay standardization --- src/ast/item_test.cpp | 2 +- src/char/char.cpp | 2 +- src/map/atcommand.cpp | 5 ++-- src/map/battle.cpp | 4 +-- src/map/clif.cpp | 2 +- src/map/map.hpp | 2 +- src/map/pc.cpp | 75 ++++++++++++++++++++++++++++++--------------------- src/mmo/clif.t.hpp | 2 ++ src/mmo/enums.hpp | 31 ++++++++++++++++----- 9 files changed, 81 insertions(+), 44 deletions(-) diff --git a/src/ast/item_test.cpp b/src/ast/item_test.cpp index 7bb7193..7e5f1a9 100644 --- a/src/ast/item_test.cpp +++ b/src/ast/item_test.cpp @@ -135,7 +135,7 @@ namespace item EXPECT_SPAN(p->elv.span, 1,42, 1,43); EXPECT_EQ(p->elv.data, 13); EXPECT_SPAN(p->view.span, 1,45, 1,46); - EXPECT_EQ(p->view.data, ItemLook::BOW); + EXPECT_EQ(p->view.data, ItemLook::W_BOW); EXPECT_SPAN(p->use_script.span, 1,49, 1,54); EXPECT_EQ(p->use_script.braced_body, "{end;}"_s); EXPECT_SPAN(p->equip_script.span, 1,57, 1,58); diff --git a/src/char/char.cpp b/src/char/char.cpp index 8b403b3..70ad049 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -746,7 +746,7 @@ CharPair *make_new_char(Session *s, CharName name, const Stats6& stats, uint8_t cd.hair_color = hair_color; cd.clothes_color = 0; // removed initial armor/weapon - unused and problematic - cd.weapon = ItemLook::NONE; + cd.weapon = ItemLook::W_FIST; cd.shield = ItemNameId(); cd.head_top = ItemNameId(); cd.head_mid = ItemNameId(); diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index b537431..8c0eb90 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -2576,9 +2576,10 @@ ATCE atcommand_character_stats_full(Session *s, dumb_ptr, pl_sd->hit, pl_sd->hit_rate); clif_displaymessage(s, output); - output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d"_fmt, + output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d | BASE_WEAPON_DELAY_ADJUST: %d"_fmt, pl_sd->deadly_strike, - pl_sd->deadly_strike_add_rate); + pl_sd->deadly_strike_add_rate, + pl_sd->base_weapon_delay_adjust.count()); clif_displaymessage(s, output); output = STRPRINTF("arrow_atk: %d | arrow_cri: %d | arrow_hit: %d | arrow_range: %d"_fmt, pl_sd->arrow_atk, diff --git a/src/map/battle.cpp b/src/map/battle.cpp index eaa37a0..b745e05 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -1561,7 +1561,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr src, } OMATCH_END (); } - if (sd->status.weapon == ItemLook::BOW) + if (sd->status.weapon == ItemLook::W_BOW) { // 武器が弓矢の場合 | If the weapon is a bow and arrow atkmin = watk * ((atkmin < watk) ? atkmin : watk) / 100; // 弓用最低ATK計算 | Bows are calculated with minimum ATK flag = (flag & ~BF::RANGEMASK) | BF::LONG; // 遠距離攻撃フラグを有効 | Enable ranged attack flag @@ -2058,7 +2058,7 @@ ATK battle_weapon_attack(dumb_ptr src, dumb_ptr target, battle_check_range(src, target, 0)) { // 攻撃対象となりうるので攻撃 | Attack because it can be attacked - if (sd && sd->status.weapon == ItemLook::BOW) + if (sd && sd->status.weapon == ItemLook::W_BOW) { IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW]; if (aidx.ok()) diff --git a/src/map/clif.cpp b/src/map/clif.cpp index e81a510..9edf2af 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -3762,7 +3762,7 @@ RecvResult clif_parse_LoadEndAck(Session *s, dumb_ptr sd) clif_equiplist(sd); clif_initialstatus(sd); clif_changeoption(sd); - clif_changelook(sd, LOOK::WEAPON, static_cast(ItemLook::NONE)); + clif_changelook(sd, LOOK::WEAPON, static_cast(ItemLook::W_FIST)); clif_updatestatus(sd, SP::MAXWEIGHT); clif_updatestatus(sd, SP::WEIGHT); npc_event_doall_l(stringish("OnPCLoginEvent"_s), sd->bl_id, nullptr); diff --git a/src/map/map.hpp b/src/map/map.hpp index a4295fd..659ed2d 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -248,7 +248,7 @@ struct map_session_data : block_list, SessionData ItemLook weapontype1; earray paramb, paramc, parame, paramcard; int hit, flee, flee2; - interval_t aspd, amotion, dmotion; + interval_t aspd, amotion, dmotion, base_weapon_delay_adjust; int watk, watk2; int def, def2, mdef, mdef2, critical, matk1, matk2; int hprate, sprate, dsprate; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 5196f16..63c7614 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -127,23 +127,30 @@ int sp_coefficient_0 = 100; static //const earray aspd_base_0 //= {{ -650_ms, // 0 NONE -700_ms, // 1 BLADE or some other common weapons -750_ms, // 2 -610_ms, // 3 SETZER_AND_SCYTHE -2000_ms, // 4 -2000_ms, // 5 -800_ms, // 6 Falchion -2000_ms, // 7 -700_ms, // 8 -700_ms, // 9 -650_ms, //10 STAFF / Sandcutter -900_ms, //11 BOW -2000_ms, //12 -2000_ms, //13 -2000_ms, //14 -2000_ms, //15 -2000_ms, //16 + 550_ms, // 0 { "Fist", W_FIST }, + 600_ms, // 1 { "Dagger", W_DAGGER }, + 650_ms, // 2 { "Sword", W_1HSWORD }, + 700_ms, // 3 { "TwoHandSword", W_2HSWORD }, + 650_ms, // 4 { "Spear", W_1HSPEAR }, + 700_ms, // 5 { "TwoHandSpear", W_2HSPEAR }, + 700_ms, // 6 { "Axe", W_1HAXE }, + 750_ms, // 7 { "TwoHandAxe", W_2HAXE }, + 700_ms, // 8 { "Mace", W_MACE }, + 750_ms, // 9 { "TwoHandMace", W_2HMACE }, + 700_ms, // 10 { "Rod", W_STAFF }, + 800_ms, // 11 { "Bow", W_BOW }, + 575_ms, // 12 { "Knuckle", W_KNUCKLE }, + 800_ms, // 13 { "Instrument", W_MUSICAL }, + 675_ms, // 14 { "Whip", W_WHIP }, + 700_ms, // 15 { "Book", W_BOOK }, + 600_ms, // 16 { "Katar", W_KATAR }, + 600_ms, // 17 { "Revolver", W_REVOLVER }, + 800_ms, // 18 { "Rifle", W_RIFLE }, + 500_ms, // 19 { "GatlingGun", W_GATLING }, + 1000_ms, // 20 { "Shotgun", W_SHOTGUN }, + 2000_ms, // 21 { "GrenadeLauncher", W_GRENADE }, + 650_ms, // 22 { "FuumaShuriken", W_HUUMA }, + 750_ms, // 23 { "TwoHandRod", W_2HSTAFF }, }}; static const @@ -204,6 +211,7 @@ int exp_table_0[MAX_LEVEL] = //993241342, 1120376234, 1263784392, 1425548794, 1608019039, //2147483647, 0 + // is this *actually* used anywhere? static const int exp_table_7[MAX_LEVEL] = @@ -705,7 +713,7 @@ int pc_setequipindex(dumb_ptr sd) } OMATCH_CASE_NONE () { - sd->weapontype1 = ItemLook::NONE; + sd->weapontype1 = ItemLook::W_FIST; } } OMATCH_END (); @@ -842,7 +850,7 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version, sd->state.connect_new = 1; sd->bl_prev = sd->bl_next = nullptr; - sd->weapontype1 = ItemLook::NONE; + sd->weapontype1 = ItemLook::W_FIST; sd->speed = DEFAULT_WALK_SPEED; sd->state.dead_sit = 0; sd->dir = DIR::S; @@ -1130,7 +1138,7 @@ int pc_calcstatus(dumb_ptr sd, int first) earray b_skill = sd->status.skill; b_hit = sd->hit; b_flee = sd->flee; - interval_t b_aspd = sd->aspd; + interval_t b_aspd = sd->aspd, b_base_weapon_delay_adjust = interval_t::zero(); b_watk = sd->watk; b_def = sd->def; b_watk2 = sd->watk2; @@ -1172,7 +1180,7 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->flee = 0; sd->flee2 = 0; sd->critical = 0; - sd->aspd = interval_t::zero(); + sd->aspd = sd->base_weapon_delay_adjust = interval_t::zero(); sd->watk = 0; sd->def = 0; sd->mdef = 0; @@ -1336,7 +1344,7 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->attackrange < 1) sd->attackrange = 1; - if (sd->status.weapon == ItemLook::BOW) + if (sd->status.weapon == ItemLook::W_BOW) sd->attackrange += sd->arrow_range; sd->double_rate += sd->double_add_rate; sd->perfect_hit += sd->perfect_hit_add_rate; @@ -1354,7 +1362,7 @@ int pc_calcstatus(dumb_ptr 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) + if (sd->status.weapon == ItemLook::W_BOW) { str = sd->paramc[ATTR::DEX]; dex = sd->paramc[ATTR::STR]; @@ -1448,9 +1456,12 @@ int pc_calcstatus(dumb_ptr sd, int first) //二刀流 ASPD 修正 | Two-cut ASPD correction { - sd->aspd += aspd_base_0[sd->status.weapon] + b_base_weapon_delay_adjust = aspd_base_0[sd->status.weapon] + sd->base_weapon_delay_adjust; + if (b_base_weapon_delay_adjust.count() < 0) + b_base_weapon_delay_adjust = interval_t::zero(); + sd->aspd += b_base_weapon_delay_adjust - (sd->paramc[ATTR::AGI] * 4 + sd->paramc[ATTR::DEX]) - * aspd_base_0[sd->status.weapon] / 1000; + * b_base_weapon_delay_adjust / 1000; } aspd_rate = sd->aspd_rate; @@ -1877,6 +1888,10 @@ int pc_bonus(dumb_ptr sd, SP type, int val) if (!sd->state.lr_flag_is_arrow_2) sd->deadly_strike_add_rate += val; break; + case SP::BASE_WEAPON_DELAY_ADJUST: + if (!sd->state.lr_flag_is_arrow_2) + sd->base_weapon_delay_adjust += interval_t(val); + break; default: if (battle_config.error_log) PRINTF("pc_bonus: unknown type %d %d !\n"_fmt, @@ -2897,7 +2912,7 @@ void pc_attack_timer(TimerData *, tick_t tick, BlockId id) { dist = distance(sd->bl_x, sd->bl_y, bl->bl_x, bl->bl_y); range = sd->attackrange; - if (sd->status.weapon != ItemLook::BOW) + if (sd->status.weapon != ItemLook::W_BOW) range++; if (dist > range) { //届 かないので移動 | Move because it does not arrive @@ -4829,11 +4844,11 @@ int pc_equipitem(dumb_ptr sd, IOff0 n, EPOS) sd->status.inventory[n].equip = pos; ItemNameId view_i; - ItemLook view_l = ItemLook::NONE; + ItemLook view_l = ItemLook::W_FIST; // TODO: This is ugly. OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[n]) { - bool look_not_weapon = sdidn->look == ItemLook::NONE; + bool look_not_weapon = sdidn->look == ItemLook::W_FIST; bool equip_is_weapon = bool(sd->status.inventory[n].equip & EPOS::WEAPON); assert (look_not_weapon != equip_is_weapon); @@ -4922,9 +4937,9 @@ int pc_unequipitem(dumb_ptr sd, IOff0 n, CalcStatus type) } if (bool(sd->status.inventory[n].equip & EPOS::WEAPON)) { - sd->weapontype1 = ItemLook::NONE; + sd->weapontype1 = ItemLook::W_FIST; // when reading the diff, think twice about this - sd->status.weapon = ItemLook::NONE; + sd->status.weapon = ItemLook::W_FIST; pc_calcweapontype(sd); pc_set_weapon_look(sd); } diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp index e92c349..1d61070 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -482,6 +482,8 @@ enum class SP : uint16_t DEADLY_STRIKE_RATE = 1091, DEADLY_STRIKE_ADD_RATE = 1092, + + BASE_WEAPON_DELAY_ADJUST = 1093, }; constexpr diff --git a/src/mmo/enums.hpp b/src/mmo/enums.hpp index 12c82ca..c4a1b17 100644 --- a/src/mmo/enums.hpp +++ b/src/mmo/enums.hpp @@ -99,12 +99,31 @@ constexpr ATTR ATTRs[6] = enum class ItemLook : uint16_t { - NONE = 0, - BLADE = 1, // or some other common weapons - SETZER_AND_SCYTHE = 3, - STAFF = 10, - BOW = 11, - COUNT = 17, + W_FIST, // 0 Fist + W_DAGGER, // 1 Dagger + W_1HSWORD, // 2 Sword + W_2HSWORD, // 3 TwoHandSword + W_1HSPEAR, // 4 Spear + W_2HSPEAR, // 5 TwoHandSpear + W_1HAXE, // 6 Axe + W_2HAXE, // 7 TwoHandAxe + W_MACE, // 8 Mace + W_2HMACE, // 9 TwoHandMace + W_STAFF, // 10 Rod + W_BOW, // 11 Bow + W_KNUCKLE, // 12 Knuckle + W_MUSICAL, // 13 Instrument + W_WHIP, // 14 Whip + W_BOOK, // 15 Book + W_KATAR, // 16 Katar + W_REVOLVER, // 17 Revolver + W_RIFLE, // 18 Rifle + W_GATLING, // 19 GatlingGun + W_SHOTGUN, // 20 Shotgun + W_GRENADE, // 21 GrenadeLauncher + W_HUUMA, // 22 FuumaShuriken + W_2HSTAFF, // 23 TwoHandRod + COUNT, }; namespace e -- cgit v1.2.3-60-g2f50 From c3ee6602842e60509342869a92eadf8cb4d0dc9e Mon Sep 17 00:00:00 2001 From: Led Mitz Date: Mon, 28 Aug 2023 23:45:06 +0000 Subject: Revert magic attack delay to original behaviour --- src/map/pc.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 63c7614..d496c5f 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1106,10 +1106,11 @@ void pc_set_weapon_look(dumb_ptr sd) * Actively changed parameters should be send on their own * * First is a bitmask - * &1 = ? - * &2 = ? - * &4 = ? - * &8 = magic override + * &0 = Status Recalculation | ステータス再計算 + * &1 = Status initial calculation, etc.| ステータス初期計算など + * &2 = Recalculate item bonus (used in pc_checkitem but not handled in this function atm, so if function is called with first = 2 its basically first = 0 only) + * &4 = Status Recalculation but don't use any clif_updatestatus to send status to client (used by map_quit) + * &8 = magic override (used in pc_set_attack_info) *------------------------------------------ */ int pc_calcstatus(dumb_ptr sd, int first) @@ -1556,14 +1557,13 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->speed_cap = interval_t::zero(); if (sd->speed < sd->speed_cap) sd->speed = sd->speed_cap; + if (aspd_rate != 100) + sd->aspd = sd->aspd * aspd_rate / 100; /* Magic speed */ if (sd->attack_spell_override || first & 8) sd->aspd = sd->attack_spell_delay; - if (aspd_rate != 100) - sd->aspd = sd->aspd * aspd_rate / 100; - /* Red Threshold Calculation (TODO) */ if (sd->aspd < 300_ms) { sd->aspd = 300_ms + ((sd->aspd - 300_ms) * 20 / 20); @@ -1581,12 +1581,12 @@ int pc_calcstatus(dumb_ptr sd, int first) if (first & 4) return 0; - if (first & 3) + if (first & 3) // never executed atm { clif_updatestatus(sd, SP::SPEED); clif_updatestatus(sd, SP::MAXHP); clif_updatestatus(sd, SP::MAXSP); - if (first & 1) + if (first & 1) // its always 1 here if first is 3 so this if is not needed normally { clif_updatestatus(sd, SP::HP); clif_updatestatus(sd, SP::SP); -- cgit v1.2.3-60-g2f50 From 7ba51de96d337fa4f00983ca5c018b9fee780f49 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Wed, 8 Nov 2023 02:57:42 +0000 Subject: SC_MATKPOT --- src/map/pc.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index d496c5f..ea15910 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1378,6 +1378,13 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->base_atk += str + dstr * dstr + dex / 5 + sd->paramc[ATTR::LUK] / 5; sd->matk1 += sd->paramc[ATTR::INT] + (sd->paramc[ATTR::INT] / 5) * (sd->paramc[ATTR::INT] / 5); sd->matk2 += sd->paramc[ATTR::INT] + (sd->paramc[ATTR::INT] / 7) * (sd->paramc[ATTR::INT] / 7); + + if (sd->sc_data[StatusChange::SC_MATKPOT].timer) + { + sd->matk1 += sd->sc_data[StatusChange::SC_MATKPOT].val1; + sd->matk2 += sd->sc_data[StatusChange::SC_MATKPOT].val1; + } + if (sd->matk1 < sd->matk2) { int temp = sd->matk2; @@ -1532,11 +1539,6 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->sc_data[StatusChange::SC_ATKPOT].timer) sd->watk += sd->sc_data[StatusChange::SC_ATKPOT].val1; - if (sd->sc_data[StatusChange::SC_MATKPOT].timer) - { - sd->matk1 += sd->sc_data[StatusChange::SC_MATKPOT].val1; - sd->matk2 += sd->sc_data[StatusChange::SC_MATKPOT].val1; - } if (sd->sc_data[StatusChange::SC_SPEEDPOTION0].timer) aspd_rate -= sd->sc_data[StatusChange::SC_SPEEDPOTION0].val1; -- cgit v1.2.3-60-g2f50 From d429a96fcc021df6a643be2b57a0bd80062aa7d6 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Sun, 12 Nov 2023 23:24:45 +0000 Subject: Update ProprietaryHub link. git:// was likely waiting indefinetely for user to login. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index a07e803..931035d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "deps/attoconf"] path = deps/attoconf - url = git://github.com/o11c/attoconf.git + url = https://github.com/o11c/attoconf.git -- cgit v1.2.3-60-g2f50 From 78ad8bcab7a0d29200e8cd47c1d759d0eeb15a72 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Mon, 27 Nov 2023 13:47:32 +0000 Subject: activity checks and status cleanup --- src/map/atcommand.cpp | 28 +++--- src/map/chrif.cpp | 2 +- src/map/map.cpp | 2 +- src/map/map.hpp | 9 ++ src/map/map.t.hpp | 2 +- src/map/mob.cpp | 253 ++++++++++++++++++++++++++++++++++-------------- src/map/pc.cpp | 103 ++++++++++++++------ src/map/pc.t.hpp | 10 ++ src/map/script-fun.cpp | 21 +++- src/map/skill-pools.cpp | 4 +- src/map/skill.cpp | 4 +- src/mmo/clif.t.hpp | 6 ++ 12 files changed, 318 insertions(+), 126 deletions(-) diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 8c0eb90..eaefd4f 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1270,7 +1270,7 @@ ATCE atcommand_option(Session *s, dumb_ptr sd, sd->status.option = param3; clif_changeoption(sd); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Options changed."_s); return ATCE::OKAY; @@ -1532,7 +1532,7 @@ ATCE atcommand_baselevelup(Session *s, dumb_ptr sd, clif_updatestatus(sd, SP::BASELEVEL); clif_updatestatus(sd, SP::NEXTBASEEXP); clif_updatestatus(sd, SP::STATUSPOINT); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); pc_heal(sd, sd->status.max_hp, sd->status.max_sp); clif_misceffect(sd, 0); clif_displaymessage(s, "Base level raised."_s); @@ -1560,7 +1560,7 @@ ATCE atcommand_baselevelup(Session *s, dumb_ptr sd, sd->status.base_level += level; clif_updatestatus(sd, SP::BASELEVEL); clif_updatestatus(sd, SP::NEXTBASEEXP); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Base level lowered."_s); } @@ -1595,7 +1595,7 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr sd, clif_updatestatus(sd, SP::NEXTJOBEXP); sd->status.skill_point += level; clif_updatestatus(sd, SP::SKILLPOINT); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_misceffect(sd, 1); clif_displaymessage(s, "Job level raised."_s); } @@ -1620,7 +1620,7 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr sd, clif_updatestatus(sd, SP::SKILLPOINT); } // to add: remove status points from skills - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Job level lowered."_s); } @@ -1853,7 +1853,7 @@ ATCE atcommand_mobinfo(Session *s, dumb_ptr sd, clif_displaymessage(s, STRPRINTF("Monster ID: %i, English Name: %s, Japanese Name: %s"_fmt, mob_id, get_mob_db(mob_id).name, get_mob_db(mob_id).jname)); clif_displaymessage(s, STRPRINTF("Level: %i, HP: %i, SP: %i, Base EXP: %i, JEXP: %i"_fmt, get_mob_db(mob_id).lv, get_mob_db(mob_id).max_hp, get_mob_db(mob_id).max_sp, get_mob_db(mob_id).base_exp, get_mob_db(mob_id).job_exp)); clif_displaymessage(s, STRPRINTF("Range1: %i, ATK1: %i, ATK2: %i, DEF: %i, MDEF: %i, CRITICAL_DEF: %i"_fmt, get_mob_db(mob_id).range, get_mob_db(mob_id).atk1, get_mob_db(mob_id).atk2, get_mob_db(mob_id).def, get_mob_db(mob_id).mdef, get_mob_db(mob_id).critical_def)); - clif_displaymessage(s, STRPRINTF("Stats: STR: %i, AGI: %i, VIT: %i, INT: %i, DEX:, %i LUK:, %i"_fmt, get_mob_db(mob_id).attrs[ATTR::STR], get_mob_db(mob_id).attrs[ATTR::AGI], get_mob_db(mob_id).attrs[ATTR::VIT], get_mob_db(mob_id).attrs[ATTR::INT], get_mob_db(mob_id).attrs[ATTR::DEX], get_mob_db(mob_id).attrs[ATTR::LUK])); + clif_displaymessage(s, STRPRINTF("Stats: STR: %i, AGI: %i, VIT: %i, INT: %i, DEX: %i, LUK: %i"_fmt, get_mob_db(mob_id).attrs[ATTR::STR], get_mob_db(mob_id).attrs[ATTR::AGI], get_mob_db(mob_id).attrs[ATTR::VIT], get_mob_db(mob_id).attrs[ATTR::INT], get_mob_db(mob_id).attrs[ATTR::DEX], get_mob_db(mob_id).attrs[ATTR::LUK])); clif_displaymessage(s, STRPRINTF("Range2: %i, Range3: %i, Scale: %i, Race: %i, Element: %i, Element Level: %i, Mode: %i"_fmt, get_mob_db(mob_id).range2, get_mob_db(mob_id).range3, get_mob_db(mob_id).size, get_mob_db(mob_id).race, get_mob_db(mob_id).element.element, get_mob_db(mob_id).element.level, get_mob_db(mob_id).mode)); clif_displaymessage(s, STRPRINTF("Speed: %i, Adelay: %i, Amotion: %i, Dmotion: %i"_fmt, get_mob_db(mob_id).speed.count(), get_mob_db(mob_id).adelay.count(), get_mob_db(mob_id).amotion.count(), get_mob_db(mob_id).dmotion.count())); if (get_mob_db(mob_id).mutations_nr) @@ -2283,7 +2283,7 @@ ATCE atcommand_param(Session *s, dumb_ptr sd, sd->status.attrs[attr] = new_value; clif_updatestatus(sd, attr_to_sp(attr)); clif_updatestatus(sd, attr_to_usp(attr)); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Stat changed."_s); } else @@ -2318,7 +2318,7 @@ ATCE atcommand_all_stats(Session *s, dumb_ptr sd, sd->status.attrs[attr] = new_value; clif_updatestatus(sd, attr_to_sp(attr)); clif_updatestatus(sd, attr_to_usp(attr)); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); count++; } } @@ -2682,7 +2682,7 @@ ATCE atcommand_character_option(Session *s, dumb_ptr sd, pl_sd->status.option = opt3; clif_changeoption(pl_sd); - pc_calcstatus(pl_sd, 0); + pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Character's options changed."_s); } else @@ -3004,7 +3004,7 @@ ATCE atcommand_character_baselevel(Session *s, dumb_ptr sd, clif_updatestatus(pl_sd, SP::BASELEVEL); clif_updatestatus(pl_sd, SP::NEXTBASEEXP); clif_updatestatus(pl_sd, SP::STATUSPOINT); - pc_calcstatus(pl_sd, 0); + pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC); pc_heal(pl_sd, pl_sd->status.max_hp, pl_sd->status.max_sp); clif_misceffect(pl_sd, 0); clif_displaymessage(s, "Character's base level raised."_s); @@ -3034,7 +3034,7 @@ ATCE atcommand_character_baselevel(Session *s, dumb_ptr sd, clif_updatestatus(pl_sd, SP::BASELEVEL); clif_updatestatus(pl_sd, SP::NEXTBASEEXP); clif_updatestatus(pl_sd, SP::BASEEXP); - pc_calcstatus(pl_sd, 0); + pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Character's base level lowered."_s); } // Reset their stat points to prevent extra points from stacking @@ -3088,7 +3088,7 @@ ATCE atcommand_character_joblevel(Session *s, dumb_ptr sd, clif_updatestatus(pl_sd, SP::NEXTJOBEXP); pl_sd->status.skill_point += level; clif_updatestatus(pl_sd, SP::SKILLPOINT); - pc_calcstatus(pl_sd, 0); + pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC); clif_misceffect(pl_sd, 1); clif_displaymessage(s, "character's job level raised."_s); } @@ -3112,7 +3112,7 @@ ATCE atcommand_character_joblevel(Session *s, dumb_ptr sd, clif_updatestatus(pl_sd, SP::SKILLPOINT); } // to add: remove status points from skills - pc_calcstatus(pl_sd, 0); + pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC); clif_displaymessage(s, "Character's job level lowered."_s); } } @@ -3595,7 +3595,7 @@ ATCE atcommand_char_wipe(Session *s, dumb_ptr sd, pc_additem(pl_sd, &item, 1); // Reset stats and skills - pc_calcstatus(pl_sd, 0); + pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC); pc_resetstate(pl_sd); pc_resetskill(pl_sd); pc_setglobalreg(pl_sd, stringish("MAGIC_FLAGS"_s), 0); diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index 972bfd0..52c311b 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -587,7 +587,7 @@ void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed) && bool(sd->status.inventory[i].equip)) pc_unequipitem(sd, i, CalcStatus::LATER); } - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); // save character chrif_save(sd); sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters diff --git a/src/map/map.cpp b/src/map/map.cpp index e7b0da8..ff69a56 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -816,7 +816,7 @@ void map_quit(dumb_ptr sd) pc_stopattack(sd); pc_delinvincibletimer(sd); - pc_calcstatus(sd, 4); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC_NO_CLIENT_UPDATE); clif_clearchar(sd, BeingRemoveWhy::QUIT); diff --git a/src/map/map.hpp b/src/map/map.hpp index 659ed2d..7cf43d5 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -307,6 +307,15 @@ struct map_session_data : block_list, SessionData unsigned guild:1; } mute; + struct + { + int kills; + int casts; + int items_used; + int tiles_walked; + int attacks; + } activity; + AutoMod automod; tick_t flood_rates[0x220]; diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp index 4336411..0f3e608 100644 --- a/src/map/map.t.hpp +++ b/src/map/map.t.hpp @@ -182,7 +182,7 @@ namespace e enum class MapCell : uint8_t { // the usual thing - UNWALKABLE = 0x01, + UNWALKABLE = 0x01, // not in tmwa data _range = 0x04, }; diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 715a9cb..4fd9d6d 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -227,9 +227,9 @@ earray mutation_base //= /*======================================== * Mutates a MOB. For large `direction' values, calling this multiple times will give bigger XP boni. + * intensity: positive: strengthen, negative: weaken. 256 = 100%. *---------------------------------------- */ -// intensity: positive: strengthen, negative: weaken. 256 = 100%. static void mob_mutate(dumb_ptr md, mob_stat stat, int intensity) { @@ -309,7 +309,10 @@ void mob_mutate(dumb_ptr md, mob_stat stat, int intensity) } } -// This calculates the exp of a given mob +/*========================================== + * This calculates the exp of a given mob + *------------------------------------------ + */ static int mob_gen_exp(mob_db_ *mob) { @@ -343,6 +346,10 @@ int mob_gen_exp(mob_db_ *mob) return xp; } +/*========================================== + * + *------------------------------------------ + */ static void mob_init(dumb_ptr md) { @@ -517,46 +524,82 @@ BlockId mob_once_spawn_area(dumb_ptr sd, } // TODO: deprecate these +/*========================================== + * + *------------------------------------------ + */ short mob_get_hair(Species mob_class) { return get_mob_db(mob_class).hair; } +/*========================================== + * + *------------------------------------------ + */ short mob_get_hair_color(Species mob_class) { return get_mob_db(mob_class).hair_color; } +/*========================================== + * + *------------------------------------------ + */ short mob_get_weapon(Species mob_class) { return get_mob_db(mob_class).weapon; } +/*========================================== + * + *------------------------------------------ + */ ItemNameId mob_get_shield(Species mob_class) { return get_mob_db(mob_class).shield; } +/*========================================== + * + *------------------------------------------ + */ ItemNameId mob_get_head_top(Species mob_class) { return get_mob_db(mob_class).head_top; } +/*========================================== + * + *------------------------------------------ + */ ItemNameId mob_get_head_mid(Species mob_class) { return get_mob_db(mob_class).head_mid; } +/*========================================== + * + *------------------------------------------ + */ ItemNameId mob_get_head_buttom(Species mob_class) { return get_mob_db(mob_class).head_buttom; } +/*========================================== + * + *------------------------------------------ + */ short mob_get_clothes_color(Species mob_class) // Add for player monster dye - Valaris { return get_mob_db(mob_class).clothes_color; // End } +/*========================================== + * + *------------------------------------------ + */ int mob_get_equip(Species mob_class) // mob equip [Valaris] { return get_mob_db(mob_class).equip; @@ -789,6 +832,10 @@ int mob_check_attack(dumb_ptr md) return 1; } +/*========================================== + * + *------------------------------------------ + */ static void mob_ancillary_attack(dumb_ptr bl, dumb_ptr mdbl, dumb_ptr tbl, tick_t tick) @@ -815,7 +862,7 @@ int mob_attack(dumb_ptr md, tick_t tick) return 0; if (battle_config.monster_attack_direction_change) - md->dir = map_calc_dir(md, tbl->bl_x, tbl->bl_y); // 向き設定 + md->dir = map_calc_dir(md, tbl->bl_x, tbl->bl_y); // 向き設定 | Orientation setting //clif_fixmobpos(md); @@ -941,7 +988,7 @@ void mob_timer(TimerData *, tick_t tick, BlockId id, unsigned char data) dumb_ptr bl; bl = map_id2bl(id); if (bl == nullptr) - { //攻撃してきた敵がもういないのは正常のようだ + { // 攻撃してきた敵がもういないのは正常のようだ | It seems normal that the enemy that attacked us is no longer there. return; } @@ -1301,13 +1348,13 @@ int mob_can_reach(dumb_ptr md, dumb_ptr bl, int range) return 0; } - if (md->bl_m != bl->bl_m) // 違うャbプ + if (md->bl_m != bl->bl_m) // 違うャbプ | Different type return 0; - if (range > 0 && range < arange) // 遠すぎる + if (range > 0 && range < arange) // 遠すぎる | too far return 0; - if (md->bl_x == bl->bl_x && md->bl_y == bl->bl_y) // 同じャX + if (md->bl_x == bl->bl_x && md->bl_y == bl->bl_y) // 同じャX | Same guy return 1; // Obstacle judging @@ -1400,6 +1447,10 @@ int mob_target(dumb_ptr md, dumb_ptr bl, int dist) return 0; } +/*========================================== + * + *------------------------------------------ + */ int mob_aggravate(dumb_ptr md, dumb_ptr bl) { if (md->bl_type != BL::MOB) @@ -1434,7 +1485,7 @@ void mob_ai_sub_hard_activesearch(dumb_ptr bl, else return; - //敵味方判定 + // 敵味方判定 | Enemy/ally determination if (battle_check_target(smd, bl, BCT_ENEMY) == 0) return; @@ -1443,11 +1494,11 @@ void mob_ai_sub_hard_activesearch(dumb_ptr bl, else mode = smd->mode; - // アクティブでターゲット射程内にいるなら、ロックする + // アクティブでターゲット射程内にいるなら、ロックする | Lock if active and within target range if (bool(mode & MobMode::AGGRESSIVE)) { Race race = get_mob_db(smd->mob_class).race; - //対象がPCの場合 + // 対象がPCの場合 | If the target is a PC if (tsd && !pc_isdead(tsd) && tsd->bl_m == smd->bl_m && @@ -1461,29 +1512,29 @@ void mob_ai_sub_hard_activesearch(dumb_ptr bl, || race == Race::_insect || race == Race::_demon)) { - // 妨害がないか判定 - // 到達可能性判定 + // 妨害がないか判定 | Determine if there is any interference + // 到達可能性判定 | Arrival possibility determination if (mob_can_reach(smd, bl, 12) && random_::chance({1, ++*pcc})) { - // 範囲内PCで等確率にする + // 範囲内PCで等確率にする | Make the probability equal for PCs within the range smd->target_id = tsd->bl_id; smd->state.attackable = true; smd->min_chase = 13; } } } - //対象がMobの場合 + // 対象がMobの場合 | If the target is a mob else if (tmd && tmd->bl_m == smd->bl_m && (dist = distance(smd->bl_x, smd->bl_y, tmd->bl_x, tmd->bl_y)) < 9) { - // 到達可能性判定 + // 到達可能性判定 | Arrival possibility determination if (mob_can_reach(smd, bl, 12) && random_::chance({1, ++*pcc})) { - // 範囲内で等確率にする + // 範囲内で等確率にする | Make the probability equal within the range smd->target_id = bl->bl_id; smd->state.attackable = true; smd->min_chase = 13; @@ -1681,7 +1732,7 @@ int mob_ai_sub_hard_slavemob(dumb_ptr md, tick_t tick) || (!sd->state.gangsterparadise || race == Race::_insect || race == Race::_demon)) - { // 妨害がないか判定 + { // 妨害がないか判定 | Determine if there is any interference md->target_id = sd->bl_id; md->state.attackable = true; @@ -1875,7 +1926,7 @@ void mob_ai_sub_hard(dumb_ptr bl, tick_t tick) if (md->master_id && md->state.special_mob_ai == 0) mob_ai_sub_hard_slavemob(md, tick); - // アクティヴモンスターの策敵 (?? of a bitter taste TIVU monster) + // アクティヴモンスターの策敵 | Active monster's enemy (?? of a bitter taste TIVU monster) if ((!md->target_id || !md->state.attackable) && bool(mode & MobMode::AGGRESSIVE) && !md->state.master_check && battle_config.monster_active_enable == 1) @@ -1927,40 +1978,40 @@ void mob_ai_sub_hard(dumb_ptr bl, tick_t tick) || (dist = distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y)) >= md->min_chase) - mob_unlocktarget(md, tick); // 別マップか、視界外 + mob_unlocktarget(md, tick); // 別マップか、視界外 | Another map or out of sight? else if (tsd && !bool(mode & MobMode::BOSS) && (tsd->state.gangsterparadise && race != Race::_insect && race != Race::_demon)) - mob_unlocktarget(md, tick); // スキルなどによる策敵妨害 + mob_unlocktarget(md, tick); // スキルなどによる策敵妨害 | Interfering with enemy tactics using skills etc. else if (!battle_check_range(md, tbl, get_mob_db(md->mob_class).range)) { - // 攻撃範囲外なので移動 + // 攻撃範囲外なので移動 | Move because you are out of attack range if (!bool(mode & MobMode::CAN_MOVE)) - { // 移動しないモード + { // 移動しないモード | No-move mode mob_unlocktarget(md, tick); return; } - if (!mob_can_move(md)) // 動けない状態にある + if (!mob_can_move(md)) // 動けない状態にある | unable to move return; - md->state.skillstate = MobSkillState::MSS_CHASE; // 突撃時スキル + md->state.skillstate = MobSkillState::MSS_CHASE; // 突撃時スキル | Assault skills mobskill_use(md, tick, MobSkillCondition::ANY); if (md->timer && md->state.state != MS::ATTACK && (md->next_walktime < tick || distance(md->to_x, md->to_y, tbl->bl_x, tbl->bl_y) < 2)) - return; // 既に移動中 + return; // 既に移動中 | Already on the move if (!mob_can_reach(md, tbl, (md->min_chase > 13) ? md->min_chase : 13)) - mob_unlocktarget(md, tick); // 移動できないのでタゲ解除(IWとか?) + mob_unlocktarget(md, tick); // 移動できないのでタゲ解除(IWとか?) | I can't move so I can't target it (IW or something?) else { - // 追跡 + // 追跡 | tracking md->next_walktime = tick + 500_ms; i = 0; do { if (i == 0) { - // 最初はAEGISと同じ方法で検索 + // 最初はAEGISと同じ方法で検索 | First search in the same way as AEGIS dx = tbl->bl_x - md->bl_x; dy = tbl->bl_y - md->bl_y; if (dx < 0) @@ -1974,7 +2025,7 @@ void mob_ai_sub_hard(dumb_ptr bl, tick_t tick) } else { - // だめならAthena式(ランダム) + // だめならAthena式(ランダム) | If not, use Athena style (random) // {0 1 2} dx = tbl->bl_x - md->bl_x + random_::in(-1, 1); dy = tbl->bl_y - md->bl_y + random_::in(-1, 1); @@ -1985,7 +2036,7 @@ void mob_ai_sub_hard(dumb_ptr bl, tick_t tick) while (ret && i < 5); if (ret) - { // 移動不可能な所からの攻撃なら2歩下る + { // 移動不可能な所からの攻撃なら2歩下る | If attacking from a place where you can't move, take 2 steps back. if (dx < 0) dx = 2; else if (dx > 0) @@ -2000,57 +2051,57 @@ void mob_ai_sub_hard(dumb_ptr bl, tick_t tick) } } else - { // 攻撃射程範囲内 + { // 攻撃射程範囲内 | Within attack range md->state.skillstate = MobSkillState::MSS_ATTACK; if (md->state.state == MS::WALK) - mob_stop_walking(md, 1); // 歩行中なら停止 + mob_stop_walking(md, 1); // 歩行中なら停止 | Stop if you are walking if (md->state.state == MS::ATTACK) - return; // 既に攻撃中 + return; // 既に攻撃中 | already under attack mob_changestate(md, MS::ATTACK, attack_type); } return; } else - { // ルートモンスター処理 + { // ルートモンスター処理 | Root monster processing if (tbl == nullptr || tbl->bl_type != BL::ITEM || tbl->bl_m != md->bl_m || (dist = distance(md->bl_x, md->bl_y, tbl->bl_x, tbl->bl_y)) >= md->min_chase || !bool(get_mob_db(md->mob_class).mode & MobMode::LOOTER)) { - // 遠すぎるかアイテムがなくなった + // 遠すぎるかアイテムがなくなった | Too far or missing item mob_unlocktarget(md, tick); if (md->state.state == MS::WALK) - mob_stop_walking(md, 1); // 歩行中なら停止 + mob_stop_walking(md, 1); // 歩行中なら停止 | Stop if you are walking } else if (dist) { if (!bool(mode & MobMode::CAN_MOVE)) - { // 移動しないモード + { // 移動しないモード | no-move mode mob_unlocktarget(md, tick); return; } - if (!mob_can_move(md)) // 動けない状態にある + if (!mob_can_move(md)) // 動けない状態にある | unable to move return; - md->state.skillstate = MobSkillState::MSS_LOOT; // ルート時スキル使用 + md->state.skillstate = MobSkillState::MSS_LOOT; // ルート時スキル使用 | Skill use during root mobskill_use(md, tick, MobSkillCondition::ANY); if (md->timer && md->state.state != MS::ATTACK && (md->next_walktime < tick || distance(md->to_x, md->to_y, tbl->bl_x, tbl->bl_y) <= 0)) - return; // 既に移動中 + return; // 既に移動中 | Already on the move md->next_walktime = tick + 500_ms; dx = tbl->bl_x - md->bl_x; dy = tbl->bl_y - md->bl_y; ret = mob_walktoxy(md, md->bl_x + dx, md->bl_y + dy, 0); if (ret) - mob_unlocktarget(md, tick); // 移動できないのでタゲ解除(IWとか?) + mob_unlocktarget(md, tick); // 移動できないのでタゲ解除(IWとか?) | I can't move so I can't target it (IW or something?) } else - { // アイテムまでたどり着いた + { // アイテムまでたどり着いた | I got to the item if (md->state.state == MS::ATTACK) - return; // 攻撃中 + return; // 攻撃中 | Under attack if (md->state.state == MS::WALK) - mob_stop_walking(md, 1); // 歩行中なら停止 + mob_stop_walking(md, 1); // 歩行中なら停止 | Stop if you are walking fitem = tbl->is_item(); md->lootitemv.push_back(fitem->item_data); map_clearflooritem(tbl->bl_id); @@ -2063,7 +2114,7 @@ void mob_ai_sub_hard(dumb_ptr bl, tick_t tick) { mob_unlocktarget(md, tick); if (md->state.state == MS::WALK) - mob_stop_walking(md, 4); // 歩行中なら停止 + mob_stop_walking(md, 4); // 歩行中なら停止 | Stop if you are walking return; } } @@ -2302,6 +2353,10 @@ int mob_delete(dumb_ptr md) return 0; } +/*========================================== + * + *------------------------------------------ + */ int mob_catch_delete(dumb_ptr md, BeingRemoveWhy type) { nullpo_retr(1, md); @@ -2315,6 +2370,10 @@ int mob_catch_delete(dumb_ptr md, BeingRemoveWhy type) return 0; } +/*========================================== + * + *------------------------------------------ + */ void mob_timer_delete(TimerData *, tick_t, BlockId id) { dumb_ptr bl = map_id2bl(id); @@ -2378,7 +2437,7 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, tick_t tick = gettick(); dumb_ptr mvp_sd = nullptr, second_sd = nullptr, third_sd = nullptr; - nullpo_retz(md); //srcはNULLで呼ばれる場合もあるので、他でチェック + nullpo_retz(md); // srcはNULLで呼ばれる場合もあるので、他でチェック | src may be called as NULL, so check it elsewhere. if (src && src->bl_id == md->master_id && bool(md->mode & MobMode::TURNS_AGAINST_BAD_MASTER)) @@ -2495,6 +2554,13 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, md->hp -= damage; + // activity + if (sd) + if (sd->activity.attacks == 2147483647) + sd->activity.attacks = 1; + else + sd->activity.attacks++; + if (md->hp > 0) { return 0; @@ -2502,7 +2568,7 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, MAP_LOG("MOB%d DEAD"_fmt, md->bl_id); - // ----- ここから死亡処理 ----- + // ----- ここから死亡処理 | Death processing begins here ----- MapBlockLock lock; // cancels timers @@ -2514,8 +2580,8 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, if (src && src->bl_type == BL::MOB) mob_unlocktarget(src->is_mob(), tick); - // map外に消えた人は計算から除くので - // overkill分は無いけどsumはmax_hpとは違う + // map外に消えた人は計算から除くので | People who disappear outside the map will be excluded from the calculation. + // overkill分は無いけどsumはmax_hpとは違う | There is no overkill portion, but sum is different from max_hp // snip a prelude loop, now merged @@ -2545,6 +2611,12 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, if (tmpsdi->bl_m != md->bl_m || pc_isdead(tmpsdi)) continue; + // activity + if (tmpsdi->activity.kills == 2147483647) + tmpsdi->activity.kills = 1; + else + tmpsdi->activity.kills++; + // this way is actually fair, unlike the old way // that refers to the subsequents ... was buggy though if (tmpdmg > mvp_dmg) @@ -2704,7 +2776,7 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, } } // [MouseJstr] - // SCRIPT実行 + // SCRIPT実行 | SCRIPT execution { if (sd == nullptr) { @@ -2737,6 +2809,7 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, /*========================================== * mob回復 + * mob recovery *------------------------------------------ */ int mob_heal(dumb_ptr md, int heal) @@ -2784,6 +2857,7 @@ int mob_warpslave(dumb_ptr md, int x, int y) /*========================================== * mobワープ + * mob warp *------------------------------------------ */ int mob_warp(dumb_ptr md, Option> m_, int x, int y, BeingRemoveWhy type) @@ -2806,7 +2880,7 @@ int mob_warp(dumb_ptr md, Option> m_, int x, int y map_delblock(md); if (bx > 0 && by > 0) - { // 位置指定の場合周囲9セルを探索 + { // 位置指定の場合周囲9セルを探索 | When specifying a location, search the surrounding 9 cells xs = ys = 9; } @@ -2817,13 +2891,13 @@ int mob_warp(dumb_ptr md, Option> m_, int x, int y { if (xs > 0 && ys > 0 && i < 250) { - // 指定位置付近の探索 + // 指定位置付近の探索 | Search near specified location x = bx + random_::to(xs) - xs / 2; y = by + random_::to(ys) - ys / 2; } else { - // 完全ランダム探索 + // 完全ランダム探索 | Completely random search x = random_::in(1, m->xs - 2); y = random_::in(1, m->ys - 2); } @@ -2841,7 +2915,7 @@ int mob_warp(dumb_ptr md, Option> m_, int x, int y PRINTF("MOB %d warp failed, mob_class = %d\n"_fmt, md->bl_id, md->mob_class); } - md->target_id = BlockId(); // タゲを解除する + md->target_id = BlockId(); // タゲを解除する | remove target md->state.attackable = false; md->attacked_id = BlockId(); md->state.skillstate = MobSkillState::MSS_IDLE; @@ -2867,6 +2941,7 @@ int mob_warp(dumb_ptr md, Option> m_, int x, int y /*========================================== * 画面内の取り巻きの数計算用(foreachinarea) + * For calculating the number of entourage in the screen (foreachinarea) *------------------------------------------ */ static @@ -2883,6 +2958,7 @@ void mob_countslave_sub(dumb_ptr bl, BlockId id, int *c) /*========================================== * 画面内の取り巻きの数計算 + * Calculating the number of entourage in the screen *------------------------------------------ */ static @@ -2902,6 +2978,7 @@ int mob_countslave(dumb_ptr md) /*========================================== * 手下MOB召喚 + * MOB summoning *------------------------------------------ */ int mob_summonslave(dumb_ptr md2, int *value_, int amount, int flag) @@ -2965,8 +3042,8 @@ int mob_summonslave(dumb_ptr md2, int *value_, int amount, int flag) md->spawn.xs = 0; md->spawn.ys = 0; md->stats[mob_stat::SPEED] = md2->stats[mob_stat::SPEED]; - md->spawn.delay1 = static_cast(-1); // 一度のみフラグ - md->spawn.delay2 = static_cast(-1); // 一度のみフラグ + md->spawn.delay1 = static_cast(-1); // 一度のみフラグ | once flag + md->spawn.delay2 = static_cast(-1); // 一度のみフラグ | once flag md->npc_event = NpcEvent(); md->bl_type = BL::MOB; @@ -2982,6 +3059,7 @@ int mob_summonslave(dumb_ptr md2, int *value_, int amount, int flag) /*========================================== * 自分をロックしているPCの数を数える(foreachclient) + * Count the number of PCs that have locked you (foreachclient) *------------------------------------------ */ static @@ -3011,6 +3089,7 @@ void mob_counttargeted_sub(dumb_ptr bl, /*========================================== * 自分をロックしているPCの数を数える + * Count the number of PCs that have locked you *------------------------------------------ */ int mob_counttargeted(dumb_ptr md, dumb_ptr src, @@ -3029,11 +3108,12 @@ int mob_counttargeted(dumb_ptr md, dumb_ptr src, } // -// MOBスキル +// MOBスキル | MOB skills // /*========================================== * スキル使用(詠唱完了、ID指定) + * Skill use (casting completed, ID designation) *------------------------------------------ */ void mobskill_castend_id(TimerData *, tick_t tick, BlockId id) @@ -3043,7 +3123,7 @@ void mobskill_castend_id(TimerData *, tick_t tick, BlockId id) dumb_ptr mbl; int range; - if ((mbl = map_id2bl(id)) == nullptr) //詠唱したMobがもういないというのは良くある正常処理 + if ((mbl = map_id2bl(id)) == nullptr) // 詠唱したMobがもういないというのは良くある正常処理 | It's common and normal that the mob that cast is no longer there. return; if ((md = mbl->is_mob()) == nullptr) { @@ -3060,13 +3140,13 @@ void mobskill_castend_id(TimerData *, tick_t tick, BlockId id) md->last_thinktime = tick + battle_get_adelay(md); if ((bl = map_id2bl(md->skilltarget)) == nullptr || bl->bl_prev == nullptr) - { //スキルターゲットが存在しない + { // スキルターゲットが存在しない | Skill target does not exist return; } if (md->bl_m != bl->bl_m) return; - if (((skill_get_inf(md->skillid) & 1) || (skill_get_inf2(md->skillid) & 4)) && // 彼我敵対関係チェック + if (((skill_get_inf(md->skillid) & 1) || (skill_get_inf2(md->skillid) & 4)) && // 彼我敵対関係チェック | Self-enemy relationship check battle_check_target(md, bl, BCT_ENEMY) <= 0) return; range = skill_get_range(md->skillid, md->skilllv); @@ -3084,14 +3164,14 @@ void mobskill_castend_id(TimerData *, tick_t tick, BlockId id) switch (skill_get_nk(md->skillid)) { - // 攻撃系/吹き飛ばし系 + // 攻撃系/吹き飛ばし系 | Attack type/Blow type case 0: case 2: skill_castend_damage_id(md, bl, md->skillid, md->skilllv, tick, BCT_ZERO); break; - case 1: // 支援系 + case 1: // 支援系 | Support system skill_castend_nodamage_id(md, bl, md->skillid, md->skilllv); break; @@ -3100,6 +3180,7 @@ void mobskill_castend_id(TimerData *, tick_t tick, BlockId id) /*========================================== * スキル使用(詠唱完了、場所指定) + * Skill use (casting completed, location specified) *------------------------------------------ */ void mobskill_castend_pos(TimerData *, tick_t tick, BlockId id) @@ -3108,7 +3189,8 @@ void mobskill_castend_pos(TimerData *, tick_t tick, BlockId id) dumb_ptr bl; int range; - //mobskill_castend_id同様詠唱したMobが詠唱完了時にもういないというのはありそうなのでnullpoから除外 + // mobskill_castend_id同様詠唱したMobが詠唱完了時にもういないというのはありそうなのでnullpoから除外 + // mobskill_castend_id It is likely that the mob that cast the same as the one is no longer there when the cast is completed, so it is excluded from nullpo. if ((bl = map_id2bl(id)) == nullptr) return; @@ -3164,7 +3246,7 @@ int mobskill_use_id(dumb_ptr md, dumb_ptr target, if (skill_get_inf2(skill_id) & 0x200 && md->bl_id == target->bl_id) return 0; - // 射程と障害物チェック + // 射程と障害物チェック | Range and obstacle check range = skill_get_range(skill_id, skill_lv); if (range < 0) range = battle_get_range(md) - (range + 1); @@ -3183,7 +3265,7 @@ int mobskill_use_id(dumb_ptr md, dumb_ptr target, target->bl_id, skill_id, skill_lv, static_cast(casttime.count()), md->mob_class); - if (casttime <= interval_t::zero()) // 詠唱の無いものはキャンセルされない + if (casttime <= interval_t::zero()) // 詠唱の無いものはキャンセルされない | Anything without a chant will not be canceled md->state.skillcastcancel = 0; md->skilltarget = target->bl_id; @@ -3210,6 +3292,7 @@ int mobskill_use_id(dumb_ptr md, dumb_ptr target, /*========================================== * スキル使用(場所指定) + * Skill usage (Location) *------------------------------------------ */ static @@ -3233,7 +3316,7 @@ int mobskill_use_pos(dumb_ptr md, if (bool(md->opt1)) return 0; - // 射程と障害物チェック + // 射程と障害物チェック | Range and obstacle check bl.bl_type = BL::NUL; bl.bl_m = md->bl_m; bl.bl_x = skill_x; @@ -3304,11 +3387,11 @@ int mobskill_use(dumb_ptr md, tick_t tick, tick_t& sdii = md->skilldelayup[&msii - &ms.front()]; int flag = 0; - // ディレイ中 + // ディレイ中 | During delay if (tick < sdii + msii.delay) continue; - // 状態判定 + // 状態判定 | Status determination if (msii.state != MobSkillState::ANY && msii.state != md->state.skillstate) continue; @@ -3336,13 +3419,13 @@ int mobskill_use(dumb_ptr md, tick_t tick, } } - // 確率判定 + // 確率判定 | Probability judgment if (flag && random_::chance({msii.permillage, 10000})) { if (skill_get_inf(msii.skill_id) & 2) { - // 場所指定 + // 場所指定 | Specify location dumb_ptr bl = nullptr; int x = 0, y = 0; { @@ -3404,7 +3487,7 @@ int mobskill_event(dumb_ptr md, BF flag) } // -// 初期化 +// 初期化 | Initialization // /*========================================== * Since un-setting [ mob ] up was used, it is an initial provisional value setup. @@ -3451,6 +3534,10 @@ int mob_makedummymobdb(Species mob_class) return 0; } +/*========================================== + * + *------------------------------------------ + */ static bool impl_extract(XString str, LevelElement *le) { @@ -3463,6 +3550,10 @@ bool impl_extract(XString str, LevelElement *le) return false; } +/*========================================== + * + *------------------------------------------ + */ bool mob_readdb(ZString filename) { bool rv = true; @@ -3614,6 +3705,10 @@ bool mob_readdb(ZString filename) return rv; } +/*========================================== + * + *------------------------------------------ + */ static bool impl_extract(XString str, MobSkillCondition *msc) { @@ -3638,6 +3733,10 @@ bool impl_extract(XString str, MobSkillCondition *msc) return false; } +/*========================================== + * + *------------------------------------------ + */ static bool impl_extract(XString str, MobSkillState *mss) { @@ -3661,6 +3760,10 @@ bool impl_extract(XString str, MobSkillState *mss) return false; } +/*========================================== + * + *------------------------------------------ + */ static bool impl_extract(XString str, MobSkillTarget *mst) { @@ -3682,6 +3785,10 @@ bool impl_extract(XString str, MobSkillTarget *mst) return false; } +/*========================================== + * + *------------------------------------------ + */ bool mob_readskilldb(ZString filename) { bool rv = true; @@ -3764,6 +3871,10 @@ bool mob_readskilldb(ZString filename) return rv; } +/*========================================== + * + *------------------------------------------ + */ void do_init_mob2(void) { Timer(gettick() + MIN_MOBTHINKTIME, diff --git a/src/map/pc.cpp b/src/map/pc.cpp index ea15910..c7c6acf 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -805,13 +805,13 @@ void pc_set_attack_info(dumb_ptr sd, interval_t speed, int ran if (speed == interval_t::zero()) { - pc_calcstatus(sd, 1); + pc_calcstatus(sd, (int)CalcStatusKind::INITIAL_CALC); clif_updatestatus(sd, SP::ASPD); clif_updatestatus(sd, SP::ATTACKRANGE); } else { - pc_calcstatus(sd, 9); + pc_calcstatus(sd, ((int)CalcStatusKind::INITIAL_CALC + (int)CalcStatusKind::MAGIC_OVERRIDE)); clif_updatestatus(sd, SP::ASPD); clif_updatestatus(sd, SP::ATTACKRANGE); } @@ -948,7 +948,7 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version, sd->die_counter = pc_readglobalreg(sd, stringish("PC_DIE_COUNTER"_s)); // ステータス初期計算など | Status initial calculation, etc. - pc_calcstatus(sd, 1); + pc_calcstatus(sd, (int)CalcStatusKind::INITIAL_CALC); if (pc_isGM(sd)) { @@ -981,7 +981,7 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version, sd->packet_flood_reset_due = tick_t(); sd->packet_flood_in = 0; - pc_calcstatus(sd, 1); + pc_calcstatus(sd, (int)CalcStatusKind::INITIAL_CALC); if(sd->bl_m->mask > 0) clif_send_mask(sd, sd->bl_m->mask); @@ -1157,7 +1157,7 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->max_weight = max_weight_base_0 + sd->status.attrs[ATTR::STR] * 300; - if (first & 1) + if (first & (int)CalcStatusKind::INITIAL_CALC) { sd->weight = 0; for (IOff0 i : IOff0::iter()) @@ -1563,7 +1563,7 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->aspd = sd->aspd * aspd_rate / 100; /* Magic speed */ - if (sd->attack_spell_override || first & 8) + if (sd->attack_spell_override || first & (int)CalcStatusKind::MAGIC_OVERRIDE) sd->aspd = sd->attack_spell_delay; /* Red Threshold Calculation (TODO) */ @@ -1581,14 +1581,14 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->status.sp > sd->status.max_sp) sd->status.sp = sd->status.max_sp; - if (first & 4) + if (first & (int)CalcStatusKind::NORMAL_RECALC_NO_CLIENT_UPDATE) return 0; - if (first & 3) // never executed atm + if (first & ((int)CalcStatusKind::INITIAL_CALC + (int)CalcStatusKind::ITEM_BONUS_RECALC)) // never executed atm { clif_updatestatus(sd, SP::SPEED); clif_updatestatus(sd, SP::MAXHP); clif_updatestatus(sd, SP::MAXSP); - if (first & 1) // its always 1 here if first is 3 so this if is not needed normally + if (first & (int)CalcStatusKind::INITIAL_CALC) // its always 1 here if first is 3 so this if is not needed normally { clif_updatestatus(sd, SP::HP); clif_updatestatus(sd, SP::SP); @@ -1955,7 +1955,7 @@ int pc_skill(dumb_ptr sd, SkillID id, int level, int flag) if (!flag && (sd->status.skill[id].lv || level == 0)) { sd->status.skill[id].lv = level; - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_skillinfoblock(sd); } else if (sd->status.skill[id].lv < level) @@ -2407,6 +2407,13 @@ int pc_useitem(dumb_ptr sd, IOff0 n) clif_useitemack(sd, n, amount - 1, 1); pc_delitem(sd, n, 1, 1); + // activity + if (sd) + if (sd->activity.items_used == 2147483647) + sd->activity.items_used = 1; + else + sd->activity.items_used++; + run_script(ScriptPointer(script, 0), sd->bl_id, BlockId()); } OMATCH_END (); @@ -2730,6 +2737,13 @@ int pc_walktoxy_sub(dumb_ptr sd) } clif_movechar(sd); + // activity + if (sd) + if (sd->activity.tiles_walked == 2147483647) + sd->activity.tiles_walked = 1; + else + sd->activity.tiles_walked++; + return 0; } @@ -2907,7 +2921,7 @@ void pc_attack_timer(TimerData *, tick_t tick, BlockId id) sd->attack_spell_override = BlockId(); pc_set_weapon_icon(sd, 0, StatusChange::ZERO, ItemNameId()); pc_set_attack_info(sd, interval_t::zero(), 0); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } } else @@ -3043,7 +3057,7 @@ int pc_checkbaselevelup(dumb_ptr sd) clif_updatestatus(sd, SP::STATUSPOINT); clif_updatestatus(sd, SP::BASELEVEL); clif_updatestatus(sd, SP::NEXTBASEEXP); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); pc_heal(sd, sd->status.max_hp, sd->status.max_sp, true); clif_misceffect(sd, 0); @@ -3102,7 +3116,7 @@ int pc_checkjoblevelup(dumb_ptr sd) { // [Fate] Bah, this is is painful. // But the alternative is quite error-prone, and eAthena has far worse performance issues... sd->status.job_exp = next - 1; - pc_calcstatus(sd,0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); return 0; } @@ -3111,7 +3125,7 @@ int pc_checkjoblevelup(dumb_ptr sd) clif_updatestatus(sd, SP::NEXTJOBEXP); sd->status.skill_point++; clif_updatestatus(sd, SP::SKILLPOINT); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); MAP_LOG_PC(sd, "SKILLPOINTS-UP %d"_fmt, sd->status.skill_point); @@ -3348,7 +3362,7 @@ int pc_statusup(dumb_ptr sd, SP type) } clif_updatestatus(sd, SP::STATUSPOINT); clif_updatestatus(sd, type); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_statusupack(sd, type, 1, val); MAP_LOG_STATS(sd, "STATUP"_fmt); @@ -3377,7 +3391,7 @@ int pc_statusup2(dumb_ptr sd, SP type, int val) sd->status.attrs[attr] = val; clif_updatestatus(sd, sp_to_usp(type)); clif_updatestatus(sd, type); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_statusupack(sd, type, 1, val); MAP_LOG_STATS(sd, "STATUP2"_fmt); @@ -3400,7 +3414,7 @@ int pc_skillup(dumb_ptr sd, SkillID skill_num) sd->status.skill_point -= sd->status.skill[skill_num].lv; sd->status.skill[skill_num].lv++; - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); clif_skillup(sd, skill_num); clif_updatestatus(sd, SP::SKILLPOINT); clif_skillinfoblock(sd); @@ -3432,7 +3446,7 @@ int pc_resetstate(dumb_ptr sd) for (ATTR attr : ATTRs) clif_updatestatus(sd, attr_to_usp(attr)); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); return 0; } @@ -3458,7 +3472,7 @@ int pc_resetskill(dumb_ptr sd) clif_updatestatus(sd, SP::SKILLPOINT); clif_skillinfoblock(sd); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); return 0; } @@ -3551,7 +3565,7 @@ int pc_damage(dumb_ptr src, dumb_ptr sd, pc_set_weapon_icon(sd, 0, StatusChange::ZERO, ItemNameId()); pc_set_attack_info(sd, interval_t::zero(), 0); } - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); if (battle_config.death_penalty_type > 0 && sd->status.base_level >= 20) { @@ -3851,6 +3865,21 @@ int pc_readparam(dumb_ptr bl, SP type) case SP::MUTE_GUILD: val = sd ? sd->mute.guild : 0; break; + case SP::KILLS: + val = sd->activity.kills; + break; + case SP::CASTS: + val = sd->activity.casts; + break; + case SP::ITEMS_USED: + val = sd->activity.items_used; + break; + case SP::TILES_WALKED: + val = sd->activity.tiles_walked; + break; + case SP::ATTACKS: + val = sd->activity.attacks; + break; case SP::AUTOMOD: val = sd ? static_cast(sd->automod) : 0; break; @@ -3901,7 +3930,7 @@ int pc_setparam(dumb_ptr bl, SP type, int val) clif_updatestatus(sd, SP::NEXTBASEEXP); clif_updatestatus(sd, SP::STATUSPOINT); clif_updatestatus(sd, SP::BASEEXP); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); pc_heal(sd, sd->status.max_hp, sd->status.max_sp, true); break; case SP::JOBLEVEL: @@ -3919,7 +3948,7 @@ int pc_setparam(dumb_ptr bl, SP type, int val) clif_updatestatus(sd, SP::JOBLEVEL); clif_updatestatus(sd, SP::NEXTJOBEXP); clif_updatestatus(sd, SP::JOBEXP); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); break; case SP::CLASS: // TODO: mob class change @@ -3999,7 +4028,7 @@ int pc_setparam(dumb_ptr bl, SP type, int val) && !pc_isequip(sd, j)) pc_unequipitem(sd, j, CalcStatus::LATER); } - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); chrif_save(sd); clif_fixpcpos(sd); } @@ -4100,6 +4129,22 @@ int pc_setparam(dumb_ptr bl, SP type, int val) nullpo_retz(sd); sd->mute.guild = (val == 1); break; + // atm only setting of casts is needed since magic is handled in serverdata but I let the others here as well for whatever reason + case SP::KILLS: + sd->activity.kills = val; + break; + case SP::CASTS: + sd->activity.casts = val; + break; + case SP::ITEMS_USED: + sd->activity.items_used = val; + break; + case SP::TILES_WALKED: + sd->activity.tiles_walked = val; + break; + case SP::ATTACKS: + sd->activity.attacks = val; + break; case SP::AUTOMOD: nullpo_retz(sd); sd->automod = static_cast(val); @@ -4479,7 +4524,7 @@ int pc_setglobalreg(dumb_ptr sd, VarName reg, int val) if (reg == stringish("PC_DIE_COUNTER"_s) && sd->die_counter != val) { sd->die_counter = val; - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } Option> quest_data_ = questdb_searchname(var); OMATCH_BEGIN_SOME(quest_data, quest_data_) @@ -4910,7 +4955,7 @@ int pc_equipitem(dumb_ptr sd, IOff0 n, EPOS) } pc_signal_advanced_equipment_change(sd, n); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); return 0; } @@ -4977,7 +5022,7 @@ int pc_unequipitem(dumb_ptr sd, IOff0 n, CalcStatus type) } if (type == CalcStatus::NOW) { - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } return 0; @@ -5050,7 +5095,7 @@ int pc_checkitem(dumb_ptr sd) pc_setequipindex(sd); if (calc_flag) - pc_calcstatus(sd, 2); + pc_calcstatus(sd, (int)CalcStatusKind::ITEM_BONUS_RECALC); return 0; } @@ -5435,7 +5480,7 @@ void pc_natural_heal_sub(dumb_ptr sd) if (sd->spellpower_bonus_target < sd->spellpower_bonus_current) { sd->spellpower_bonus_current = sd->spellpower_bonus_target; - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } else if (sd->spellpower_bonus_target > sd->spellpower_bonus_current) { @@ -5443,7 +5488,7 @@ void pc_natural_heal_sub(dumb_ptr sd) 1 + ((sd->spellpower_bonus_target - sd->spellpower_bonus_current) >> 5); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } if (sd->sc_data[StatusChange::SC_HALT_REGENERATE].timer) diff --git a/src/map/pc.t.hpp b/src/map/pc.t.hpp index c9235fa..870b25a 100644 --- a/src/map/pc.t.hpp +++ b/src/map/pc.t.hpp @@ -56,5 +56,15 @@ enum class CalcStatus NOW, LATER, }; + +enum class CalcStatusKind +{ + NORMAL_RECALC = 0, + INITIAL_CALC = 1, + ITEM_BONUS_RECALC = 2, + NORMAL_RECALC_NO_CLIENT_UPDATE = 4, + MAGIC_OVERRIDE = 8, +}; + } // namespace map } // namespace tmwa diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index fd3f798..8dc1989 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -117,6 +117,10 @@ void builtin_mes(ScriptState *st) clif_scriptmes(sd, st->oid, mes); } +/*========================================== + * + *------------------------------------------ + */ static void builtin_mesq(ScriptState *st) { @@ -131,6 +135,10 @@ void builtin_mesq(ScriptState *st) clif_scriptmes(sd, st->oid, RString(mesq)); } +/*========================================== + * + *------------------------------------------ + */ static void builtin_mesn(ScriptState *st) { @@ -148,6 +156,10 @@ void builtin_mesn(ScriptState *st) clif_scriptmes(sd, st->oid, RString(mesq)); } +/*========================================== + * + *------------------------------------------ + */ static void builtin_clear(ScriptState *st) { @@ -2440,7 +2452,7 @@ void builtin_overrideattack(ScriptState *st) sd->attack_spell_override = BlockId(); pc_set_weapon_icon(sd, 0, StatusChange::ZERO, ItemNameId()); pc_set_attack_info(sd, interval_t::zero(), 0); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } } @@ -2508,7 +2520,7 @@ void builtin_setopt2(ScriptState *st) return; sd->opt2 = new_opt2; clif_changeoption(sd); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } @@ -4827,7 +4839,7 @@ void builtin_nude(ScriptState *st) if (idx.ok()) pc_unequipitem(sd, idx, CalcStatus::LATER); } - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } @@ -4850,7 +4862,7 @@ void builtin_unequipbyid(ScriptState *st) pc_unequipitem(sd, idx, CalcStatus::LATER); } - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); } @@ -5563,7 +5575,6 @@ void builtin_mapexit(ScriptState *) runflag = 0; } - #define BUILTIN(func, args, ret) \ {builtin_##func, #func ## _s, args, ret} diff --git a/src/map/skill-pools.cpp b/src/map/skill-pools.cpp index dfc70b0..ddec824 100644 --- a/src/map/skill-pools.cpp +++ b/src/map/skill-pools.cpp @@ -77,7 +77,7 @@ int skill_pool_activate(dumb_ptr sd, SkillID skill_id) && (skill_pool_size(sd) < skill_pool_max(sd))) { sd->status.skill[skill_id].flags |= SkillFlags::POOL_ACTIVATED; - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); MAP_LOG_PC(sd, "SKILL-ACTIVATE %d %d %d"_fmt, skill_id, sd->status.skill[skill_id].lv, skill_power(sd, skill_id)); @@ -98,7 +98,7 @@ int skill_pool_deactivate(dumb_ptr sd, SkillID skill_id) { sd->status.skill[skill_id].flags &= ~SkillFlags::POOL_ACTIVATED; MAP_LOG_PC(sd, "SKILL-DEACTIVATE %d"_fmt, skill_id); - pc_calcstatus(sd, 0); + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); return 0; } diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 0fcf505..87bbbda 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -805,7 +805,7 @@ void skill_status_change_end(dumb_ptr bl, StatusChange type, TimerDa clif_changeoption(bl); if (bl->bl_type == BL::PC && calc_flag) - pc_calcstatus(bl->is_player(), 0); /* ステータス再計算 | Status Recalculation */ + pc_calcstatus(bl->is_player(), (int)CalcStatusKind::NORMAL_RECALC); /* ステータス再計算 | Status Recalculation */ } int skill_update_heal_animation(dumb_ptr sd) @@ -1085,7 +1085,7 @@ int skill_status_effect(dumb_ptr bl, StatusChange type, bl->bl_id, type)); if (bl->bl_type == BL::PC && calc_flag) - pc_calcstatus(sd, 0); /* ステータス再計算 | Status recalculation */ + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); /* ステータス再計算 | Status recalculation */ if (bl->bl_type == BL::PC && updateflag != SP::ZERO) clif_updatestatus(sd, updateflag); /* ステータスをクライアントに送る | Send status to client */ diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp index 1d61070..f8350a7 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -333,6 +333,12 @@ enum class SP : uint16_t DEAF = 70, + KILLS = 490, + CASTS = 491, + ITEMS_USED = 492, + TILES_WALKED = 493, + ATTACKS = 494, + // sent to client GM = 500, -- cgit v1.2.3-60-g2f50 From 0c0b5719babfa474185bf7aab273dae1fc614c9e Mon Sep 17 00:00:00 2001 From: Jesusaves Date: Wed, 31 Jan 2024 18:33:58 -0300 Subject: Transfer something from local/ to live repository so there are less conflicts --- src/map/pc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index c7c6acf..e6b65b7 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1566,9 +1566,9 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->attack_spell_override || first & (int)CalcStatusKind::MAGIC_OVERRIDE) sd->aspd = sd->attack_spell_delay; - /* Red Threshold Calculation (TODO) */ + /* Red Threshold Calculation */ if (sd->aspd < 300_ms) { - sd->aspd = 300_ms + ((sd->aspd - 300_ms) * 20 / 20); + sd->aspd = 300_ms + ((sd->aspd - 300_ms) * 19 / 20); } sd->aspd = std::max(sd->aspd, battle_config.max_aspd); -- cgit v1.2.3-60-g2f50 From e9b49f5f827cbacc02ff9a54f158d363942d6fe5 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Thu, 1 Feb 2024 16:55:31 +0100 Subject: Fix bug whereby stat updates were not sent to client after equipping +1 stat pt item when base stat is 1. What is funnier is that it sent updates for all other 5 (unchanged stats). Example, amethyst ring +1 dex: Sending update for stat 0: saved: 0+1, new: 0+0 (str?) Sending update for stat 1: saved: 0+1, new: 0+0 (agi?) Sending update for stat 2: saved: 0+1, new: 0+0 (vit?) Sending update for stat 3: saved: 0+1, new: 0+0 (int?) Sending update for stat 5: saved: 0+1, new: 0+0 (luk?) --- src/map/pc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index e6b65b7..12af48f 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1135,7 +1135,7 @@ int pc_calcstatus(dumb_ptr sd, int first) b_weight = sd->weight; b_max_weight = sd->max_weight; earray b_paramb = sd->paramb; - earray b_parame = sd->paramc; + earray b_parame = sd->parame; earray b_skill = sd->status.skill; b_hit = sd->hit; b_flee = sd->flee; -- cgit v1.2.3-60-g2f50 From ad78e6a131143dbd18a47f03943f3be5eec00d01 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Wed, 13 Dec 2023 23:14:07 +0100 Subject: Enable GitLab CI +Add meway's Ubuntu +Add python -> python2 symlink +Separate python/python2 into INSTALL_PACKAGES --- .gitlab-ci.yml | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..67559b8 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,52 @@ +# Copied in from Moubootaur Legends's Hercules .gitlab-ci.yml +stages: + - build + +variables: &base_vars + DEBIAN_COMMON_PACKAGES: make git gcc g++ + # Depth of clone. If no tag is made after this many commits, then + # the git describe call and version header generation will fail. + GIT_DEPTH: 100 # Will break again eventually. + +.prerequisites: &prerequisites + before_script: + - echo "Building TMW Athena $CI_BUILD_NAME" + - uname -a + - apt-get update + - apt-get install -y -qq $INSTALL_PACKAGES $DEBIAN_COMMON_PACKAGES + + +# Active server OS? +re:ubuntu1804:build: + <<: *prerequisites + stage: build + image: ubuntu:18.04 + variables: + <<: *base_vars + INSTALL_PACKAGES: python + script: + - git submodule update --init + - git fetch -t + - printf "Building TMW Athena version %s\n" "$(git describe --tags HEAD)" + - ./configure --user + - make + - whoami + - make install + +# Next server OS? +re:ubuntu2204:build: + <<: *prerequisites + stage: build + image: ubuntu:22.04 + variables: + <<: *base_vars + INSTALL_PACKAGES: python2 + script: + - ln -s /usr/bin/python2 /usr/bin/python + - git submodule update --init + - git fetch -t + - printf "Building TMW Athena version %s\n" "$(git describe --tags HEAD)" + - ./configure --user + - make + - whoami + - make install -- cgit v1.2.3-60-g2f50 From a2c628a405e6ecdf4cb4a10cc0b2dee9805a633a Mon Sep 17 00:00:00 2001 From: Thorbjørn Lindeijer Date: Tue, 20 Feb 2024 02:46:34 +0000 Subject: tools/protocol.py: Added generation of client code This helps with keeping the protocol in the Mana client up to date. **** --- tools/protocol.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/tools/protocol.py b/tools/protocol.py index 7419639..cf89a16 100755 --- a/tools/protocol.py +++ b/tools/protocol.py @@ -984,6 +984,18 @@ class BasePacket(object): d[p].post_set(d, n - 1 + (len(self.post) == 1), accum) return accum + def dump_client_enum(self, f): + id = self.id + define = self.define + name = self.name + if define and id: + f.write(' %s ' % define) + f.write(' ' * (30 - len(define))) + f.write('= 0x%04x,' % id) + if name: + f.write(" // " + name) + f.write('\n') + class FixedPacket(BasePacket): __slots__ = ('fixed_struct') @@ -1016,6 +1028,15 @@ class FixedPacket(BasePacket): self.fixed_struct.dump_convert(f) f.write('\n') + def dump_client_packet_info(self, f): + size = self.fixed_struct.size + define = self.define + if define and id: + f.write(' { %s, ' % define) + f.write(' ' * (30 - len(define))) + f.write('%d, "%s" },' % (size, define)) + f.write('\n') + class VarPacket(BasePacket): __slots__ = ('head_struct', 'repeat_struct') @@ -1053,6 +1074,14 @@ class VarPacket(BasePacket): self.repeat_struct.dump_convert(f) f.write('\n') + def dump_client_packet_info(self, f): + define = self.define + if define and id: + f.write(' { %s, ' % define) + f.write(' ' * (30 - len(define))) + f.write('VAR, "%s" },' % define) + f.write('\n') + def sanitize_line(line, n): if not line: return line @@ -1181,6 +1210,20 @@ class Channel(object): p.dump_convert(f) f.write('} // namespace tmwa\n') + def dump_client_enum(self, f): + if any(p.define and p.id for p in self.packets): + f.write(' // %s server messages\n' % self.server) + for p in self.packets: + p.dump_client_enum(f) + f.write('\n') + + def dump_client_packet_info(self, f): + if any(p.define and p.id for p in self.packets): + f.write(' // %s server messages\n' % self.server) + for p in self.packets: + p.dump_client_packet_info(f) + f.write('\n') + ident_translation = ''.join(chr(c) if chr(c).isalnum() else '_' for c in range(256)) @@ -1293,6 +1336,20 @@ class Context(object): ty.dump(f) f.write('} // namespace tmwa\n') + # for net/tmwa/protocol.h in Mana client + with OpenWrite(os.path.join(outdir, 'client-enum.hpp')) as f: + f.write('enum {\n') + for ch in self._channels: + ch.dump_client_enum(f) + f.write('};\n') + + # for net/tmwa/network.cpp in Mana client + with OpenWrite(os.path.join(outdir, 'client-packet-info.cpp')) as f: + f.write('static const PacketInfo packet_infos[] = {\n') + for ch in self._channels: + ch.dump_client_packet_info(f) + f.write('};\n') + for g in glob.glob(os.path.join(outdir, '*.old')): print('Obsolete: %s' % g) os.remove(g) @@ -3651,7 +3708,7 @@ def build_context(): ''', ) map_user.r(0x00f5, 'storage take', - define='CSMG_MOVE_FROM_STORAGE', + define='CMSG_MOVE_FROM_STORAGE', fixed=[ at(0, u16, 'packet id'), at(2, soff1, 'soff1'), @@ -6267,6 +6324,7 @@ def build_context(): # TOC_MISC # any client any_user.r(0x7530, 'version', + define='CMSG_SERVER_VERSION_REQUEST', fixed=[ at(0, u16, 'packet id'), ], @@ -6278,6 +6336,7 @@ def build_context(): ''', ) any_user.s(0x7531, 'version result', + define='SMSG_SERVER_VERSION_RESPONSE', fixed=[ at(0, u16, 'packet id'), at(2, version, 'version'), @@ -6290,6 +6349,7 @@ def build_context(): ''', ) any_user.r(0x7532, 'disconnect', + define='CMSG_CLIENT_DISCONNECT', fixed=[ at(0, u16, 'packet id'), ], @@ -6300,9 +6360,6 @@ def build_context(): Request from client or ladmin to disconnect. ''', ) - # 0x7530 define='CMSG_SERVER_VERSION_REQUEST', - # 0x7531 define='SMSG_SERVER_VERSION_RESPONSE', - # 0x7532 define='CMSG_CLIENT_DISCONNECT', # TOC_LOGINADMIN # login admin @@ -6937,7 +6994,7 @@ def build_context(): delete a login-stored ##register of an account. ''', ) - + # TOC_NEW ## new-style packets # notify packets, standalone, can occur at any time; always 'payload' -- cgit v1.2.3-60-g2f50 From b5acf91dfe7057b8effaf2f23afebb200448cd97 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Tue, 16 Jan 2024 18:02:10 +0100 Subject: Update test cases for addition of Item Mode field See "Item Mode" commit from Apr 3 2023 --- src/ast/item_test.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ast/item_test.cpp b/src/ast/item_test.cpp index 7e5f1a9..33ed9cb 100644 --- a/src/ast/item_test.cpp +++ b/src/ast/item_test.cpp @@ -87,11 +87,11 @@ namespace item QuietFd q; LString inputs[] = { - // 1 2 3 4 5 - //2345678901234567890123456789012345678901234567890123456789 - "1,abc , 3,4,5,6,7,8,9,10,xx,2,16,12,13,11, {end;}, {}"_s, - "1,abc , 3,4,5,6,7,8,9,10,xx,2,16,12,13,11, {end;}, {}\n"_s, - "1,abc , 3,4,5,6,7,8,9,10,xx,2,16,12,13,11, {end;}, {}\nabc"_s, + // 1 2 3 4 5 6 + //23456789012345678901234567890123456789012345678901234567890123456789 + "1,abc , 3,4,5,6,7,8,9,10,xx,2,16,12,13,11,1, {end;}, {}"_s, + "1,abc , 3,4,5,6,7,8,9,10,xx,2,16,12,13,11,1, {end;}, {}\n"_s, + "1,abc , 3,4,5,6,7,8,9,10,xx,2,16,12,13,11,1, {end;}, {}\nabc"_s, }; for (auto input : inputs) { @@ -99,7 +99,7 @@ namespace item auto res = TRY_UNWRAP(parse_item(lr), FAIL()); EXPECT_TRUE(res.get_success().is_some()); auto top = TRY_UNWRAP(std::move(res.get_success()), FAIL()); - EXPECT_SPAN(top.span, 1,1, 1,58); + EXPECT_SPAN(top.span, 1,1, 1,60); auto p = top.get_if(); EXPECT_TRUE(p); if (p) @@ -136,9 +136,11 @@ namespace item EXPECT_EQ(p->elv.data, 13); EXPECT_SPAN(p->view.span, 1,45, 1,46); EXPECT_EQ(p->view.data, ItemLook::W_BOW); - EXPECT_SPAN(p->use_script.span, 1,49, 1,54); + EXPECT_SPAN(p->mode.span, 1,48, 1,48); + EXPECT_EQ(p->mode.data, ItemMode::NO_DROP); + EXPECT_SPAN(p->use_script.span, 1,51, 1,56); EXPECT_EQ(p->use_script.braced_body, "{end;}"_s); - EXPECT_SPAN(p->equip_script.span, 1,57, 1,58); + EXPECT_SPAN(p->equip_script.span, 1,59, 1,60); EXPECT_EQ(p->equip_script.braced_body, "{}"_s); } } -- cgit v1.2.3-60-g2f50 From 790c57e165648bcf11d01960d0f8e50ebf1c3074 Mon Sep 17 00:00:00 2001 From: Thorbjørn Lindeijer Date: Wed, 6 Mar 2024 09:33:00 +0100 Subject: Restored README.md visibility * Removed the
tag used to hide the main contents. * Removed deprecation notice, since we're still running this server and will need to maintain it until it has been replaced. * Deleted the section about tmwa-monitor, since the tool is not just deprecated but actually was deleted in 53a91a3fbf0929a99abcdfea23126f978c3ce71a. This partly reverts da50c517000391c83305ff704e3059c900f28d5b. --- README.md | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 2b61743..95a5903 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,10 @@ ![The Mana World logo](share/tmwa/TheManaWorldLogo.png) -This is TMWA, an MMORPG server used by The Mana World Legacy that uses a -protocol based on one of many projects that foolishly chose the name "Athena". +This is TMWA, an MMORPG server used by The Mana World that uses a protocol +based on one of many projects that foolishly chose the name "Athena". Specifically, it was forked from eAthena, a Ragnarok Online clone, in 2004. -# TMWA IS NO LONGER SUPPORTED! don't use this - -

- -
-click _here_ for the old readme - -
- Take a look at the [wiki](http://wiki.themanaworld.org/index.php/How_to_Develop) for user instructions. **Important note:** building from a github-generated tarball does not work! @@ -154,22 +145,6 @@ current working directory; this was the only thing that makes sense since the files are dependent on the server-data. However, a migration to installed files has begun. - -#### tmwa-monitor: -<DEPRECATED> -Formerly known as `eathena-monitor`. - -An unmaintained tool whose job was to keep restarting the servers -every time they crashed. It still builds in case anyone was using it, -but it proved inflexible and has't really been kept up-to-date with our -(TMW's) server-data, and besides, the server doesn't crash much now. -There are also a number of other Open Source programs that monitor -services already. - -There is a `run-all` script in the server-data repo that starts the -appropriate server for that config. On the main server, we instead -start the servers (and bots) individually in a tmux. - #### tmwa-admin: Formerly known as `ladmin` ("local"). @@ -275,4 +250,3 @@ The following skills are good to know required for various tasks: tasks. Particularly, reread the bit about review.) - C++11 (Not a low entry barrier. I'm not really expecting help with this, and since this is conflict heavy, please do the other tasks first). -
-- cgit v1.2.3-60-g2f50 From e1aa301c395afe399898d84c13297c4c2557ed52 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Sat, 9 Dec 2023 20:00:13 +0100 Subject: Correct issue with GTEST_DIR not being passed properly. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note how gcc uses /usr/include/gtest (default search path) as the -I for GTEST_DIR is not on the gcc command line: System-wide gtest is 1.14 and requires C++14 while provided one is 1.8.1. GTEST_DIR="$PWD/deps/googletest/googletest" ./configure --user make[1]: Leaving directory '/data/users/tmwa/proj/tmw/classic/tmwa' find: ‘doc-gen/’: No such file or directory g++ -std=c++0x -I . -I ./include -DGENERATING_DEPENDENCIES -O2 -g -fstack-protector -fno-strict-aliasing -fvisibility=hidden -fvisibility=hidden -MG -MM \ -MT 'ast/item_test := ' \ -MF obj/ast/item_test.d src/ast/item_test.cpp In file included from /usr/include/gtest/gtest-message.h:57, from /usr/include/gtest/gtest-assertion-result.h:46, from /usr/include/gtest/gtest.h:64, from src/ast/item_test.cpp:21: /usr/include/gtest/internal/gtest-port.h:270:2: error: #error C++ versions less than C++14 are not supported. 270 | #error C++ versions less than C++14 are not supported. | ^~~~~ Makefile:331: obj/ast/item_test.d: No such file or directory --- Makefile.in | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 610e7f6..10f909c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -492,8 +492,15 @@ lib/%.a: ${GTEST_BINARIES}: obj/gtest_main.pdc.o obj/gtest-all.pdc.o -# This isn't perfect. -$(filter %_test.pdc.o,${PDC_OBJECTS}) obj/gtest_main.pdc.o obj/gtest-all.pdc.o: override CPPFLAGS += -DGTEST_HAS_PTHREAD=0 -I${GTEST_DIR} +# Need gtest include for both compile (*_test.pdc.o) and dependency-generation (*_test.d) steps. +GTEST_NEED_INCLUDE := $(filter %_test.pdc.o,${PDC_OBJECTS}) $(filter %_test.d,${DEPENDS}) obj/gtest_main.pdc.o obj/gtest-all.pdc.o +${GTEST_NEED_INCLUDE}: override CXXFLAGS += -DGTEST_HAS_PTHREAD=0 -I${GTEST_DIR}/include + + +# Special rule for src/gtest-all.cc, it includes "src/gtest.cc" +# and thus additionally needs toplevel as include +obj/gtest-all.pdc.o: override CXXFLAGS += -DGTEST_HAS_PTHREAD=0 -I${GTEST_DIR} + obj/gtest-all.pdc.o obj/gtest_main.pdc.o: override WARNINGS := obj/gtest%.pdc.o: ${GTEST_DIR}/src/gtest%.cc $(MKDIR_FIRST) -- cgit v1.2.3-60-g2f50 From cc086e08c128763762b3fa67c6d2771b88d84d9d Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Sun, 10 Dec 2023 22:10:58 +0100 Subject: Add googletest-1.8.1 as a submodule - gtest-1.14 shipped by my distro requires C++14. --- .gitmodules | 3 +++ configure | 8 +++++++- deps/googletest | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) create mode 160000 deps/googletest diff --git a/.gitmodules b/.gitmodules index 931035d..8197e60 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "deps/attoconf"] path = deps/attoconf url = https://github.com/o11c/attoconf.git +[submodule "deps/googletest"] + path = deps/googletest + url = https://github.com/google/googletest.git diff --git a/configure b/configure index 67bcf53..aa1d0fd 100755 --- a/configure +++ b/configure @@ -84,7 +84,13 @@ class Configuration(Cxx, Install, ConfigHash, Templates): def vars(self): super(Configuration, self).vars() - self.add_option('GTEST_DIR', init='/usr/src/gtest', + # Why submodule gtest? + # 1) make test requires gtest-all.cc. This file is shipped by Ubuntu, + # but not by Gentoo; + # 2) Modern distros ship gtest-1.13+. It requires C++14+, while + # TMWA is currently a C++0x codebase. + self.add_option('GTEST_DIR', + init=os.path.join(os.getcwd(), 'deps/googletest/googletest'), # http://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog type=filepath, check=lambda build, GTEST_DIR: None, help='Location of Google Test sources, must contain src/gtest-all.cc (linking to a precompiled library is NOT supported)', hidden=False) diff --git a/deps/googletest b/deps/googletest new file mode 160000 index 0000000..2fe3bd9 --- /dev/null +++ b/deps/googletest @@ -0,0 +1 @@ +Subproject commit 2fe3bd994b3189899d93f1d5a881e725e046fdc2 -- cgit v1.2.3-60-g2f50 From 581490f804832b479abda46a52cefd4218cbf910 Mon Sep 17 00:00:00 2001 From: Thorbjørn Lindeijer Date: Mon, 11 Mar 2024 14:40:08 +0000 Subject: Several updates to the README.md It's no longer maintained by o11c since many years now, so an update was long due. Also updated some outdated links. Finally, who can say for sure that The Mana World will never run on Manaserv? --- README.md | 68 +++++++++++++++++---------------------------------------------- 1 file changed, 18 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 95a5903..b2309f5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Specifically, it was forked from eAthena, a Ragnarok Online clone, in 2004. Take a look at the [wiki](http://wiki.themanaworld.org/index.php/How_to_Develop) for user instructions. -**Important note:** building from a github-generated tarball does not work! +**Important note:** building from a GitHub-generated tarball does not work! You must either build from a git checkout or from a 'make dist' tarball. @@ -17,24 +17,14 @@ The rest of this file contains information relevant only to: 1. Distributors. 2. Contributors. - -TMWA has been maintained by o11c (Ben Longbons) since early 2011 or so. -Before that, it never really had a proper maintainer, since everyone -thought that ManaServ was going to be the thing. But it won't ever be, -at least not for TMW. - -TMWA has a [bugtracker](https://github.com/themanaworld/tmwa/issues). +TMWA has a [bugtracker](https://git.themanaworld.org/legacy/tmwa/-/issues). But it's probably worth getting on IRC first: -* Use an IRC client: irc://chat.freenode.net/tmwa -* Or just use the [webchat](https://webchat.freenode.net/?channels=#tmwa). - -Note that this channel is *only* for technical discussion of TMWA (and -attoconf), not general chat or TMW content development. +* Use an IRC client: irc://irc.libera.chat/themanaworld-dev +* Or just use the [webchat](https://web.libera.chat/?channel=#themanaworld-dev). -I'm active in the Pacific timezone, but I might not have internet access -all the time. I'm usually never AFK longer than 48 hours; when there is an -exception, I always tell the content devs who also idle there. +Note that this channel is not specific to technical discussion of TMWA (and +attoconf), but for any discussions related to TMW development. ## 1. Distributors. ### Important notes: @@ -196,7 +186,7 @@ developers get annoyed when wushin makes us work straight from his client-data repo. Currently, there is only *one* set of server data that is known to be -compatible with TMWA: https://github.com/themanaworld/tmwa-server-data +compatible with TMWA: https://git.themanaworld.org/legacy/serverdata The only recommended way of using this is by following the instructions in the [How to Develop](https://wiki.themanaworld.org/index.php/Dev:How_to_Develop) article. These instructions are only designed @@ -217,36 +207,14 @@ Note also that The Mana World has not investigated the copyright status of other sets of server data. ## 2. Contributors. -The most important thing if you want to help improve TMWA is *talk* to me. -No, wait, that's the second most important thing. - -The real most important thing if you want to help improve TMWA is that it's -*work*. You can't just stop by and chat for a few hours and help at all. -If you're going to work on TMWA, you have to be work months in the future. - -TMWA was terrible when I got it, and I've only fixed enough to make it -sane, not pretty. Even a minimal change is likely to touch the whole tree, -so merge conflicts are a constant problem. - -That said, there *are* several tasks that I could use help with. Several -essential tasks have been left undone just because they don't conflict with -the main body of my work. - -But I do not want someone who will just work for a few hours, go to bed, -then never return. I have wasted far too many hours answering their -questions. If you're going to help, you have to actually *help*. - -The following skills are good to know required for various tasks: - - - ability to read - - ability to write - - ability to notice error messages - - ability to solve your own problems - - willingness to accept review of your changes. It's not personal if I - say your work is wrong, I'm just seeing more than you do, and tiny - details are often incredibly important. - - familiarity with gdb - - Python (A low entry barrier, but Python alone is not enough for the - tasks. Particularly, reread the bit about review.) - - C++11 (Not a low entry barrier. I'm not really expecting help with this, - and since this is conflict heavy, please do the other tasks first). + +You're welcome to help maintain this server, but please make sure to +get in touch with the currently active maintainers first. + +Remember that this server is what currently keeps The Mana World alive, +so any changes should be made with extreme care. It is important that +each change be tested and reviewed before it goes live. + +Finally, if you got yourself somewhat familiar with this code, please +consider sticking around either to fix further issues as they come up +or to help reviewing changes by others. Thanks! -- cgit v1.2.3-60-g2f50 From 6071d37c4127aafef84ba1144ac1055972426116 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Sun, 28 Jan 2024 13:52:38 +0100 Subject: Workaround "Function... not defined in.." (breakpoints not found) (GDB bug) Function "_Z13do_breakpointIN4tmwa3map11script_dataEEvRKT_PKc" not defined in "/builds/specing/tmwa/src/debug-debug/map-script-persist.cpp". Breakpoint 1 (/builds/specing/tmwa/src/debug-debug/map-script-persist.cpp:'_Z13do_breakpointIN4tmwa3map11script_dataEEvRKT_PKc') pending. void do_breakpoint(tmwa::map::script_data const&, char const*); Thanks to ssbssa@#gdb for pointing this out. --- tools/debug-debug.gdb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/debug-debug.gdb b/tools/debug-debug.gdb index 2e59437..b50a49b 100644 --- a/tools/debug-debug.gdb +++ b/tools/debug-debug.gdb @@ -42,8 +42,21 @@ set print frame-arguments none set python print-stack full set logging on -rbreak do_breakpoint +# Workaround "Function... not defined in.." (breakpoints not found) (GDB bug) +# https://sourceware.org/bugzilla/show_bug.cgi?id=15962 +# In some gdb versions rbreak works, in some break does. +# This code should work for any. +python +bpoint = gdb.Breakpoint("do_breakpoint") + +if bpoint.pending: + print("`break ...` found no breakpoints, trying `rbreak ...`") + bpoint.delete() + gdb.execute("rbreak do_breakpoint") + +end set logging off + commands silent python hit_breakpoint() -- cgit v1.2.3-60-g2f50 From ebf078b9fa81142834dc45e22ea661a61c50d17b Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Thu, 14 Dec 2023 23:22:52 +0100 Subject: Add CI test stage +Pass artifacts (well, the whole repo) to test stage +YAML syntax error. Since I saw a glimpse of the repo being reinitialised two tries ago, perhaps it saves everything tracked and just adding untracked files should be enough. --- .gitlab-ci.yml | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 67559b8..f7c750a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ # Copied in from Moubootaur Legends's Hercules .gitlab-ci.yml stages: - build + - test variables: &base_vars DEBIAN_COMMON_PACKAGES: make git gcc g++ @@ -10,7 +11,6 @@ variables: &base_vars .prerequisites: &prerequisites before_script: - - echo "Building TMW Athena $CI_BUILD_NAME" - uname -a - apt-get update - apt-get install -y -qq $INSTALL_PACKAGES $DEBIAN_COMMON_PACKAGES @@ -25,6 +25,7 @@ re:ubuntu1804:build: <<: *base_vars INSTALL_PACKAGES: python script: + - echo "Building TMW Athena $CI_BUILD_NAME" - git submodule update --init - git fetch -t - printf "Building TMW Athena version %s\n" "$(git describe --tags HEAD)" @@ -32,6 +33,12 @@ re:ubuntu1804:build: - make - whoami - make install + artifacts: # required for test stage + untracked: true + expire_in: 30 mins + + + # Next server OS? re:ubuntu2204:build: @@ -50,3 +57,35 @@ re:ubuntu2204:build: - make - whoami - make install + artifacts: # required for test stage + untracked: true + expire_in: 30 mins + + + + +# Disabled. fails with: +# (1) GDB failing to resolve a type +# (2) /usr/bin/ld: Dwarf Error: Can't find .debug_ranges section. +.re:ubuntu1804:test: + <<: *prerequisites + stage: test + image: ubuntu:18.04 + variables: + <<: *base_vars + INSTALL_PACKAGES: python gdb + script: + - printf "Testing TMW Athena version %s\n" "$(git describe --tags HEAD)" + - make test + +re:ubuntu2204:test: + <<: *prerequisites + stage: test + image: ubuntu:22.04 + variables: + <<: *base_vars + INSTALL_PACKAGES: python2 gdb + script: + - ln -s /usr/bin/python2 /usr/bin/python + - printf "Testing TMW Athena version %s\n" "$(git describe --tags HEAD)" + - make test -- cgit v1.2.3-60-g2f50