From 01a27d4af7e54736a7922aec23f6f4e3e21f0965 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Wed, 10 Apr 2024 16:00:04 +0200 Subject: Report (hardcoded) drop rates on same line as base/job exp, reword messages. --- src/map/atcommand.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index eaefd4f..d9ec555 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1681,7 +1681,7 @@ ATCE atcommand_exprate(Session *s, dumb_ptr, } battle_config.base_exp_rate = rate; battle_config.job_exp_rate = rate; - AString output = STRPRINTF("All Xp at %d percent"_fmt, rate); + AString output = STRPRINTF("Base & job XP rates now at %d percent"_fmt, rate); clif_displaymessage(s, output); return ATCE::OKAY; } @@ -1690,9 +1690,9 @@ static ATCE atcommand_rates(Session *s, dumb_ptr, ZString message) { - AString output = STRPRINTF("Experience rates: Base %d%% / Job %d%%"_fmt, battle_config.base_exp_rate, battle_config.job_exp_rate); - clif_displaymessage(s, output); - output = STRPRINTF("Drop rate: 100%%"_fmt); + AString output = STRPRINTF( + "Experience rates: Base %d%% / Job %d%%. Drop rate: 100%%"_fmt, + battle_config.base_exp_rate, battle_config.job_exp_rate); clif_displaymessage(s, output); return ATCE::OKAY; } @@ -5599,10 +5599,10 @@ Map atcommand_info = "Enable PvP on your map"_s}}, {"exprate"_s, {""_s, 60, atcommand_exprate, - "Set base job/exp rate"_s}}, + "Set base and job exp rate"_s}}, {"rates"_s, {""_s, 0, atcommand_rates, - "Show base job/exp rate"_s}}, + "Show base and job exp rates"_s}}, {"pvpon"_s, {""_s, 60, atcommand_pvpon, "Disable PvP on your map"_s}}, -- cgit v1.2.3-70-g09d2 From 0fb2ce09aeec67550a41f7027db5b68a6a8b06d7 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Wed, 10 Apr 2024 16:24:46 +0200 Subject: Split @exprate into @bexprate and @jexprate Preserve @exprate as a shortcut for both & because scripts in serverdata call it --- src/map/atcommand.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'src') diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index d9ec555..6901437 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1667,6 +1667,8 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr sd, return ATCE::OKAY; } +// Command not removed during bexprate/jexprate split +// because serverdata calls it. static ATCE atcommand_exprate(Session *s, dumb_ptr, ZString message) @@ -1686,6 +1688,42 @@ ATCE atcommand_exprate(Session *s, dumb_ptr, return ATCE::OKAY; } +static +ATCE atcommand_bexprate(Session *s, dumb_ptr, + ZString message) +{ + int rate; + + if (!extract(message, &rate) || !rate) + { + clif_displaymessage(s, + "Please, enter a rate adjustement (usage: @bexprate )."_s); + return ATCE::USAGE; + } + battle_config.base_exp_rate = rate; + AString output = STRPRINTF("Base XP rate now at %d percent"_fmt, rate); + clif_displaymessage(s, output); + return ATCE::OKAY; +} + +static +ATCE atcommand_jexprate(Session *s, dumb_ptr, + ZString message) +{ + int rate; + + if (!extract(message, &rate) || !rate) + { + clif_displaymessage(s, + "Please, enter a rate adjustement (usage: @jexprate )."_s); + return ATCE::USAGE; + } + battle_config.job_exp_rate = rate; + AString output = STRPRINTF("Job XP rate now at %d percent"_fmt, rate); + clif_displaymessage(s, output); + return ATCE::OKAY; +} + static ATCE atcommand_rates(Session *s, dumb_ptr, ZString message) @@ -5600,6 +5638,12 @@ Map atcommand_info = {"exprate"_s, {""_s, 60, atcommand_exprate, "Set base and job exp rate"_s}}, + {"bexprate"_s, {""_s, + 60, atcommand_bexprate, + "Set base exp rate"_s}}, + {"jexprate"_s, {""_s, + 60, atcommand_jexprate, + "Set job exp rate"_s}}, {"rates"_s, {""_s, 0, atcommand_rates, "Show base and job exp rates"_s}}, -- cgit v1.2.3-70-g09d2 From dc9c104ad231e6ba9f695072d36d586e2e3d3d4c Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Wed, 10 Apr 2024 16:43:21 +0200 Subject: Add server-wide drop rates modifier --- src/map/atcommand.cpp | 28 +++++++++++++++++++++++++--- src/map/mob.cpp | 3 +++ tools/config.py | 1 + 3 files changed, 29 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 6901437..20743dd 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1724,13 +1724,32 @@ ATCE atcommand_jexprate(Session *s, dumb_ptr, return ATCE::OKAY; } +static +ATCE atcommand_droprate(Session *s, dumb_ptr, + ZString message) +{ + int rate; + + if (!extract(message, &rate) || !rate) + { + clif_displaymessage(s, + "Please, enter a rate adjustement (usage: @droprate )."_s); + return ATCE::USAGE; + } + battle_config.drop_rate = rate; + AString output = STRPRINTF("Drops rate now at %d percent"_fmt, rate); + clif_displaymessage(s, output); + return ATCE::OKAY; +} + static ATCE atcommand_rates(Session *s, dumb_ptr, ZString message) { AString output = STRPRINTF( - "Experience rates: Base %d%% / Job %d%%. Drop rate: 100%%"_fmt, - battle_config.base_exp_rate, battle_config.job_exp_rate); + "Experience rates: Base %d%% / Job %d%%. Drop rate: %d%%"_fmt, + battle_config.base_exp_rate, battle_config.job_exp_rate, + battle_config.drop_rate); clif_displaymessage(s, output); return ATCE::OKAY; } @@ -5644,9 +5663,12 @@ Map atcommand_info = {"jexprate"_s, {""_s, 60, atcommand_jexprate, "Set job exp rate"_s}}, + {"droprate"_s, {""_s, + 60, atcommand_droprate, + "Set drop rate"_s}}, {"rates"_s, {""_s, 0, atcommand_rates, - "Show base and job exp rates"_s}}, + "Show base and job exp and drop rates"_s}}, {"pvpon"_s, {""_s, 60, atcommand_pvpon, "Disable PvP on your map"_s}}, diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 4fd9d6d..f2f6815 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2736,6 +2736,9 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, if (sd && md && battle_config.pk_mode == 1 && (get_mob_db(md->mob_class).lv - sd->status.base_level >= 20)) drop_rate.num *= 1.25; // pk_mode increase drops if 20 level difference [Valaris] + + // server-wide drop rate scaling + drop_rate.num = (drop_rate.num * battle_config.drop_rate) / 100; if (!random_::chance(drop_rate)) continue; diff --git a/tools/config.py b/tools/config.py index a187c06..49339bd 100755 --- a/tools/config.py +++ b/tools/config.py @@ -601,6 +601,7 @@ def build_config(): battle_conf.opt('item_third_get_time', milliseconds, '1_s') battle_conf.opt('base_exp_rate', percent, '100') battle_conf.opt('job_exp_rate', percent, '100') + battle_conf.opt('drop_rate', percent, '100') battle_conf.opt('death_penalty_type', i32, '0', min='0', max='2') battle_conf.opt('death_penalty_base', per10kd, '0') battle_conf.opt('death_penalty_job', per10kd, '0') -- cgit v1.2.3-70-g09d2 From 45d4a85fe4b9e6804a454daab19bd41638aec874 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Fri, 12 Apr 2024 01:13:10 +0200 Subject: Add battle_config.max_rate limit (500). GMs cannot go above this Blame Ledmitz (: --- src/map/atcommand.cpp | 63 ++++++++++++++++++++++++++++----------------------- tools/config.py | 1 + 2 files changed, 36 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 20743dd..311ca76 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1667,20 +1667,38 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr sd, return ATCE::OKAY; } + + +static int extract_rate(Session *s, ZString message) +{ + int rate; + AString output; + + if (!extract(message, &rate)) + { + clif_displaymessage(s, "Please enter the new rate"_s); + return -1; + } + if (rate <= 0 || rate > battle_config.max_rate) + { + output = STRPRINTF("Rate adjustment must be between 1 and %d%%"_fmt, + battle_config.max_rate); + clif_displaymessage(s, output); + return -1; + } + return rate; +} + // Command not removed during bexprate/jexprate split // because serverdata calls it. static ATCE atcommand_exprate(Session *s, dumb_ptr, ZString message) { - int rate; - - if (!extract(message, &rate) || !rate) - { - clif_displaymessage(s, - "Please, enter a rate adjustement (usage: @exprate )."_s); + int rate = extract_rate(s, message); + if (rate < 0) return ATCE::USAGE; - } + battle_config.base_exp_rate = rate; battle_config.job_exp_rate = rate; AString output = STRPRINTF("Base & job XP rates now at %d percent"_fmt, rate); @@ -1692,14 +1710,10 @@ static ATCE atcommand_bexprate(Session *s, dumb_ptr, ZString message) { - int rate; - - if (!extract(message, &rate) || !rate) - { - clif_displaymessage(s, - "Please, enter a rate adjustement (usage: @bexprate )."_s); + int rate = extract_rate(s, message); + if (rate < 0) return ATCE::USAGE; - } + battle_config.base_exp_rate = rate; AString output = STRPRINTF("Base XP rate now at %d percent"_fmt, rate); clif_displaymessage(s, output); @@ -1710,14 +1724,10 @@ static ATCE atcommand_jexprate(Session *s, dumb_ptr, ZString message) { - int rate; - - if (!extract(message, &rate) || !rate) - { - clif_displaymessage(s, - "Please, enter a rate adjustement (usage: @jexprate )."_s); + int rate = extract_rate(s, message); + if (rate < 0) return ATCE::USAGE; - } + battle_config.job_exp_rate = rate; AString output = STRPRINTF("Job XP rate now at %d percent"_fmt, rate); clif_displaymessage(s, output); @@ -1728,14 +1738,10 @@ static ATCE atcommand_droprate(Session *s, dumb_ptr, ZString message) { - int rate; - - if (!extract(message, &rate) || !rate) - { - clif_displaymessage(s, - "Please, enter a rate adjustement (usage: @droprate )."_s); + int rate = extract_rate(s, message); + if (rate < 0) return ATCE::USAGE; - } + battle_config.drop_rate = rate; AString output = STRPRINTF("Drops rate now at %d percent"_fmt, rate); clif_displaymessage(s, output); @@ -1754,6 +1760,7 @@ ATCE atcommand_rates(Session *s, dumb_ptr, return ATCE::OKAY; } + static ATCE atcommand_pvpon(Session *s, dumb_ptr sd, ZString) diff --git a/tools/config.py b/tools/config.py index 49339bd..2f0781d 100755 --- a/tools/config.py +++ b/tools/config.py @@ -602,6 +602,7 @@ def build_config(): battle_conf.opt('base_exp_rate', percent, '100') battle_conf.opt('job_exp_rate', percent, '100') battle_conf.opt('drop_rate', percent, '100') + battle_conf.opt('max_rate', percent, '500') battle_conf.opt('death_penalty_type', i32, '0', min='0', max='2') battle_conf.opt('death_penalty_base', per10kd, '0') battle_conf.opt('death_penalty_job', per10kd, '0') -- cgit v1.2.3-70-g09d2 From b301141dd36b0dc5d7289ffe504e17cf4c2921e1 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Sat, 20 Apr 2024 18:35:55 +0000 Subject: npc: Deregister events with `ev_db` on free In serverdata@c3b7fe59a, `magic-knuckles` made use of temporary copies of the spell NPC via `puppet`/`destroy` to provide additional functionality. This implementation was correct with respect to tmwa behaviour as documented. However, `puppet` and `destroy` doesn't quite return the server to a clean prior state. In `builtin_puppet`, events with the fresh new copy of NPC are registered into the global `ev_db` map to track named events, such as `OnDischarge`, which might be triggered later. However, these registrations are not reversed with `destroy`, leaving `ev_db` to retain references to now invalid and destroyed NPCs. serverdata@c3b7fe59a revealed this oversight through an intersection of rare conditions: - An NPC that is routinely cloned and destroyed - Having a variety of events - Including one that can be triggered during a search for the event over ALL NPCs when `#discharge` is cast. To reproduce, compile with `-fsanitize=address -fsanitize=undefined` to more reliably catch use of invalid memory, cast `magic-knuckles`, log out the character which cast `magic-knuckles` to destroy the NPC, log back in, then cast `#discharge`. The server will then crash. Special thanks to SystemError for testing out this theory. Currently lacking a test environment of my own, this would not have been possible without his patience and diligence. --- src/map/npc.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/map/npc.cpp b/src/map/npc.cpp index ee2f30c..efb2ba3 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -1050,6 +1050,18 @@ void npc_free_internal(dumb_ptr nd_) nd_->bl_m->npc[nd_->n] = nullptr; } + // Also clean up any events we registered to the global ev_db + if (auto nd = nd_->is_script()) + { + for (auto& pair : ev_db) + { + if (pair.second.nd == nd) + { + ev_db.erase(pair.first); + } + } + } + nd_.delete_(); } -- cgit v1.2.3-70-g09d2 From 3f214c06c13dfc4c4eb42a3f24553d7a1d30b26d Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 18 Apr 2024 00:46:16 +0200 Subject: getmapmaxx getmapmaxy --- src/map/script-fun.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 8dc1989..2be0333 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -5471,6 +5471,30 @@ void builtin_getmap(ScriptState *st) push_str(st->stack, sd->bl_m->name_); } +/*========================================== + * Get the maximum x coordinate of a map + *------------------------------------------ + */ +static +void builtin_getmapmaxx(ScriptState *st) +{ + MapName mapname = stringish(ZString(conv_str(st, &AARG(0)))); + P m = TRY_UNWRAP(map_mapname2mapid(mapname), return); + push_int(st->stack, m->xs-1); +} + +/*========================================== + * Get the maximum y coordinate of a map + *------------------------------------------ + */ +static +void builtin_getmapmaxy(ScriptState *st) +{ + MapName mapname = stringish(ZString(conv_str(st, &AARG(0)))); + P m = TRY_UNWRAP(map_mapname2mapid(mapname), return); + push_int(st->stack, m->ys-1); +} + /*========================================== * Get the NPC's info *------------------------------------------ @@ -5732,6 +5756,8 @@ BuiltinFunction builtin_functions[] = BUILTIN(getnpcy, "?"_s, 'i'), BUILTIN(strnpcinfo, "i?"_s, 's'), BUILTIN(getmap, "?"_s, 's'), + BUILTIN(getmapmaxx, "M"_s, 'i'), + BUILTIN(getmapmaxy, "M"_s, 'i'), BUILTIN(mapexit, ""_s, '\0'), BUILTIN(freeloop, "i"_s, '\0'), BUILTIN(if_then_else, "iii"_s, 'v'), -- cgit v1.2.3-70-g09d2 From ae2556ec8fcbfed9e18d275a578f4bc47d26f721 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Sun, 21 Apr 2024 06:43:43 +0000 Subject: DB: Maybe fix concurrent modification --- src/generic/db.hpp | 4 ++++ src/map/npc.cpp | 10 +++------- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/generic/db.hpp b/src/generic/db.hpp index 04ead79..d610f32 100644 --- a/src/generic/db.hpp +++ b/src/generic/db.hpp @@ -78,6 +78,10 @@ public: { return borrow(impl[k]); } + void erase_if(std::function&)> predicate) + { + std::erase_if(impl, predicate); + } void erase(const K& k) { impl.erase(k); diff --git a/src/map/npc.cpp b/src/map/npc.cpp index efb2ba3..76f0e14 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -1053,13 +1053,9 @@ void npc_free_internal(dumb_ptr nd_) // Also clean up any events we registered to the global ev_db if (auto nd = nd_->is_script()) { - for (auto& pair : ev_db) - { - if (pair.second.nd == nd) - { - ev_db.erase(pair.first); - } - } + ev_db.erase_if([&](auto& pair) { + return pair.second.nd == nd; + }); } nd_.delete_(); -- cgit v1.2.3-70-g09d2 From f31f51ae0fa0ce8f34de747dec3ed57a3f5373cd Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Sun, 21 Apr 2024 07:09:23 +0000 Subject: DB/npc_free_internal: Use ancient approach C++11 was a really long time ago, huh? --- src/generic/db.hpp | 4 ---- src/map/npc.cpp | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/generic/db.hpp b/src/generic/db.hpp index d610f32..04ead79 100644 --- a/src/generic/db.hpp +++ b/src/generic/db.hpp @@ -78,10 +78,6 @@ public: { return borrow(impl[k]); } - void erase_if(std::function&)> predicate) - { - std::erase_if(impl, predicate); - } void erase(const K& k) { impl.erase(k); diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 76f0e14..e8d6d4b 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -1053,9 +1053,18 @@ void npc_free_internal(dumb_ptr nd_) // Also clean up any events we registered to the global ev_db if (auto nd = nd_->is_script()) { - ev_db.erase_if([&](auto& pair) { - return pair.second.nd == nd; - }); + std::vector to_erase; + for (auto& pair : ev_db) + { + if (pair.second.nd == nd) + { + to_erase.push_back(pair.first); + } + } + for (auto& key : to_erase) + { + ev_db.erase(key); + } } nd_.delete_(); -- cgit v1.2.3-70-g09d2 From 18b88038af1750288fed389c4674a3a71786b5fd Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Fri, 12 Apr 2024 17:51:49 +0200 Subject: Fix -Wformat warnings --- src/admin/ladmin.cpp | 2 +- src/map/atcommand.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index 6e8642b..f538069 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -2571,7 +2571,7 @@ void parse_fromlogin(Session *s) } else { - PRINTF("Variables %i of %i used.\n"_fmt, repeat.size(), ACCOUNT_REG2_NUM); + PRINTF("Variables %zi of %zi used.\n"_fmt, repeat.size(), ACCOUNT_REG2_NUM); auto jlim = std::min(repeat.size(), ACCOUNT_REG2_NUM); for (size_t j = 0; j < jlim; ++j) PRINTF("Variable %s == `%i`\n"_fmt, repeat[j].name, repeat[j].value); diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 311ca76..bcfb1da 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1918,8 +1918,8 @@ ATCE atcommand_mobinfo(Session *s, dumb_ptr sd, 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("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())); + 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, static_cast(get_mob_db(mob_id).race), static_cast(get_mob_db(mob_id).element.element), get_mob_db(mob_id).element.level, static_cast(get_mob_db(mob_id).mode))); + clif_displaymessage(s, STRPRINTF("Speed: %li, Adelay: %li, Amotion: %li, Dmotion: %li"_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) clif_displaymessage(s, STRPRINTF("May mutate %i attribute up to %i%%"_fmt, get_mob_db(mob_id).mutations_nr, get_mob_db(mob_id).mutation_power)); @@ -2616,7 +2616,7 @@ ATCE atcommand_character_stats_full(Session *s, dumb_ptr, pl_sd->def2, pl_sd->def2_rate); clif_displaymessage(s, output); - output = STRPRINTF("ADD_SPEED: %d | SPEED_RATE: %d | SPEED_ADDRATE: %d | ASPD: %d | ASPD_RATE: %d | ASPD_ADDRATE: %d"_fmt, + output = STRPRINTF("ADD_SPEED: %ld | SPEED_RATE: %d | SPEED_ADDRATE: %d | ASPD: %ld | ASPD_RATE: %d | ASPD_ADDRATE: %d"_fmt, pl_sd->speed.count(), pl_sd->speed_rate, pl_sd->speed_add_rate, @@ -2640,7 +2640,7 @@ 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 | BASE_WEAPON_DELAY_ADJUST: %d"_fmt, + output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d | BASE_WEAPON_DELAY_ADJUST: %ld"_fmt, pl_sd->deadly_strike, pl_sd->deadly_strike_add_rate, pl_sd->base_weapon_delay_adjust.count()); -- cgit v1.2.3-70-g09d2 From 254a60784bd69642afadc3188ae593b738a20a93 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Fri, 12 Apr 2024 17:52:27 +0200 Subject: Fix Wformat-zero-length warnings Squash with: remove empty lines --- src/admin/ladmin.cpp | 1 - src/char/char.cpp | 2 -- src/login/login.cpp | 2 -- 3 files changed, 5 deletions(-) (limited to 'src') diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index f538069..240582b 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -2789,7 +2789,6 @@ int do_init(Slice argv) admin::eathena_interactive_session = isatty(0); - LADMIN_LOG(""_fmt); LADMIN_LOG("Configuration file readed.\n"_fmt); Iprintf("EAthena login-server administration tool.\n"_fmt); diff --git a/src/char/char.cpp b/src/char/char.cpp index 70ad049..a7f1490 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -2900,8 +2900,6 @@ int do_init(Slice argv) if (!loaded_config_yet) runflag &= load_config_file("conf/tmwa-char.conf"_s, char_::char_confs); - // a newline in the log... - CHAR_LOG(""_fmt); CHAR_LOG("do_init: char-server starting...\n"_fmt); runflag &= lan_check(); diff --git a/src/login/login.cpp b/src/login/login.cpp index 8f3aa70..e4c1197 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -3104,8 +3104,6 @@ bool display_conf_warnings(void) static void save_config_in_log(void) { - // a newline in the log... - LOGIN_LOG(""_fmt); LOGIN_LOG("The login-server starting...\n"_fmt); // save configuration in log file -- cgit v1.2.3-70-g09d2 From c6f6862303b28323f039a0b3bb17a189ce136658 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Fri, 12 Apr 2024 16:53:52 +0200 Subject: O(48logN) -> O(1logN) + reformat very long lines --- src/map/atcommand.cpp | 73 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index bcfb1da..346b0ac 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1914,22 +1914,47 @@ ATCE atcommand_mobinfo(Session *s, dumb_ptr sd, if (mob_id == Species()) return ATCE::EXIST; - 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("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, static_cast(get_mob_db(mob_id).race), static_cast(get_mob_db(mob_id).element.element), get_mob_db(mob_id).element.level, static_cast(get_mob_db(mob_id).mode))); - clif_displaymessage(s, STRPRINTF("Speed: %li, Adelay: %li, Amotion: %li, Dmotion: %li"_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) - clif_displaymessage(s, STRPRINTF("May mutate %i attribute up to %i%%"_fmt, get_mob_db(mob_id).mutations_nr, get_mob_db(mob_id).mutation_power)); + const struct mob_db_& mob = get_mob_db(mob_id); + + clif_displaymessage(s, STRPRINTF( + "Monster ID: %i, English Name: %s, Japanese Name: %s"_fmt, + mob_id, mob.name, mob.jname)); + clif_displaymessage(s, STRPRINTF( + "Level: %i, HP: %i, SP: %i, Base EXP: %i, JEXP: %i"_fmt, + mob.lv, mob.max_hp, mob.max_sp, mob.base_exp, mob.job_exp)); + clif_displaymessage(s, STRPRINTF( + "Range1: %i, ATK1: %i, ATK2: %i, DEF: %i, MDEF: %i, CRITICAL_DEF: %i"_fmt, + mob.range, mob.atk1, mob.atk2, + mob.def, mob.mdef, mob.critical_def)); + clif_displaymessage(s, STRPRINTF( + "Stats: STR: %i, AGI: %i, VIT: %i, INT: %i, DEX: %i, LUK: %i"_fmt, + mob.attrs[ATTR::STR], mob.attrs[ATTR::AGI], + mob.attrs[ATTR::VIT], mob.attrs[ATTR::INT], + mob.attrs[ATTR::DEX], mob.attrs[ATTR::LUK])); + clif_displaymessage(s, STRPRINTF( + "Range2: %i, Range3: %i, Scale: %i, Race: %i, Element: %i, Element Level: %i, Mode: %i"_fmt, + mob.range2, mob.range3, mob.size, static_cast(mob.race), + static_cast(mob.element.element), mob.element.level, + static_cast(mob.mode))); + clif_displaymessage(s, STRPRINTF( + "Speed: %li, Adelay: %li, Amotion: %li, Dmotion: %li"_fmt, + mob.speed.count(), mob.adelay.count(), + mob.amotion.count(), mob.dmotion.count())); + + if (mob.mutations_nr) + { + clif_displaymessage(s, STRPRINTF( + "May mutate %i attribute up to %i%%"_fmt, + mob.mutations_nr, mob.mutation_power)); + } for (int i = 0; i < MaxDrops; ++i) - if (get_mob_db(mob_id).dropitem[i].nameid) + if (mob.dropitem[i].nameid) { - Option> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[i].nameid)); + Option> i_data = Some(itemdb_search(mob.dropitem[i].nameid)); RString item_name = i_data.pmd_pget(&item_data::name).copy_or(stringish(""_s)); - int drop_rate = get_mob_db(mob_id).dropitem[i].p.num; + int drop_rate = mob.dropitem[i].p.num; char str[6]; char strpos = 0; @@ -1986,33 +2011,35 @@ 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, 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, mob.dropitem[i].nameid, item_name, str, drop_rate2)); } else break; clif_displaymessage(s, STRPRINTF("Mob Mode Info:"_fmt)); - if (!bool(get_mob_db(mob_id).mode & MobMode::ZERO)) + if (!bool(mob.mode & MobMode::ZERO)) { - if (bool(get_mob_db(mob_id).mode & MobMode::CAN_MOVE)) + if (bool(mob.mode & MobMode::CAN_MOVE)) clif_displaymessage(s, STRPRINTF("Mobile"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::LOOTER)) + if (bool(mob.mode & MobMode::LOOTER)) clif_displaymessage(s, STRPRINTF("Picks up loot"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::AGGRESSIVE)) + if (bool(mob.mode & MobMode::AGGRESSIVE)) clif_displaymessage(s, STRPRINTF("Aggro"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::ASSIST)) + if (bool(mob.mode & MobMode::ASSIST)) clif_displaymessage(s, STRPRINTF("Assists"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::CAST_SENSOR)) + if (bool(mob.mode & MobMode::CAST_SENSOR)) clif_displaymessage(s, STRPRINTF("Cast Sensor"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::BOSS)) + if (bool(mob.mode & MobMode::BOSS)) clif_displaymessage(s, STRPRINTF("Boss"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::PLANT)) + if (bool(mob.mode & MobMode::PLANT)) clif_displaymessage(s, STRPRINTF("Plant"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::CAN_ATTACK)) + if (bool(mob.mode & MobMode::CAN_ATTACK)) clif_displaymessage(s, STRPRINTF("Can attack"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::DETECTOR)) + if (bool(mob.mode & MobMode::DETECTOR)) clif_displaymessage(s, STRPRINTF("Detector"_fmt)); - if (bool(get_mob_db(mob_id).mode & MobMode::CHANGE_TARGET)) + if (bool(mob.mode & MobMode::CHANGE_TARGET)) clif_displaymessage(s, STRPRINTF("Change Target"_fmt)); /* Not needed here i guess -- cgit v1.2.3-70-g09d2 From 000cdca878911759643e18a9648c587e9730fa91 Mon Sep 17 00:00:00 2001 From: Fedja Beader Date: Fri, 12 Apr 2024 19:03:32 +0200 Subject: Fix warning: 'T& tmwa::Slice::operator[](size_t) is deprecated --- src/char/char.cpp | 14 +++++++++----- src/map/script-call.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/char/char.cpp b/src/char/char.cpp index a7f1490..7ffdd0f 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -1040,11 +1040,15 @@ int set_account_reg2(AccountId acc, Slice reg) { if (cd.key.account_id == acc) { - for (int i = 0; i < num; ++i) - cd.data->account_reg2[i] = reg[i]; - cd.data->account_reg2_num = num; - for (int i = num; i < ACCOUNT_REG2_NUM; ++i) - cd.data->account_reg2[i] = GlobalReg{}; + int i = 0; + for (const GlobalReg& r : reg) + cd.data->account_reg2[i++] = r; + + cd.data->account_reg2_num = i; + + while (i < ACCOUNT_REG2_NUM) + cd.data->account_reg2[i++] = GlobalReg{}; + c++; } } diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp index 76bae8d..f551ec4 100644 --- a/src/map/script-call.cpp +++ b/src/map/script-call.cpp @@ -1004,12 +1004,12 @@ int run_script_l(ScriptPointer sp, BlockId rid, BlockId oid, st.freeloop = 0; st.is_true = 0; - for (i = 0; i < args.size(); i++) + for (const argrec_t& arg : args) { - if (args[i].name.back() == '$') - pc_setregstr(sd, SIR::from(variable_names.intern(args[i].name)), args[i].v.s); + if (arg.name.back() == '$') + pc_setregstr(sd, SIR::from(variable_names.intern(arg.name)), arg.v.s); else - pc_setreg(sd, SIR::from(variable_names.intern(args[i].name)), args[i].v.i); + pc_setreg(sd, SIR::from(variable_names.intern(arg.name)), arg.v.i); } run_script_main(&st, rootscript); -- cgit v1.2.3-70-g09d2 From 96d1f29db8260ddd478391f87fb6299682f8ae55 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Mon, 15 Apr 2024 14:26:44 +0000 Subject: script_nullpo_end: Change error printf fmt -> arg PR !270 is an ongoing investigation into outstanding compiler warnings. One such warning is `warning: format '%s' expects a matching 'char*' argument` from `script_nullpo_end(nd, STRPRINTF("no such npc: '%s'"_fmt, name));` in `src/map/script-fun.cpp`. No such warning is emitted from a similar line in `src/map/atcommand.cpp`: `AString output = STRPRINTF("Jump to %s"_fmt, npc);`. `script_nullpo_end` is a macro, rather than a function. `error` is passed in verbatim by the preprocessor. The macro definition of `script_nullpo_end` includes lines such as the following: ```cpp PRINTF("script:%s: " #error " @ %s\n"_fmt, BUILTIN_NAME(), nullpo_nd->name); ``` `#` instructs the preprocessor to transform `` into a literal string. In this case, the string literal: ```cpp "STRPRINTF(\"no such npc: '%s'\"_fmt, name)" ``` So the entire line partly resolves to something like: ```cpp printf("script:%s: STRPRINTF(\"no such npc: '%s'\"_fmt, name) @ %s\n"_fmt, BUILTIN_NAME(), nullpo_nd->name); ``` Once the compiler sees this, it throws out the warning seen here, because printf is seeing three placeholders in the formatter, but is only given two value arguments. Checking with `gcc -E`, the full expansion is as follows: ```cpp if (nullpo_chk("script-fun.cpp", 4885, __PRETTY_FUNCTION__, nd)) { if (st->oid) { dumb_ptr nullpo_nd = map_id_is_npc(st->oid); if (nullpo_nd && nullpo_nd->name) { ({ struct format_impl { constexpr static FormatString print_format() __asm__("_print_format") { return "script:%s: " "STRPRINTF(\"no such npc: '%s'\"_fmt, npc)" " @ %s\n"_fmt; } }; cxxstdio::PrintFormatter::print(( # 4885 "script-fun.cpp" 3 4 stdout # 4885 "script-fun.cpp" ), (builtin_functions[st->stack->stack_datav[st->start].get_if()->numi].name), nullpo_nd->name); }); } else if (nullpo_nd) { ({ struct format_impl { constexpr static FormatString print_format() __asm__("_print_format") { return "script:%s: " "STRPRINTF(\"no such npc: '%s'\"_fmt, npc)" " (unnamed npc)\n"_fmt; } }; cxxstdio::PrintFormatter::print(( # 4885 "script-fun.cpp" 3 4 stdout # 4885 "script-fun.cpp" ), (builtin_functions[st->stack->stack_datav[st->start].get_if()->numi].name)); }); } else { ({ struct format_impl { constexpr static FormatString print_format() __asm__("_print_format") { return "script:%s: " "STRPRINTF(\"no such npc: '%s'\"_fmt, npc)" " (no npc)\n"_fmt; } }; cxxstdio::PrintFormatter::print(( # 4885 "script-fun.cpp" 3 4 stdout # 4885 "script-fun.cpp" ), (builtin_functions[st->stack->stack_datav[st->start].get_if()->numi].name)); }); } } else { ({ struct format_impl { constexpr static FormatString print_format() __asm__("_print_format") { return "script:%s: " "STRPRINTF(\"no such npc: '%s'\"_fmt, npc)" " (no npc)\n"_fmt; } }; cxxstdio::PrintFormatter::print(( # 4885 "script-fun.cpp" 3 4 stdout # 4885 "script-fun.cpp" ), (builtin_functions[st->stack->stack_datav[st->start].get_if()->numi].name)); }); } st->state = ScriptEndState::END; return; }; ``` Note the string literal: `"STRPRINTF(\"no such npc: '%s'\"_fmt, npc)"`. `script_nullpo_end` currently can't take as its argument for `error` any expression which, when stringified, contains something which `printf` will interpret as its formatter expecting another argument. This appears to have been broken since it was first introduced in https://git.themanaworld.org/legacy/tmwa/-/commit/594eafd4f231a897cbefd since the first revision implicitly had these requirements, and also introduced usage which didn't meet them. This rewrites each PRINTF line in `script_nullpo_end` from the template ```cpp PRINTF("script:%s: " #error " @ %s\n"_fmt, BUILTIN_NAME(), nullpo_nd->name); ``` to something like ```cpp PRINTF("script:%s: %s @ %s\n"_fmt, BUILTIN_NAME(), error, nullpo_nd->name); ``` This means that instead of an expression being stringified, error is interpreted as an expression that resolves (or decays) to a string. This seems consistent with all current usage of `script_nullpo_end`. --- src/map/script-fun.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 2be0333..deb781a 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -80,14 +80,14 @@ namespace map if (st->oid) { \ dumb_ptr nullpo_nd = map_id_is_npc(st->oid); \ if (nullpo_nd && nullpo_nd->name) { \ - PRINTF("script:%s: " #error " @ %s\n"_fmt, BUILTIN_NAME(), nullpo_nd->name); \ + PRINTF("script:%s: %s @ %s\n"_fmt, BUILTIN_NAME(), error, nullpo_nd->name); \ } else if (nullpo_nd) { \ - PRINTF("script:%s: " #error " (unnamed npc)\n"_fmt, BUILTIN_NAME()); \ + PRINTF("script:%s: %s (unnamed npc)\n"_fmt, BUILTIN_NAME(), error); \ } else { \ - PRINTF("script:%s: " #error " (no npc)\n"_fmt, BUILTIN_NAME()); \ + PRINTF("script:%s: %s (no npc)\n"_fmt, BUILTIN_NAME(), error); \ } \ } else { \ - PRINTF("script:%s: " #error " (no npc)\n"_fmt, BUILTIN_NAME()); \ + PRINTF("script:%s: %s (no npc)\n"_fmt, BUILTIN_NAME(), error); \ } \ st->state = ScriptEndState::END; \ return; \ -- cgit v1.2.3-70-g09d2 From 89a49910c30769ed85a715d003fdcbbced44feee Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Wed, 17 Apr 2024 05:16:53 +0000 Subject: script-fun: Convert string literals to LString This is some rather impressive type safety, albeit safety that has evidently desensitized people to warnings for rather serious problems. --- src/map/script-fun.cpp | 166 ++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index deb781a..0014805 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -111,7 +111,7 @@ static void builtin_mes(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); sd->state.npc_dialog_mes = 1; RString mes = HARG(0) ? conv_str(st, &AARG(0)) : ""_s; clif_scriptmes(sd, st->oid, mes); @@ -125,7 +125,7 @@ static void builtin_mesq(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); sd->state.npc_dialog_mes = 1; RString mes = HARG(0) ? conv_str(st, &AARG(0)) : ""_s; MString mesq; @@ -145,8 +145,8 @@ 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"); + script_nullpo_end(nd, "npc not found"_s); + script_nullpo_end(sd, "player not found"_s); 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; @@ -164,7 +164,7 @@ static void builtin_clear(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); clif_npc_action(sd, st->oid, 9, 0, 0, 0); } @@ -389,7 +389,7 @@ static void builtin_next(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); st->state = ScriptEndState::STOP; clif_scriptnext(sd, st->oid); } @@ -411,7 +411,7 @@ void builtin_close(ScriptState *st) } st->state = ScriptEndState::END; dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (sd->state.npc_dialog_mes) clif_scriptclose(sd, st->oid); @@ -428,7 +428,7 @@ void builtin_close2(ScriptState *st) { st->state = ScriptEndState::STOP; dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (sd->state.npc_dialog_mes) clif_scriptclose(sd, st->oid); else @@ -443,7 +443,7 @@ static void builtin_menu(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (sd->state.menu_or_input == 0) { @@ -676,7 +676,7 @@ void builtin_isat(ScriptState *st) x = conv_num(st, &AARG(1)); y = conv_num(st, &AARG(2)); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, (x == sd->bl_x) && (y == sd->bl_y) @@ -695,7 +695,7 @@ void builtin_warp(ScriptState *st) MapName str = stringish(ZString(conv_str(st, &AARG(0)))); x = conv_num(st, &AARG(1)); y = conv_num(st, &AARG(2)); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_setpos(sd, str, x, y, BeingRemoveWhy::GONE); } @@ -748,7 +748,7 @@ void builtin_heal(ScriptState *st) hp = conv_num(st, &AARG(0)); sp = conv_num(st, &AARG(1)); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if(sd != nullptr && (sd->status.hp < 1 && hp > 0)){ pc_setstand(sd); @@ -901,7 +901,7 @@ void builtin_input(ScriptState *st) char postfix = name.back(); sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (sd->state.menu_or_input) { // Second time (rerun) @@ -962,7 +962,7 @@ void builtin_requestitem(ScriptState *st) } sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (sd->state.menu_or_input) { // Second time (rerunline) @@ -1055,7 +1055,7 @@ void builtin_requestlang(ScriptState *st) ZString name = variable_names.outtern(reg.base()); char postfix = name.back(); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (postfix != '$') { @@ -1247,7 +1247,7 @@ void builtin_foreach(ScriptState *st) else if (st->rid) sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); map_foreachinarea(std::bind(builtin_foreach_sub, ph::_1, event, sd->bl_id), m, @@ -1279,7 +1279,7 @@ void builtin_destroy(ScriptState *st) /* Not safe to call destroy if others may also be paused on this NPC! */ if (st->rid) { sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); npc_event_dequeue(sd); } @@ -1453,7 +1453,7 @@ void builtin_set(ScriptState *st) else { bl = script_rid2sd(st); - script_nullpo_end(bl, "player not found"); + script_nullpo_end(bl, "player not found"_s); } int val = conv_num(st, &AARG(1)); @@ -1628,14 +1628,14 @@ void builtin_setarray(ScriptState *st) else bl = map_id_is_npc(wrap(tid)); } - script_nullpo_end(bl, "npc not found"); + script_nullpo_end(bl, "npc not found"_s); if (st->oid && bl->bl_id != st->oid) j = getarraysize2(reg, bl); } else if (prefix != '$' && !name.startswith(".@"_s)) { bl = map_id_is_player(st->rid); - script_nullpo_end(bl, "player not found"); + script_nullpo_end(bl, "player not found"_s); } for (; i < st->end - st->start - 2 && j < 256; i++, j++) @@ -1674,7 +1674,7 @@ void builtin_cleararray(ScriptState *st) else if (prefix != '$' && !name.startswith(".@"_s)) { bl = map_id_is_player(st->rid); - script_nullpo_end(bl, "player not found"); + script_nullpo_end(bl, "player not found"_s); } for (int i = 0; i < sz; i++) @@ -1847,7 +1847,7 @@ void builtin_gmlog(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); ZString message = ZString(conv_str(st, &AARG(0))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); log_atcommand(sd, STRPRINTF("{SCRIPT} %s"_fmt, message)); } @@ -1861,7 +1861,7 @@ void builtin_setlook(ScriptState *st) dumb_ptr sd = script_rid2sd(st); LOOK type = LOOK(conv_num(st, &AARG(0))); int val = conv_num(st, &AARG(1)); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_changelook(sd, type, val); @@ -1881,7 +1881,7 @@ void builtin_countitem(ScriptState *st) struct script_data *data; sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); data = &AARG(0); get_val(st, data); @@ -1929,7 +1929,7 @@ void builtin_checkweight(ScriptState *st) struct script_data *data; sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); data = &AARG(0); get_val(st, data); @@ -1978,7 +1978,7 @@ void builtin_getitem(ScriptState *st) struct script_data *data; sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); data = &AARG(0); get_val(st, data); @@ -2082,7 +2082,7 @@ void builtin_delitem(ScriptState *st) struct script_data *data; sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); data = &AARG(0); get_val(st, data); @@ -2133,7 +2133,7 @@ static void builtin_getversion(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, unwrap(sd->client_version)); } @@ -2220,7 +2220,7 @@ void builtin_strcharinfo(ScriptState *st) else sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); num = conv_num(st, &AARG(0)); if (num == 0) @@ -2277,7 +2277,7 @@ void builtin_getequipid(ScriptState *st) else sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); num = conv_num(st, &AARG(0)); IOff0 i = pc_checkequip(sd, equip[num - 1]); if (i.ok()) @@ -2336,7 +2336,7 @@ void builtin_bonus(ScriptState *st) type = SP(conv_num(st, &AARG(0))); int val = conv_num(st, &AARG(1)); dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_bonus(sd, type, val); } @@ -2357,7 +2357,7 @@ void builtin_bonus2(ScriptState *st) int type2 = conv_num(st, &AARG(1)); int val = conv_num(st, &AARG(2)); dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_bonus2(sd, type, type2, val); } @@ -2378,7 +2378,7 @@ void builtin_skill(ScriptState *st) if (HARG(2)) flag = conv_num(st, &AARG(2)); sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_skill(sd, id, level, flag); clif_skillinfoblock(sd); @@ -2397,7 +2397,7 @@ void builtin_setskill(ScriptState *st) SkillID id = static_cast(conv_num(st, &AARG(0))); level = conv_num(st, &AARG(1)); sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); level = std::min(level, MAX_SKILL_LEVEL); level = std::max(level, 0); @@ -2415,7 +2415,7 @@ void builtin_getskilllv(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); SkillID id = SkillID(conv_num(st, &AARG(0))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, pc_checkskill(sd, id)); } @@ -2427,7 +2427,7 @@ static void builtin_overrideattack(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (HARG(0)) { @@ -2464,7 +2464,7 @@ static void builtin_getgmlevel(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, pc_isGM(sd).get_all_bits()); } @@ -2497,7 +2497,7 @@ void builtin_getopt2(ScriptState *st) dumb_ptr sd; sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, static_cast(sd->opt2)); @@ -2514,7 +2514,7 @@ void builtin_setopt2(ScriptState *st) Opt2 new_opt2 = Opt2(conv_num(st, &AARG(0))); sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (new_opt2 == sd->opt2) return; @@ -2535,7 +2535,7 @@ void builtin_savepoint(ScriptState *st) dumb_ptr sd = script_rid2sd(st); int x, y; MapName str = stringish(ZString(conv_str(st, &AARG(0)))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); x = conv_num(st, &AARG(1)); y = conv_num(st, &AARG(2)); @@ -2635,7 +2635,7 @@ void builtin_openstorage(ScriptState *st) // int sync = 0; // if (st->end >= 3) sync = conv_num(st,& (st->stack->stack_data[st->start+2])); dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); // if (sync) { st->state = ScriptEndState::STOP; @@ -2655,7 +2655,7 @@ void builtin_getexp(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); int base = 0, job = 0; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); base = conv_num(st, &AARG(0)); job = conv_num(st, &AARG(1)); @@ -2968,7 +2968,7 @@ void builtin_mobinfo_droparrays(ScriptState *st) else if (prefix != '$' && !name.startswith(".@"_s)) { bl = map_id_is_player(st->rid); - script_nullpo_end(bl, "player not found"); + script_nullpo_end(bl, "player not found"_s); } switch (request) @@ -3321,7 +3321,7 @@ void builtin_addtimer(ScriptState *st) else if (st->rid) sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_addeventtimer(sd, tick, event); } @@ -3354,7 +3354,7 @@ void builtin_initnpctimer(ScriptState *st) nd_ = npc_name2id(stringish(ZString(conv_str(st, &AARG(0))))); else nd_ = map_id_is_npc(st->oid); - script_nullpo_end(nd_, "no npc"); + script_nullpo_end(nd_, "no npc"_s); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); dumb_ptr nd = nd_->is_script(); @@ -3375,7 +3375,7 @@ void builtin_startnpctimer(ScriptState *st) nd_ = npc_name2id(stringish(ZString(conv_str(st, &AARG(0))))); else nd_ = map_id_is_npc(st->oid); - script_nullpo_end(nd_, "no npc"); + script_nullpo_end(nd_, "no npc"_s); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); dumb_ptr nd = nd_->is_script(); @@ -3395,7 +3395,7 @@ void builtin_stopnpctimer(ScriptState *st) nd_ = npc_name2id(stringish(ZString(conv_str(st, &AARG(0))))); else nd_ = map_id_is_npc(st->oid); - script_nullpo_end(nd_, "no npc"); + script_nullpo_end(nd_, "no npc"_s); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); dumb_ptr nd = nd_->is_script(); @@ -3417,7 +3417,7 @@ void builtin_getnpctimer(ScriptState *st) nd_ = npc_name2id(stringish(ZString(conv_str(st, &AARG(1))))); else nd_ = map_id_is_npc(st->oid); - script_nullpo_end(nd_, "no npc"); + script_nullpo_end(nd_, "no npc"_s); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); dumb_ptr nd = nd_->is_script(); @@ -3450,7 +3450,7 @@ void builtin_setnpctimer(ScriptState *st) nd_ = npc_name2id(stringish(ZString(conv_str(st, &AARG(1))))); else nd_ = map_id_is_npc(st->oid); - script_nullpo_end(nd_, "no npc"); + script_nullpo_end(nd_, "no npc"_s); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); dumb_ptr nd = nd_->is_script(); @@ -3469,7 +3469,7 @@ void builtin_npcaction(ScriptState *st) int id = 0; short x = HARG(2) ? conv_num(st, &AARG(2)) : 0; short y = HARG(3) ? conv_num(st, &AARG(3)) : 0; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if(HARG(1)) { @@ -3494,7 +3494,7 @@ static void builtin_camera(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (HARG(0)) { @@ -3551,7 +3551,7 @@ void builtin_setnpcdirection(ScriptState *st) else nd_ = map_id_is_npc(st->oid); - script_nullpo_end(nd_, "no npc"); + script_nullpo_end(nd_, "no npc"_s); if (bool(conv_num(st, &AARG(1)))) action = DamageType::SIT; @@ -3567,7 +3567,7 @@ void builtin_setnpcdirection(ScriptState *st) if (st->rid) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); clif_sitnpc_towards(sd, nd_, action); clif_setnpcdirection_towards(sd, nd_, dir); } @@ -3597,7 +3597,7 @@ void builtin_announce(ScriptState *st) bl = map_id2bl(st->oid); else bl = script_rid2sd(st); - script_nullpo_end(bl, "player not found"); + script_nullpo_end(bl, "player not found"_s); clif_GMmessage(bl, str, flag); } else @@ -3979,7 +3979,7 @@ void builtin_resetstatus(ScriptState *st) { dumb_ptr sd; sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); pc_resetstate(sd); } @@ -4161,7 +4161,7 @@ void builtin_setpvpchannel(ScriptState *st) if (flag < 1) flag = 0; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); sd->state.pvpchannel = flag; } @@ -4178,7 +4178,7 @@ void builtin_getpvpflag(ScriptState *st) else sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); int num = conv_num(st, &AARG(0)); int flag = 0; @@ -4360,7 +4360,7 @@ static void builtin_getpartnerid2(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, unwrap(sd->status.partner_id)); } @@ -4425,7 +4425,7 @@ void builtin_explode(ScriptState *st) else if (prefix != '$' && prefix != '.') { bl = map_id2bl(st->rid)->is_player(); - script_nullpo_end(bl, "target player not found"); + script_nullpo_end(bl, "target player not found"_s); } @@ -4476,7 +4476,7 @@ void builtin_getinventorylist(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); int j = 0; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); for (IOff0 i : IOff0::iter()) { @@ -4507,7 +4507,7 @@ void builtin_getactivatedpoolskilllist(ScriptState *st) int skill_pool_size = skill_pool(sd, pool_skills); int i, count = 0; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); for (i = 0; i < skill_pool_size; i++) { @@ -4540,7 +4540,7 @@ void builtin_getunactivatedpoolskilllist(ScriptState *st) dumb_ptr sd = script_rid2sd(st); int i, count = 0; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); for (i = 0; i < skill_pool_skills.size(); i++) { @@ -4572,7 +4572,7 @@ void builtin_poolskill(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); SkillID skill_id = SkillID(conv_num(st, &AARG(0))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); skill_pool_activate(sd, skill_id); clif_skillinfoblock(sd); @@ -4587,7 +4587,7 @@ void builtin_unpoolskill(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); SkillID skill_id = SkillID(conv_num(st, &AARG(0))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); skill_pool_deactivate(sd, skill_id); clif_skillinfoblock(sd); @@ -4831,7 +4831,7 @@ void builtin_nude(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); for (EQUIP i : EQUIPs) { @@ -4851,7 +4851,7 @@ static void builtin_unequipbyid(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); EQUIP slot_id = EQUIP(conv_num(st, &AARG(0))); @@ -4992,7 +4992,7 @@ void builtin_title(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); ZString msg = ZString(conv_str(st, &AARG(0))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); clif_npc_send_title(sd->sess, st->oid, msg); } @@ -5013,7 +5013,7 @@ void builtin_smsg(ScriptState *st) int type = HARG(1) ? conv_num(st, &AARG(0)) : 0; ZString msg = ZString(conv_str(st, (HARG(1) ? &AARG(1) : &AARG(0)))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (type < 0 || type > 0xFF) type = 0; @@ -5028,7 +5028,7 @@ static void builtin_remotecmd(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (HARG(1)) { @@ -5055,7 +5055,7 @@ void builtin_sendcollision(ScriptState *st) short x1, y1, x2, y2; x1 = x2 = conv_num(st, &AARG(2)); y1 = y2 = conv_num(st, &AARG(3)); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); if (HARG(5)) { @@ -5088,7 +5088,7 @@ void builtin_music(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); ZString msg = ZString(conv_str(st, &AARG(0))); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); clif_change_music(sd, msg); } @@ -5113,7 +5113,7 @@ void builtin_mapmask(ScriptState *st) else if(HARG(1) && nd) nd->bl_m->mask = map_mask; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); clif_send_mask(sd, map_mask); } @@ -5195,7 +5195,7 @@ void builtin_getlook(ScriptState *st) dumb_ptr sd = script_rid2sd(st); LOOK type = LOOK(conv_num(st, &AARG(0))); int val = -1; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); switch (type) { @@ -5239,7 +5239,7 @@ void builtin_getsavepoint(ScriptState *st) { int x, y, type; dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); type = conv_num(st, &AARG(0)); @@ -5333,7 +5333,7 @@ void builtin_isin(ScriptState *st) x2 = conv_num(st, &AARG(3)); y2 = conv_num(st, &AARG(4)); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, (sd->bl_x >= x1 && sd->bl_x <= x2) @@ -5369,7 +5369,7 @@ void builtin_shop(ScriptState *st) dumb_ptr sd = script_rid2sd(st); dumb_ptr nd; - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); NpcName name = stringish(ZString(conv_str(st, &AARG(0)))); nd = npc_name2id(name); @@ -5387,7 +5387,7 @@ static void builtin_isdead(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, pc_isdead(sd)); } @@ -5421,7 +5421,7 @@ static void builtin_getx(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, sd->bl_x); } @@ -5433,7 +5433,7 @@ static void builtin_gety(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, sd->bl_y); } @@ -5445,7 +5445,7 @@ static void builtin_getdir(ScriptState *st) { dumb_ptr sd = script_rid2sd(st); - script_nullpo_end(sd, "player not found"); + script_nullpo_end(sd, "player not found"_s); push_int(st->stack, static_cast(sd->dir)); } @@ -5524,7 +5524,7 @@ void builtin_strnpcinfo(ScriptState *st) nd = map_id_is_npc(st->oid); } - script_nullpo_end(nd, "npc not found"); + script_nullpo_end(nd, "npc not found"_s); switch(num) { @@ -5562,7 +5562,7 @@ void builtin_getnpcx(ScriptState *st) nd = map_id_is_npc(st->oid); } - script_nullpo_end(nd, "no npc"); + script_nullpo_end(nd, "no npc"_s); push_int(st->stack, nd->bl_x); } @@ -5584,7 +5584,7 @@ void builtin_getnpcy(ScriptState *st) nd = map_id_is_npc(st->oid); } - script_nullpo_end(nd, "no npc"); + script_nullpo_end(nd, "no npc"_s); push_int(st->stack, nd->bl_y); } -- cgit v1.2.3-70-g09d2 From bafec99026144d807bb140b6daf86853c4603e51 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Mon, 29 Apr 2024 08:36:26 +0000 Subject: mob: Avoid dangling else --- src/map/mob.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/map/mob.cpp b/src/map/mob.cpp index f2f6815..996e2bb 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2556,10 +2556,12 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, // activity if (sd) + { if (sd->activity.attacks == 2147483647) sd->activity.attacks = 1; else sd->activity.attacks++; + } if (md->hp > 0) { -- cgit v1.2.3-70-g09d2 From 9d00c99cd0c636aa5a6c25677d334d455cd9195f Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Mon, 29 Apr 2024 10:15:51 +0000 Subject: npc_destroy: Defer NPC destruction via timer 055-1 _nodes.txt will call `destroy;` from within OnInit, that is during an iteration of the global `ev_db`. Previously, concurrent modification invalidated this iteration, resulting in a crash. This still nullifes `oid`, dequeues all timers, and effectively calls `builtin_end`. `npc_data::deletion_pending` is extended to include a third state. In addition to no deletion happening, and indicating when `npc_free` is currently on the stack, it now also tracks whether the NPC is about to be deleted by a timer. This means that an NPC which is about to be deleted is still blocked from triggering new events, much like an NPC actively being deleted would. Starting or continuing an NPC dialog with an NPC that does not, or is about to no longer exist, is now also blocked. --- src/map/map.hpp | 6 +++++- src/map/npc-parse.cpp | 8 ++++---- src/map/npc.cpp | 19 ++++++++++++++----- src/map/script-fun.cpp | 15 +++++++++++++-- 4 files changed, 36 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/map/map.hpp b/src/map/map.hpp index 7cf43d5..56d07a5 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -360,7 +360,11 @@ struct npc_data : block_list Opt0 option; short flag; - bool deletion_pending; + enum { + NOT_DELETING = 0, + DELETION_QUEUED = 1, + DELETION_ACTIVE = 2 + } deletion_pending; Array eventtimer; diff --git a/src/map/npc-parse.cpp b/src/map/npc-parse.cpp index 47b851c..df1a09a 100644 --- a/src/map/npc-parse.cpp +++ b/src/map/npc-parse.cpp @@ -164,7 +164,7 @@ bool npc_load_warp(ast::npc::Warp& warp) nd->warp.xs = xs; nd->warp.ys = ys; - nd->deletion_pending = false; + nd->deletion_pending = npc_data::NOT_DELETING; npc_warp++; nd->bl_type = BL::NPC; @@ -228,7 +228,7 @@ bool npc_load_shop(ast::npc::Shop& shop) nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - nd->deletion_pending = false; + nd->deletion_pending = npc_data::NOT_DELETING; npc_shop++; nd->bl_type = BL::NPC; @@ -458,7 +458,7 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - nd->deletion_pending = false; + nd->deletion_pending = npc_data::NOT_DELETING; npc_script++; nd->bl_type = BL::NPC; @@ -568,7 +568,7 @@ bool npc_load_script_map(ast::script::ScriptBody& body, ast::npc::ScriptMap& scr nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - nd->deletion_pending = false; + nd->deletion_pending = npc_data::NOT_DELETING; npc_script++; nd->bl_type = BL::NPC; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index e8d6d4b..8a6bead 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -357,7 +357,7 @@ void npc_eventtimer(TimerData *, tick_t, BlockId, NpcEvent data) data); return; }); - if ((nd = ev->nd) == nullptr || nd->deletion_pending == true) + if ((nd = ev->nd) == nullptr || nd->deletion_pending != npc_data::NOT_DELETING) { if (battle_config.error_log) PRINTF("npc_event: event not found [%s]\n"_fmt, @@ -591,7 +591,7 @@ int npc_event(dumb_ptr sd, NpcEvent eventname, ev.pos = ev2->pos; } - if ((nd = ev.nd) == nullptr || nd->deletion_pending == true) + if ((nd = ev.nd) == nullptr || nd->deletion_pending != npc_data::NOT_DELETING) { if (!mob_kill && battle_config.error_log) PRINTF("npc_event: event not found [%s]\n"_fmt, @@ -774,6 +774,14 @@ int npc_click(dumb_ptr sd, BlockId id) nd = map_id_is_npc(id); + // If someone clicked on an NPC that is about to no longer exist, then + // release them + if (nd->deletion_pending != npc_data::NOT_DELETING) + { + clif_scriptclose(sd, id); + return 1; + } + if (nd->flag & 1) // 無効化されている return 1; @@ -818,7 +826,8 @@ int npc_scriptcont(dumb_ptr sd, BlockId id) nd = map_id_is_npc(id); - if (!nd /* NPC was disposed? */) + // If the NPC is about to be deleted, release the PC + if (nd->deletion_pending != npc_data::NOT_DELETING) { clif_scriptclose(sd, id); npc_event_dequeue(sd); @@ -1091,10 +1100,10 @@ void npc_propagate_update(dumb_ptr nd) void npc_free(dumb_ptr nd) { - if (nd == nullptr || nd->deletion_pending == true) + if (nd == nullptr || nd->deletion_pending == npc_data::DELETION_ACTIVE) return; - nd->deletion_pending = true; + nd->deletion_pending = npc_data::DELETION_ACTIVE; nd->flag |= 1; clif_clearchar(nd, BeingRemoveWhy::GONE); npc_propagate_update(nd); diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 0014805..13b4bc8 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -1283,8 +1283,19 @@ void builtin_destroy(ScriptState *st) npc_event_dequeue(sd); } + // Cancel all existing timers on the NPC. + // They "would" never fire, and we don't want race conditions here. + for (int i = 0; i < MAX_EVENTTIMER; i++) + { + nd->eventtimer[i].cancel(); + } + // Schedule the NPC to be freed on the next available tick. + // Scripts can be invoked under iteration of the ev_db global event + // database, and we don't want to invalidate active iterators. + nd->deletion_pending = npc_data::DELETION_QUEUED; + nd->eventtimer[0] = Timer(gettick(), std::bind(npc_free, nd)); + nd = nd->is_script(); - npc_free(nd); st->oid = BlockId(); if (!HARG(0)) @@ -1350,7 +1361,7 @@ void builtin_puppet(ScriptState *st) nd->npc_subtype = NpcSubtype::SCRIPT; npc_script++; - nd->deletion_pending = false; + nd->deletion_pending = npc_data::NOT_DELETING; nd->n = map_addnpc(nd->bl_m, nd); -- cgit v1.2.3-70-g09d2 From 04dfb9a9af92352af291ea8b1fa7150644614397 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Mon, 29 Apr 2024 12:21:55 +0000 Subject: npc_scripcont: consistent return value `npc_scriptcont` now consistently returns 1 on failure, though in practice, this return value was always ignored. --- src/map/npc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 8a6bead..930b9de 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -831,14 +831,14 @@ int npc_scriptcont(dumb_ptr sd, BlockId id) { clif_scriptclose(sd, id); npc_event_dequeue(sd); - return 0; + return 1; } if (nd->is_script()->scr.parent && map_id2bl(nd->is_script()->scr.parent) == nullptr) { npc_free(nd); - return 0; + return 1; } sd->npc_pos = run_script(ScriptPointer(script_or_parent(nd->is_script()), sd->npc_pos), sd->bl_id, id); -- cgit v1.2.3-70-g09d2 From aaaf2321b8a0e47c46f8ba8a2090c423f5947cf9 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Mon, 29 Apr 2024 12:22:29 +0000 Subject: npc: formatting Nice consistency there, past!Freeyorp. --- src/map/npc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 930b9de..7d3e62b 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -767,7 +767,8 @@ int npc_click(dumb_ptr sd, BlockId id) } } - if (npc_checknear(sd, id)) { + if (npc_checknear(sd, id)) + { clif_scriptclose(sd, id); return 1; } -- cgit v1.2.3-70-g09d2 From b770e11f539de8b86a6e042d357e248fc25845b2 Mon Sep 17 00:00:00 2001 From: asuratva Date: Wed, 15 May 2024 10:49:57 +0530 Subject: Add function to check for summoned creature in scripts --- src/map/script-fun.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 13b4bc8..8d5bf94 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3726,6 +3726,23 @@ void builtin_aggravate(ScriptState *st) } } +/*========================================== + * Check for summoned creature + *------------------------------------------ + */ +static +void builtin_issummon(ScriptState *st) +{ + dumb_ptr md = map_id_is_mob(wrap(conv_num(st, &AARG(0)))); + int val = 0; + if (md && md->name.contains_seq("Summon"_s)) + { + val = 1; + } + + push_int(st->stack, val); +} + /*========================================== * エリア指定ユーザー数所得 * Area Designated User Income @@ -5757,6 +5774,7 @@ BuiltinFunction builtin_functions[] = BUILTIN(shop, "s"_s, '\0'), BUILTIN(isdead, ""_s, 'i'), BUILTIN(aggravate, "i?"_s, '\0'), + BUILTIN(issummon, "i?"_s, 'i'), BUILTIN(fakenpcname, "ssi"_s, '\0'), BUILTIN(puppet, "mxysi??"_s, 'i'), BUILTIN(destroy, "?"_s, '\0'), -- cgit v1.2.3-70-g09d2 From 8054dfe5c1f66cacca3d0d93a6479434d2240400 Mon Sep 17 00:00:00 2001 From: asuratva Date: Wed, 15 May 2024 12:25:43 +0530 Subject: updated itenplz fix to use mob flag instead of string comparison. More efficient. Credit to @Hello for figuring this out :) --- src/map/script-fun.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 8d5bf94..9346963 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3735,9 +3735,9 @@ void builtin_issummon(ScriptState *st) { dumb_ptr md = map_id_is_mob(wrap(conv_num(st, &AARG(0)))); int val = 0; - if (md && md->name.contains_seq("Summon"_s)) + if (md) { - val = 1; + val |= (md->mode & MobMode::SUMMONED); } push_int(st->stack, val); -- cgit v1.2.3-70-g09d2 From 18315186bd1dee9a6386c376ea78788c017fe3fe Mon Sep 17 00:00:00 2001 From: asuratva Date: Wed, 15 May 2024 14:12:59 +0530 Subject: fix issummon function signature. Thanks @HoraK-FDF for catching the typo. --- src/map/script-fun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 9346963..e85c9f7 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -5774,7 +5774,7 @@ BuiltinFunction builtin_functions[] = BUILTIN(shop, "s"_s, '\0'), BUILTIN(isdead, ""_s, 'i'), BUILTIN(aggravate, "i?"_s, '\0'), - BUILTIN(issummon, "i?"_s, 'i'), + BUILTIN(issummon, "i"_s, 'i'), BUILTIN(fakenpcname, "ssi"_s, '\0'), BUILTIN(puppet, "mxysi??"_s, 'i'), BUILTIN(destroy, "?"_s, '\0'), -- cgit v1.2.3-70-g09d2 From fd3527d7c6e8d295fe4bfa2ff1838e03ff162c76 Mon Sep 17 00:00:00 2001 From: asuratva Date: Wed, 15 May 2024 21:03:15 +0530 Subject: bugfix for previous commit. Need to wrap MobMode in bool() --- src/map/script-fun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index e85c9f7..6e32264 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3737,7 +3737,7 @@ void builtin_issummon(ScriptState *st) int val = 0; if (md) { - val |= (md->mode & MobMode::SUMMONED); + val = bool(md->mode & MobMode::SUMMONED); } push_int(st->stack, val); -- cgit v1.2.3-70-g09d2 From 11d75ebaae614e082055aaf7e6075e7c27bf9368 Mon Sep 17 00:00:00 2001 From: "Hello=)" Date: Fri, 17 May 2024 13:21:10 +0300 Subject: Mages Quality Of Life, part 2: This commit lands fix for infamous AFK-kill summons exploit. Its what essentially caused summoner spells in cities to be disabled. This is not free lunch: it comes at expense of little fun where mob would bite bad master hitting it. But its been minor fun or cosmetics while spells restriction in cities and so on is annoying setback for mages. So if choosing between evil and even more evil, guess... Technically, server's bug is: it too eager to reattach some things to wrong RID or something like this. Its what causes aggroed mob to lock on really wrong random targets and AFK-kill them. --- src/map/script-fun.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 6e32264..1efa006 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3188,8 +3188,8 @@ void builtin_summon(ScriptState *st) } mob->mode |= - MobMode::SUMMONED | MobMode::TURNS_AGAINST_BAD_MASTER; - + MobMode::SUMMONED; // | MobMode::TURNS_AGAINST_BAD_MASTER; <- its fun but bugged. + // This flag identified to be source of AFK PK city exploits, etc. mob->deletetimer = Timer(gettick() + lifespan, std::bind(mob_timer_delete, ph::_1, ph::_2, mob_id)); -- cgit v1.2.3-70-g09d2 From 04c17a55c5b83e1b8ef1dc336fd8e023ba1e10ad Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 6 Jun 2024 19:36:23 +0000 Subject: KeepAfterUse + DontUseAmmo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **** Approved-by: Free Yorp Approved-by: Thorbjørn Lindeijer Reviewed-by: Thorbjørn Lindeijer --- src/map/battle.cpp | 28 +++++++++++++++++++--------- src/map/clif.cpp | 23 +++++++++++++++++------ src/map/npc.cpp | 14 ++++++++++---- src/map/pc.cpp | 8 ++++++-- src/map/storage.cpp | 10 +++++++--- src/mmo/enums.hpp | 2 ++ 6 files changed, 61 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/map/battle.cpp b/src/map/battle.cpp index b745e05..ac8dcf2 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -2060,18 +2060,28 @@ ATK battle_weapon_attack(dumb_ptr src, dumb_ptr target, // 攻撃対象となりうるので攻撃 | Attack because it can be attacked if (sd && sd->status.weapon == ItemLook::W_BOW) { - IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW]; - if (aidx.ok()) - { - if (battle_config.arrow_decrement) - pc_delitem(sd, aidx, 1, 0); - } - else + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + + OMATCH_BEGIN_SOME (sdidw, sd->inventory_data[widx]) { - clif_arrow_fail(sd, 0); - return ATK::ZERO; + if (!bool(sdidw->mode & ItemMode::DONT_USE_AMMO)) + { + IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW]; + if (aidx.ok()) + { + if (battle_config.arrow_decrement) + pc_delitem(sd, aidx, 1, 0); + } + else + { + clif_arrow_fail(sd, 0); + return ATK::ZERO; + } + } } + OMATCH_END (); } + wd = battle_calc_weapon_attack(src, target, SkillID::ZERO, 0, 0); // significantly increase injuries for hasted characters diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 9edf2af..a5bb2ba 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -4617,11 +4617,17 @@ 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)) + + OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[fixed.ioff2.unshift()]) { - clif_displaymessage(sd->sess, "This item can't be dropped."_s); - return rv; + if (bool(sdidn->mode & ItemMode::NO_DROP)) + { + clif_displaymessage(sd->sess, "This item can't be dropped."_s); + return rv; + } } + OMATCH_END (); + if (sd->npc_id || sd->opt1 != Opt1::ZERO) { @@ -4901,11 +4907,16 @@ 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)) + OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[fixed.zeny_or_ioff2.unshift()]) { - clif_displaymessage(sd->sess, "This item can't be traded."_s); - return rv; + if (bool(sdidn->mode & ItemMode::NO_TRADE)) + { + clif_displaymessage(sd->sess, "This item can't be traded."_s); + return rv; + } } + OMATCH_END (); + trade_tradeadditem(sd, fixed.zeny_or_ioff2, fixed.amount); return rv; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 7d3e62b..a6d3dda 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -1003,12 +1003,18 @@ 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)) + + OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[item_list[i].ioff2.unshift()]) { - //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 (bool(sdidn->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; + } } + OMATCH_END (); + if (sd->trade_partner) return 2; // cant sell while trading z += static_cast(itemdb_value_sell(nameid)) * item_list[i].count; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 12af48f..cac3666 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -2404,8 +2404,12 @@ int pc_useitem(dumb_ptr sd, IOff0 n) } P script = borrow(*sdidn->use_script); - clif_useitemack(sd, n, amount - 1, 1); - pc_delitem(sd, n, 1, 1); + + if (!bool(sdidn->mode & ItemMode::KEEP_AFTER_USE)) + { + clif_useitemack(sd, n, amount - 1, 1); + pc_delitem(sd, n, 1, 1); + } // activity if (sd) diff --git a/src/map/storage.cpp b/src/map/storage.cpp index 54398f3..cab3f0f 100644 --- a/src/map/storage.cpp +++ b/src/map/storage.cpp @@ -186,11 +186,15 @@ 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)) + OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[index]) { - clif_displaymessage(sd->sess, "This item can't be stored."_s); - return 0; + if (bool(sdidn->mode & ItemMode::NO_STORAGE)) + { + clif_displaymessage(sd->sess, "This item can't be stored."_s); + return 0; + } } + OMATCH_END (); // 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 c4a1b17..377f7d7 100644 --- a/src/mmo/enums.hpp +++ b/src/mmo/enums.hpp @@ -135,6 +135,8 @@ enum class ItemMode : uint8_t NO_TRADE = 2, NO_SELL_TO_NPC = 4, NO_STORAGE = 8, + KEEP_AFTER_USE = 16, + DONT_USE_AMMO = 32, }; ENUM_BITWISE_OPERATORS(ItemMode) } -- cgit v1.2.3-70-g09d2 From 64cb15b1109d409643fb43d6a5560c36205e29e8 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Fri, 7 Jun 2024 00:32:54 +0200 Subject: activity add sd checking --- src/map/pc.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/map/pc.cpp b/src/map/pc.cpp index cac3666..b6bce38 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -3870,19 +3870,19 @@ int pc_readparam(dumb_ptr bl, SP type) val = sd ? sd->mute.guild : 0; break; case SP::KILLS: - val = sd->activity.kills; + val = sd ? sd->activity.kills : 0; break; case SP::CASTS: - val = sd->activity.casts; + val = sd ? sd->activity.casts : 0; break; case SP::ITEMS_USED: - val = sd->activity.items_used; + val = sd ? sd->activity.items_used : 0; break; case SP::TILES_WALKED: - val = sd->activity.tiles_walked; + val = sd ? sd->activity.tiles_walked : 0; break; case SP::ATTACKS: - val = sd->activity.attacks; + val = sd ? sd->activity.attacks : 0; break; case SP::AUTOMOD: val = sd ? static_cast(sd->automod) : 0; @@ -4135,18 +4135,23 @@ int pc_setparam(dumb_ptr bl, SP type, int val) 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: + nullpo_retz(sd); sd->activity.kills = val; break; case SP::CASTS: + nullpo_retz(sd); sd->activity.casts = val; break; case SP::ITEMS_USED: + nullpo_retz(sd); sd->activity.items_used = val; break; case SP::TILES_WALKED: + nullpo_retz(sd); sd->activity.tiles_walked = val; break; case SP::ATTACKS: + nullpo_retz(sd); sd->activity.attacks = val; break; case SP::AUTOMOD: -- cgit v1.2.3-70-g09d2 From 4c0179e1c43972521e2e6d9299914603292abaf7 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Wed, 19 Jun 2024 08:29:16 +0000 Subject: shared: Explain why startup failed on conf fail This prints out the filename and what it tried to do, rather than raising SIGABRT and silently dumping a core. --- src/shared/lib.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/shared/lib.cpp b/src/shared/lib.cpp index 0eebf17..d7d1a4e 100644 --- a/src/shared/lib.cpp +++ b/src/shared/lib.cpp @@ -39,10 +39,16 @@ namespace tmwa { io::ReadFile rf(dirfd, filename); if (!rf.is_open()) + { + FPRINTF(stderr, "Could not open %s\n"_fmt, filename); abort(); + } AString line; if (!rf.getline(line)) + { + FPRINTF(stderr, "Could not read from %s\n"_fmt, filename); abort(); + } } static @@ -50,10 +56,16 @@ namespace tmwa { io::WriteFile wf(dirfd, filename); if (!wf.is_open()) + { + FPRINTF(stderr, "Could not open %s\n"_fmt, filename); abort(); + } wf.put_line("Hello, World!"_s); if (!wf.close()) + { + FPRINTF(stderr, "Could not write to %s\n"_fmt, filename); abort(); + } } void check_paths() -- cgit v1.2.3-70-g09d2 From 4f80aafa3940abf4050290e6c8b63c45716e0db0 Mon Sep 17 00:00:00 2001 From: Freeyorp Date: Wed, 19 Jun 2024 08:52:07 +0000 Subject: shared: Also print path Try to be even more helpful, since configuration can vary. --- src/shared/lib.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/shared/lib.cpp b/src/shared/lib.cpp index d7d1a4e..c0a4371 100644 --- a/src/shared/lib.cpp +++ b/src/shared/lib.cpp @@ -35,35 +35,35 @@ namespace tmwa { static - void try_read(const io::DirFd& dirfd, ZString filename) + void try_read(const io::DirFd& dirfd, LString dir_path, ZString filename) { io::ReadFile rf(dirfd, filename); if (!rf.is_open()) { - FPRINTF(stderr, "Could not open %s\n"_fmt, filename); + FPRINTF(stderr, "Could not open %s/%s\n"_fmt, dir_path, filename); abort(); } AString line; if (!rf.getline(line)) { - FPRINTF(stderr, "Could not read from %s\n"_fmt, filename); + FPRINTF(stderr, "Could not read from %s/%s\n"_fmt, dir_path, filename); abort(); } } static - void try_write(const io::DirFd& dirfd, ZString filename) + void try_write(const io::DirFd& dirfd, LString dir_path, ZString filename) { io::WriteFile wf(dirfd, filename); if (!wf.is_open()) { - FPRINTF(stderr, "Could not open %s\n"_fmt, filename); + FPRINTF(stderr, "Could not open %s/%s\n"_fmt, dir_path, filename); abort(); } wf.put_line("Hello, World!"_s); if (!wf.close()) { - FPRINTF(stderr, "Could not write to %s\n"_fmt, filename); + FPRINTF(stderr, "Could not write to %s/%s\n"_fmt, dir_path, filename); abort(); } } @@ -77,13 +77,17 @@ namespace tmwa io::DirFd root(portable_root); - io::DirFd etc(root, PACKAGESYSCONFDIR.xslice_t(portable)); - io::DirFd var(root, PACKAGELOCALSTATEDIR.xslice_t(portable)); - io::DirFd share(root, PACKAGEDATADIR.xslice_t(portable)); + LString etc_path = PACKAGESYSCONFDIR.xslice_t(portable); + LString var_path = PACKAGELOCALSTATEDIR.xslice_t(portable); + LString share_path = PACKAGEDATADIR.xslice_t(portable); - try_read(etc, "shared.conf"_s); - try_read(share, "shared.data"_s); - try_write(var, "shared.test"_s); + io::DirFd etc(root, etc_path); + io::DirFd var(root, var_path); + io::DirFd share(root, share_path); + + try_read(etc, etc_path, "shared.conf"_s); + try_read(share, share_path, "shared.data"_s); + try_write(var, var_path, "shared.test"_s); // io::FD::open(); } -- cgit v1.2.3-70-g09d2 From 69e85064403904ba6bece8532b29cc4fc60e722d Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 20 Jun 2024 11:40:01 +0200 Subject: map hash as it was not possible to store a string variable with the current format of the athena.txt I though a hash could help to identify the maps since this one can be stored as a permanent char bound variable in athena.txt --- src/map/map.cpp | 17 +++++++++++++++++ src/map/map.hpp | 1 + src/map/script-fun.cpp | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) (limited to 'src') diff --git a/src/map/map.cpp b/src/map/map.cpp index ff69a56..f8e8bea 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -1240,6 +1240,20 @@ int map_setipport(MapName name, IP4Address ip, int port) return 0; } +/*========================================== + * creates a hash of a map name + *------------------------------------------ + */ +int map_create_hash(XString str) { + const int k = 67; + const int m = 3067; + int hash = 0; + for (int i = 0; i < str.size(); i++) { + hash += (str[i] * (int)pow(k, i)) % m; + } + return hash; +} + /*========================================== * マップ1枚読み込み *------------------------------------------ @@ -1265,6 +1279,9 @@ bool map_readmap(map_local *m, size_t num, MapName fn) m->npc_num = 0; m->users = 0; + + m->hash = map_create_hash(fn); + really_memzero_this(&m->flag); if (battle_config.pk_mode) m->flag.set(MapFlag::PVP, 1); diff --git a/src/map/map.hpp b/src/map/map.hpp index 56d07a5..de0e10b 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -531,6 +531,7 @@ struct map_local : map_abstract Point save; Point resave; int mask; + int hash; Array, MAX_NPC_PER_MAP> npc; }; diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 1efa006..74a70b3 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -5523,6 +5523,39 @@ void builtin_getmapmaxy(ScriptState *st) push_int(st->stack, m->ys-1); } +/*========================================== + * Get the hash of a map + *------------------------------------------ + */ +static +void builtin_getmaphash(ScriptState *st) +{ + MapName mapname = stringish(ZString(conv_str(st, &AARG(0)))); + P m = TRY_UNWRAP(map_mapname2mapid(mapname), return); + push_int(st->stack, m->hash); +} + +/*========================================== + * Get the map name from a hash + *------------------------------------------ + */ +static +void builtin_getmapnamefromhash(ScriptState *st) +{ + int hash = conv_num(st, &AARG(0)); + MapName mapname; + for (auto& mit : maps_db) + { + map_local *ml = static_cast(mit.second.get()); + if (ml->hash == hash) + { + mapname = ml->name_; + break; + } + } + push_str(st->stack, mapname); +} + /*========================================== * Get the NPC's info *------------------------------------------ @@ -5787,6 +5820,8 @@ BuiltinFunction builtin_functions[] = BUILTIN(getmap, "?"_s, 's'), BUILTIN(getmapmaxx, "M"_s, 'i'), BUILTIN(getmapmaxy, "M"_s, 'i'), + BUILTIN(getmaphash, "M"_s, 'i'), + BUILTIN(getmapnamefromhash, "i"_s, 's'), BUILTIN(mapexit, ""_s, '\0'), BUILTIN(freeloop, "i"_s, '\0'), BUILTIN(if_then_else, "iii"_s, 'v'), -- cgit v1.2.3-70-g09d2 From 8ee68fcd6c02a2c0d54bb3a6e2780800fa5e096e Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 18 Jul 2024 12:07:14 +0200 Subject: Max Weight Bonus --- src/map/pc.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/map/pc.cpp b/src/map/pc.cpp index b6bce38..6d71d81 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1894,6 +1894,10 @@ int pc_bonus(dumb_ptr sd, SP type, int val) if (!sd->state.lr_flag_is_arrow_2) sd->base_weapon_delay_adjust += interval_t(val); break; + case SP::MAXWEIGHT: + if (!sd->state.lr_flag_is_arrow_2) + sd->max_weight = val; + break; default: if (battle_config.error_log) PRINTF("pc_bonus: unknown type %d %d !\n"_fmt, -- cgit v1.2.3-70-g09d2 From 561af90af66d336c6c3cc10414029875ecf4902c Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 18 Jul 2024 13:14:28 +0200 Subject: Max Weight Add Bonus --- src/map/pc.cpp | 4 ++++ src/mmo/clif.t.hpp | 1 + 2 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 6d71d81..0b7cf05 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1898,6 +1898,10 @@ int pc_bonus(dumb_ptr sd, SP type, int val) if (!sd->state.lr_flag_is_arrow_2) sd->max_weight = val; break; + case SP::MAXWEIGHT_ADD: + if (!sd->state.lr_flag_is_arrow_2) + sd->max_weight += 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 f8350a7..260ae63 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -265,6 +265,7 @@ enum class SP : uint16_t WEIGHT = 24, // sent to client MAXWEIGHT = 25, + MAXWEIGHT_ADD = 26, // sent to client USTR = 32, -- cgit v1.2.3-70-g09d2 From a1caa53ab1ee0cf41d8bbc41c88d8eb84207ee7f Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Thu, 18 Jul 2024 15:49:51 +0200 Subject: Max Weight Override --- src/map/map.hpp | 2 +- src/map/pc.cpp | 12 ++++++++++++ src/mmo/clif.t.hpp | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/map/map.hpp b/src/map/map.hpp index de0e10b..8bb5aa7 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -184,7 +184,7 @@ struct map_session_data : block_list, SessionData None, None, None, None, None, None, None, None, None, None, }}; // explicit is better than implicit earray equip_index_maybe; - int weight, max_weight; + int weight, max_weight, max_weight_override; MapName mapname_; Session *sess; // use this, you idiots! short to_x, to_y; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 0b7cf05..d28dda4 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -870,6 +870,7 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version, sd->quick_regeneration_hp.amount = 0; sd->quick_regeneration_sp.amount = 0; sd->heal_xp = 0; + sd->max_weight_override = 0; sd->canact_tick = tick; sd->canmove_tick = tick; sd->attackabletime = tick; @@ -1483,6 +1484,9 @@ int pc_calcstatus(dumb_ptr sd, int first) sd->hit += skill_power(sd, SkillID::AC_OWL) / 10; // 20 for 200 } + if (sd->max_weight_override) + sd->max_weight = sd->max_weight_override; + sd->max_weight += 1000; bl = sd->status.base_level; @@ -3729,6 +3733,9 @@ int pc_readparam(dumb_ptr bl, SP type) case SP::MAXWEIGHT: val = sd ? sd->max_weight : 0; break; + case SP::MAXWEIGHT_OVERRIDE: + val = sd ? sd->max_weight_override : 0; + break; case SP::BASEEXP: val = sd ? sd->status.base_exp : 0; break; @@ -4056,6 +4063,11 @@ int pc_setparam(dumb_ptr bl, SP type, int val) sd->max_weight = val; clif_updatestatus(sd, type); break; + case SP::MAXWEIGHT_OVERRIDE: + nullpo_retz(sd); + sd->max_weight_override = val; + pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC); + break; case SP::HP: nullpo_retz(sd); // TODO: mob mutation diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp index 260ae63..c1f7ed3 100644 --- a/src/mmo/clif.t.hpp +++ b/src/mmo/clif.t.hpp @@ -266,6 +266,7 @@ enum class SP : uint16_t // sent to client MAXWEIGHT = 25, MAXWEIGHT_ADD = 26, + MAXWEIGHT_OVERRIDE = 27, // sent to client USTR = 32, -- cgit v1.2.3-70-g09d2 From 587fc350d7ab825c2cb82bdb216694893d3a2413 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Mon, 29 Jul 2024 09:45:48 +0200 Subject: GM restricted item handling --- src/map/clif.cpp | 6 ++++-- src/map/npc.cpp | 3 ++- src/map/storage.cpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/map/clif.cpp b/src/map/clif.cpp index a5bb2ba..6381c09 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -4620,7 +4620,8 @@ RecvResult clif_parse_DropItem(Session *s, dumb_ptr sd) OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[fixed.ioff2.unshift()]) { - if (bool(sdidn->mode & ItemMode::NO_DROP)) + GmLevel gmlvl = pc_isGM(sd); + if (bool(sdidn->mode & ItemMode::NO_DROP) && gmlvl.get_all_bits() < 60) { clif_displaymessage(sd->sess, "This item can't be dropped."_s); return rv; @@ -4909,7 +4910,8 @@ RecvResult clif_parse_TradeAddItem(Session *s, dumb_ptr sd) if (fixed.zeny_or_ioff2.ok()) OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[fixed.zeny_or_ioff2.unshift()]) { - if (bool(sdidn->mode & ItemMode::NO_TRADE)) + GmLevel gmlvl = pc_isGM(sd); + if (bool(sdidn->mode & ItemMode::NO_TRADE) && gmlvl.get_all_bits() < 60) { clif_displaymessage(sd->sess, "This item can't be traded."_s); return rv; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index a6d3dda..0a7bfc2 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -1006,7 +1006,8 @@ int npc_selllist(dumb_ptr sd, OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[item_list[i].ioff2.unshift()]) { - if (bool(sdidn->mode & ItemMode::NO_SELL_TO_NPC)) + GmLevel gmlvl = pc_isGM(sd); + if (bool(sdidn->mode & ItemMode::NO_SELL_TO_NPC) && gmlvl.get_all_bits() < 60) { //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. diff --git a/src/map/storage.cpp b/src/map/storage.cpp index cab3f0f..dc1fe62 100644 --- a/src/map/storage.cpp +++ b/src/map/storage.cpp @@ -188,7 +188,8 @@ int storage_storageadd(dumb_ptr sd, IOff0 index, int amount) OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[index]) { - if (bool(sdidn->mode & ItemMode::NO_STORAGE)) + GmLevel gmlvl = pc_isGM(sd); + if (bool(sdidn->mode & ItemMode::NO_STORAGE) && gmlvl.get_all_bits() < 60) { clif_displaymessage(sd->sess, "This item can't be stored."_s); return 0; -- cgit v1.2.3-70-g09d2 From 2af706705bf6dd3d147eb3b7f84fba3d3713a498 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Tue, 6 Aug 2024 23:11:17 +0200 Subject: sc_cooldown_sg, sc_slowmove, sc_cantmove --- src/map/clif.cpp | 6 ++++++ src/map/pc.cpp | 10 +++++++--- src/map/script-fun.cpp | 5 ++++- src/map/skill.cpp | 6 ++++++ src/mmo/skill.t.hpp | 3 +++ 5 files changed, 26 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 6381c09..4d36f17 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -3865,6 +3865,12 @@ RecvResult clif_parse_WalkToXY(Session *s, dumb_ptr sd) if (bool(sd->opt1) && sd->opt1 != (Opt1::_stone6)) return rv; + if (sd->sc_data[StatusChange::SC_CANTMOVE].timer) + { + pc_stop_walking(sd, 1); // this is a little hack since client is a bit bugged and still moves several tiles and then gets reset to the position where status was triggered with this it only moves 1 pixel or so and gets set back + return rv; + } + if (sd->invincible_timer) pc_delinvincibletimer(sd); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index d28dda4..df5423e 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1122,7 +1122,7 @@ int pc_calcstatus(dumb_ptr sd, int first) b_attackrange, b_matk1, b_matk2, b_mdef, b_mdef2; int b_base_atk; int bl; - int aspd_rate, refinedef = 0; + int aspd_rate, speed_rate, refinedef = 0; int str, dstr, dex; int b_pvpchannel = 0; @@ -1474,6 +1474,7 @@ int pc_calcstatus(dumb_ptr sd, int first) } aspd_rate = sd->aspd_rate; + speed_rate = sd->speed_rate; //攻撃速度増加 | Increased attack speed @@ -1554,10 +1555,13 @@ int pc_calcstatus(dumb_ptr sd, int first) if (sd->sc_data[StatusChange::SC_PHYS_SHIELD].timer) aspd_rate += sd->sc_data[StatusChange::SC_PHYS_SHIELD].val1; + + if (sd->sc_data[StatusChange::SC_SLOWMOVE].timer) + speed_rate += sd->sc_data[StatusChange::SC_SLOWMOVE].val1; } - if (sd->speed_rate != 100) - sd->speed = sd->speed * sd->speed_rate / 100; + if (speed_rate != 100) + sd->speed = sd->speed * speed_rate / 100; sd->speed = std::max(sd->speed, 1_ms); if (sd->speed_cap < interval_t::zero()) sd->speed_cap = interval_t::zero(); diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 74a70b3..3bbd369 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3929,7 +3929,10 @@ void builtin_sc_start(ScriptState *st) case StatusChange::SC_COOLDOWN_ENCH: case StatusChange::SC_COOLDOWN_KOY: case StatusChange::SC_COOLDOWN_UPMARMU: - break; + case StatusChange::SC_COOLDOWN_SG: + case StatusChange::SC_SLOWMOVE: + case StatusChange::SC_CANTMOVE: + break; default: // work around old behaviour of: diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 87bbbda..65df758 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -754,6 +754,7 @@ void skill_status_change_end(dumb_ptr bl, StatusChange type, TimerDa case StatusChange::SC_MATKPOT: /* magic attack potion [Valaris] */ case StatusChange::SC_PHYS_SHIELD: case StatusChange::SC_HASTE: + case StatusChange::SC_SLOWMOVE: calc_flag = 1; break; @@ -765,6 +766,8 @@ void skill_status_change_end(dumb_ptr bl, StatusChange type, TimerDa case StatusChange::SC_COOLDOWN_ENCH: case StatusChange::SC_COOLDOWN_KOY: case StatusChange::SC_COOLDOWN_UPMARMU: + case StatusChange::SC_COOLDOWN_SG: + case StatusChange::SC_CANTMOVE: break; /* option2 */ @@ -1031,6 +1034,7 @@ int skill_status_effect(dumb_ptr bl, StatusChange type, case StatusChange::SC_HASTE: case StatusChange::SC_PHYS_SHIELD: case StatusChange::SC_MBARRIER: + case StatusChange::SC_SLOWMOVE: calc_flag = 1; break; case StatusChange::SC_HALT_REGENERATE: @@ -1043,6 +1047,8 @@ int skill_status_effect(dumb_ptr bl, StatusChange type, case StatusChange::SC_COOLDOWN_ENCH: case StatusChange::SC_COOLDOWN_KOY: case StatusChange::SC_COOLDOWN_UPMARMU: + case StatusChange::SC_COOLDOWN_SG: + case StatusChange::SC_CANTMOVE: break; case StatusChange::SC_FLYING_BACKPACK: updateflag = SP::WEIGHT; diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp index 782980c..25d7b3e 100644 --- a/src/mmo/skill.t.hpp +++ b/src/mmo/skill.t.hpp @@ -60,8 +60,11 @@ enum class StatusChange : uint16_t SC_COOLDOWN_ENCH = 76, // Enchanter cooldown SC_COOLDOWN_KOY = 77, // Koyntety cooldown SC_COOLDOWN_UPMARMU = 78, // Upmarmu cooldown + SC_COOLDOWN_SG = 79, // Stone Golem cooldown SC_POISON = 132, // bad; actually used + SC_SLOWMOVE = 133, // slows down movement + SC_CANTMOVE = 134, // stops all movement SC_ATKPOT = 185, // item script SC_MATKPOT = 186, // unused, but kept for parallel -- cgit v1.2.3-70-g09d2 From 48ee77e4fdfc3741996df0ddaca49c090292fc10 Mon Sep 17 00:00:00 2001 From: HoraK-FDF Date: Wed, 7 Aug 2024 23:40:36 +0200 Subject: sc_phys_shield_item --- src/map/battle.cpp | 4 ++-- src/map/pc.cpp | 4 ++-- src/map/script-fun.cpp | 1 + src/map/skill.cpp | 6 ++++-- src/mmo/skill.t.hpp | 4 +++- 5 files changed, 12 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/map/battle.cpp b/src/map/battle.cpp index ac8dcf2..d66308d 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -2091,10 +2091,10 @@ ATK battle_weapon_attack(dumb_ptr src, dumb_ptr target, } if (wd.damage > 0 - && t_sc_data[StatusChange::SC_PHYS_SHIELD].timer + && (t_sc_data[StatusChange::SC_PHYS_SHIELD].timer || t_sc_data[StatusChange::SC_PHYS_SHIELD_ITEM].timer) && target->bl_type == BL::PC) { - int reduction = t_sc_data[StatusChange::SC_PHYS_SHIELD].val1; + int reduction = std::max(t_sc_data[StatusChange::SC_PHYS_SHIELD].val1, t_sc_data[StatusChange::SC_PHYS_SHIELD_ITEM].val1); // highest value is taken here but serverdata should make sure only one of those is active if (reduction > wd.damage) reduction = wd.damage; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index df5423e..9ef70fe 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -1553,8 +1553,8 @@ int pc_calcstatus(dumb_ptr sd, int first) /* Slow down if protected */ - if (sd->sc_data[StatusChange::SC_PHYS_SHIELD].timer) - aspd_rate += sd->sc_data[StatusChange::SC_PHYS_SHIELD].val1; + if (sd->sc_data[StatusChange::SC_PHYS_SHIELD].timer || sd->sc_data[StatusChange::SC_PHYS_SHIELD_ITEM].timer) + aspd_rate += std::max(sd->sc_data[StatusChange::SC_PHYS_SHIELD].val1, sd->sc_data[StatusChange::SC_PHYS_SHIELD_ITEM].val1); // highest value is taken here but serverdata should make sure only one of those is active if (sd->sc_data[StatusChange::SC_SLOWMOVE].timer) speed_rate += sd->sc_data[StatusChange::SC_SLOWMOVE].val1; diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 3bbd369..fee39d6 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -3920,6 +3920,7 @@ void builtin_sc_start(ScriptState *st) // all those use ms so this checks for < 1s are not needed on those // and it would break the cooldown symbol since many spells have cooldowns less than 1s case StatusChange::SC_PHYS_SHIELD: + case StatusChange::SC_PHYS_SHIELD_ITEM: case StatusChange::SC_MBARRIER: case StatusChange::SC_COOLDOWN: case StatusChange::SC_COOLDOWN_MG: diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 65df758..7454cc3 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -201,9 +201,9 @@ int skill_additional_effect(dumb_ptr src, dumb_ptr bl, } sc_def_phys_shield_spell = 0; - if (battle_get_sc_data(bl)[StatusChange::SC_PHYS_SHIELD].timer) + if (battle_get_sc_data(bl)[StatusChange::SC_PHYS_SHIELD].timer || battle_get_sc_data(bl)[StatusChange::SC_PHYS_SHIELD_ITEM].timer) sc_def_phys_shield_spell = - battle_get_sc_data(bl)[StatusChange::SC_PHYS_SHIELD].val1; + std::max(battle_get_sc_data(bl)[StatusChange::SC_PHYS_SHIELD].val1, battle_get_sc_data(bl)[StatusChange::SC_PHYS_SHIELD_ITEM].val1); // highest value is taken here but serverdata should make sure only one of those is active // 対象の耐性 | Target resistance luk = battle_get_luk(bl); @@ -753,6 +753,7 @@ void skill_status_change_end(dumb_ptr bl, StatusChange type, TimerDa case StatusChange::SC_ATKPOT: /* attack potion [Valaris] */ case StatusChange::SC_MATKPOT: /* magic attack potion [Valaris] */ case StatusChange::SC_PHYS_SHIELD: + case StatusChange::SC_PHYS_SHIELD_ITEM: case StatusChange::SC_HASTE: case StatusChange::SC_SLOWMOVE: calc_flag = 1; @@ -1033,6 +1034,7 @@ int skill_status_effect(dumb_ptr bl, StatusChange type, case StatusChange::SC_HASTE: case StatusChange::SC_PHYS_SHIELD: + case StatusChange::SC_PHYS_SHIELD_ITEM: case StatusChange::SC_MBARRIER: case StatusChange::SC_SLOWMOVE: calc_flag = 1; diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp index 25d7b3e..b0b6b8d 100644 --- a/src/mmo/skill.t.hpp +++ b/src/mmo/skill.t.hpp @@ -67,7 +67,9 @@ enum class StatusChange : uint16_t SC_CANTMOVE = 134, // stops all movement SC_ATKPOT = 185, // item script - SC_MATKPOT = 186, // unused, but kept for parallel + SC_MATKPOT = 186, // `Matk' spell from items (val1 : power) + + SC_PHYS_SHIELD_ITEM = 193, // `Protect' spell from items, reduce damage (val1: power) can't be chancelled with detsanc // Added for Fate's spells SC_HIDE = 194, // Hide from `detect' magic (PCs only) -- cgit v1.2.3-70-g09d2