diff options
-rw-r--r-- | CHANGELOG | 20 | ||||
-rw-r--r-- | src/map/atcommand.cpp | 111 | ||||
-rw-r--r-- | src/map/magic-stmt.cpp | 4 | ||||
-rw-r--r-- | src/map/map.hpp | 3 | ||||
-rw-r--r-- | src/map/mob.cpp | 50 | ||||
-rw-r--r-- | src/map/pc.cpp | 125 | ||||
-rw-r--r-- | src/map/pc.hpp | 3 | ||||
-rw-r--r-- | src/map/script-call.cpp | 4 | ||||
-rw-r--r-- | src/map/script-fun.cpp | 79 | ||||
-rwxr-xr-x | tools/config.py | 1 |
10 files changed, 191 insertions, 209 deletions
@@ -1,3 +1,23 @@ +v15.4.20 + - make spam warnings appear in General chat tab + - add builtin getnpcx + - add builtin getnpcy + - add builtin pvp + - add builtin getpvpflag + - add builtin strnpcinfo + - remove builtin cmdothernpc + - remove builtin killmonsterall + - remove builtin percentheal + - remove builtin itemheal + - modify builtin heal to include itemheal + - remove atcommand killer + - remove atcommand killable + - remove atcommand charkiller + - add atcommand pvp + - add atcommand charpvp + - add atcommand exprate + - remove warp debug (npc 722) + - add support for emote IDs over 100 v15.2.28 - Added Freeloop v15.1.23: diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index ad810f5..cb5e2fb 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1567,6 +1567,25 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd, } static +ATCE atcommand_exprate(Session *s, dumb_ptr<map_session_data>, + ZString message) +{ + int rate; + + if (!extract(message, &rate) || !rate) + { + clif_displaymessage(s, + "Please, enter a rate adjustement (usage: @exprate <percent>)."_s); + return ATCE::USAGE; + } + battle_config.base_exp_rate = rate; + battle_config.job_exp_rate = rate; + AString output = STRPRINTF("All Xp at %d percent"_fmt, rate); + clif_displaymessage(s, output); + return ATCE::OKAY; +} + +static ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd, ZString) { @@ -4011,81 +4030,40 @@ ATCE atcommand_character_storage_list(Session *s, dumb_ptr<map_session_data> sd, } static -ATCE atcommand_killer(Session *s, dumb_ptr<map_session_data> sd, +ATCE atcommand_pvp(Session *s, dumb_ptr<map_session_data> sd, ZString) { - sd->special_state.killer = !sd->special_state.killer; - - if (sd->special_state.killer) - clif_displaymessage(s, "You be a killa..."_s); - else - clif_displaymessage(s, "You gonna be own3d..."_s); - - return ATCE::OKAY; -} - -static -ATCE atcommand_charkiller(Session *s, dumb_ptr<map_session_data>, - ZString message) -{ - CharName character; - - if (!asplit(message, &character)) - return ATCE::USAGE; - - dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); - if (pl_sd == nullptr) - return ATCE::EXIST; - - pl_sd->special_state.killer = !pl_sd->special_state.killer; + int chan = sd->state.pvpchannel; + if (sd->pvp_timer || (chan > 1)) + return ATCE::OKAY; - if (pl_sd->special_state.killer) - { - clif_displaymessage(s, "The player is now a killer"_s); - clif_displaymessage(pl_sd->sess, "You are now a killer"_s); - } - else - { - clif_displaymessage(s, "The player is no longer a killer"_s); - clif_displaymessage(pl_sd->sess, "You are no longer a killer"_s); + if (chan < 1) { + sd->state.pvpchannel = 1; + clif_displaymessage(s, "##3PvP : ##BOn"_s); + } else { + sd->state.pvpchannel = 0; + clif_displaymessage(s, "##3PvP : ##BOff"_s); } + pc_setpvptimer(sd, battle_config.player_pvp_time); return ATCE::OKAY; } static -ATCE atcommand_killable(Session *s, dumb_ptr<map_session_data> sd, - ZString) -{ - sd->special_state.killable = !sd->special_state.killable; - - if (sd->special_state.killable) - clif_displaymessage(s, "You gonna be own3d..."_s); - else - clif_displaymessage(s, "You be a killa..."_s); - - return ATCE::OKAY; -} - -static -ATCE atcommand_charkillable(Session *s, dumb_ptr<map_session_data>, +ATCE atcommand_charpvp(Session *, dumb_ptr<map_session_data>, ZString message) { CharName character; + int channel; - if (!asplit(message, &character)) + if (!extract(message, record<' '>(&character, &channel))) return ATCE::USAGE; dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); if (pl_sd == nullptr) return ATCE::EXIST; - pl_sd->special_state.killable = !pl_sd->special_state.killable; - - if (pl_sd->special_state.killable) - clif_displaymessage(s, "The player is now killable"_s); - else - clif_displaymessage(s, "The player is no longer killable"_s); + pl_sd->state.pvpchannel = channel; return ATCE::OKAY; } @@ -5001,6 +4979,9 @@ Map<XString, AtCommandInfo> atcommand_info = {"pvpoff"_s, {""_s, 60, atcommand_pvpoff, "Enable PvP on your map"_s}}, + {"exprate"_s, {"<percent>"_s, + 60, atcommand_exprate, + "Set base job/exp rate"_s}}, {"pvpon"_s, {""_s, 60, atcommand_pvpon, "Disable PvP on your map"_s}}, @@ -5214,21 +5195,15 @@ Map<XString, AtCommandInfo> atcommand_info = {"addwarp"_s, {"<mapname> <x> <y>"_s, 80, atcommand_addwarp, "Create a new permanent warp"_s}}, - {"killer"_s, {""_s, - 60, atcommand_killer, - "Toggle whether you are a killer"_s}}, - {"charkiller"_s, {"<charname>"_s, - 60, atcommand_charkiller, - "Toggle whether a player is a killer"_s}}, + {"pvp"_s, {""_s, + 0, atcommand_pvp, + "Toggle your pvp flag"_s}}, {"npcmove"_s, {"<x> <y> <npc-name>"_s, 80, atcommand_npcmove, "Force an NPC to move on the map"_s}}, - {"killable"_s, {""_s, - 60, atcommand_killable, - "Toggle whether you are killable"_s}}, - {"charkillable"_s, {"<charname>"_s, - 60, atcommand_charkillable, - "Toggle whether a player is killable"_s}}, + {"charpvp"_s, {"<charname> <channel>"_s, + 40, atcommand_charpvp, + "Set the pvp channel of another player"_s}}, {"chareffect"_s, {"<type> <target>"_s, 40, atcommand_chareffect, "Apply effect type with arg 0 to a player"_s}}, diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index c69dafa..4d8330a 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -773,8 +773,8 @@ int op_injure(dumb_ptr<env_t> env, Slice<val_t> args) if (target->bl_type == BL::PC && !target->bl_m->flag.get(MapFlag::PVP) - && !target->is_player()->special_state.killable - && (caster->bl_type != BL::PC || !caster->is_player()->special_state.killer)) + && (caster->bl_type == BL::PC) + && ((caster->is_player()->state.pvpchannel > 1) && (target->is_player()->state.pvpchannel != caster->is_player()->state.pvpchannel))) return 0; /* Cannot damage other players outside of pvp */ if (target != caster) diff --git a/src/map/map.hpp b/src/map/map.hpp index 3dd03e7..f57dcee 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -142,11 +142,10 @@ struct map_session_data : block_list, SessionData unsigned shroud_disappears_on_pickup:1; unsigned shroud_disappears_on_talk:1; unsigned seen_motd:1; + unsigned pvpchannel; } state; struct { - unsigned killer:1; - unsigned killable:1; unsigned unbreakable_weapon:1; unsigned unbreakable_armor:1; unsigned deaf:1; diff --git a/src/map/mob.cpp b/src/map/mob.cpp index cdb348c..539b547 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -333,8 +333,7 @@ int mob_gen_exp(mob_db_ *mob) int xp = floor(effective_hp * pow(sqrt(attack_factor) + sqrt(dodge_factor) + sqrt(persuit_factor) + 55, 3) - * aggression_factor / 2000000.0 - * static_cast<double>(battle_config.base_exp_rate) / 100.); + * aggression_factor / 2000000.0); if (xp < 1) xp = 1; PRINTF("Exp for mob '%s' generated: %d\n"_fmt, mob->name, xp); @@ -3531,30 +3530,33 @@ bool mob_readdb(ZString filename) continue; } - // TODO move this lower - get_mob_db(mob_class) = std::move(mdbv); - if (get_mob_db(mob_class).base_exp < 0) - get_mob_db(mob_class).base_exp = 0; - else if (get_mob_db(mob_class).base_exp > 0 - && (get_mob_db(mob_class).base_exp * - battle_config.base_exp_rate / 100 > 1000000000 - || get_mob_db(mob_class).base_exp * - battle_config.base_exp_rate / 100 < 0)) - get_mob_db(mob_class).base_exp = 1000000000; - else - get_mob_db(mob_class).base_exp = get_mob_db(mob_class).base_exp * battle_config.base_exp_rate / 100; - + { + PRINTF("bad mob line: Xp needs to be greater than 0. %s\n"_fmt, line); + rv = false; + continue; + } + if (get_mob_db(mob_class).base_exp > 1000000000) + { + PRINTF("bad mob line: Xp needs to be less than 1000000000. %s\n"_fmt, line); + rv = false; + continue; + } if (get_mob_db(mob_class).job_exp < 0) - get_mob_db(mob_class).job_exp = 0; - else if (get_mob_db(mob_class).job_exp > 0 - && (get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / - 100 > 1000000000 - || get_mob_db(mob_class).job_exp * - battle_config.job_exp_rate / 100 < 0)) - get_mob_db(mob_class).job_exp = 1000000000; - else - get_mob_db(mob_class).job_exp = get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / 100; + { + PRINTF("bad mob line: Job Xp needs to be greater than 0. %s\n"_fmt, line); + rv = false; + continue; + } + if (get_mob_db(mob_class).job_exp > 1000000000) + { + PRINTF("bad mob line: Job Xp needs to be less than 1000000000. %s\n"_fmt, line); + rv = false; + continue; + } + + // TODO move this lower + get_mob_db(mob_class) = std::move(mdbv); for (int i = 0; i < 8; i++) { diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 7d04785..1e840ea 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -288,16 +288,12 @@ int pc_iskiller(dumb_ptr<map_session_data> src, { nullpo_retz(src); - if (src->bl_type != BL::PC) + if (src->bl_type != BL::PC || target->bl_type != BL::PC) return 0; - if (src->special_state.killer) + if ((src->state.pvpchannel == 1) && (target->state.pvpchannel == 1) && !src->bl_m->flag.get(MapFlag::NOPVP)) return 1; - - if (target->bl_type != BL::PC) - return 0; - if (target->special_state.killable) + if ((src->state.pvpchannel > 1) && (target->state.pvpchannel == src->state.pvpchannel)) // this one does not respect NOPVP return 1; - return 0; } @@ -320,6 +316,33 @@ int distance(int x0, int y0, int x1, int y1) } static +void pc_pvp_timer(TimerData *, tick_t, BlockId id) +{ + dumb_ptr<map_session_data> sd = map_id2sd(id); + + assert (sd != nullptr); + assert (sd->bl_type == BL::PC); +} + +int pc_setpvptimer(dumb_ptr<map_session_data> sd, interval_t val) +{ + nullpo_retz(sd); + + sd->pvp_timer = Timer(gettick() + val, + std::bind(pc_pvp_timer, ph::_1, ph::_2, + sd->bl_id)); + return 0; +} + +int pc_delpvptimer(dumb_ptr<map_session_data> sd) +{ + nullpo_retz(sd); + + sd->pvp_timer.cancel(); + return 0; +} + +static void pc_invincible_timer(TimerData *, tick_t, BlockId id) { dumb_ptr<map_session_data> sd = map_id2sd(id); @@ -378,7 +401,6 @@ int pc_setrestartvalue(dumb_ptr<map_session_data> sd, int type) clif_updatestatus(sd, SP::SP); sd->heal_xp = 0; // [Fate] Set gainable xp for healing this player to 0 - return 0; } @@ -899,6 +921,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) int bl; int aspd_rate, refinedef = 0; int str, dstr, dex; + int b_pvpchannel = 0; nullpo_retz(sd); @@ -927,6 +950,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) b_mdef = sd->mdef; b_mdef2 = sd->mdef2; b_base_atk = sd->base_atk; + if (!pc_isdead(sd) && sd->state.pvpchannel == 1) + b_pvpchannel = sd->state.pvpchannel; sd->max_weight = max_weight_base_0 + sd->status.attrs[ATTR::STR] * 300; @@ -1399,6 +1424,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) clif_updatestatus(sd, SP::HP); if (b_sp != sd->status.sp) clif_updatestatus(sd, SP::SP); + if (b_pvpchannel != sd->state.pvpchannel) + sd->state.pvpchannel = b_pvpchannel; return 0; } @@ -2856,6 +2883,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, } } + // Double Xp Weekends + base_exp = (base_exp * static_cast<double>(battle_config.base_exp_rate) / 100.); + if (base_exp <= 0) + base_exp = 0; + else if (base_exp > 1000000000) + base_exp = 1000000000; sd->status.base_exp += base_exp; // [Fate] Adjust experience points that healers can extract from this character @@ -2863,7 +2896,6 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, { const int max_heal_xp = 20 + (sd->status.base_level * sd->status.base_level); - sd->heal_xp += base_exp; if (sd->heal_xp > max_heal_xp) sd->heal_xp = max_heal_xp; @@ -2886,6 +2918,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, } } + // Double Xp Weekends + job_exp = (job_exp * static_cast<double>(battle_config.job_exp_rate) / 100.); + if (job_exp <= 0) + job_exp = 0; + else if (job_exp > 1000000000) + job_exp = 1000000000; sd->status.job_exp += job_exp; if (sd->status.job_exp < 0) sd->status.job_exp = 0; @@ -3690,75 +3728,6 @@ int pc_itemheal_effect(dumb_ptr<map_session_data> sd, int hp, int sp) } /*========================================== - * HP/SP回復 - *------------------------------------------ - */ -int pc_percentheal(dumb_ptr<map_session_data> sd, int hp, int sp) -{ - nullpo_retz(sd); - - if (pc_checkoverhp(sd)) - { - if (hp > 0) - hp = 0; - } - if (pc_checkoversp(sd)) - { - if (sp > 0) - sp = 0; - } - if (hp) - { - if (hp >= 100) - { - sd->status.hp = sd->status.max_hp; - } - else if (hp <= -100) - { - sd->status.hp = 0; - pc_damage(nullptr, sd, 1); - } - else - { - sd->status.hp += sd->status.max_hp * hp / 100; - if (sd->status.hp > sd->status.max_hp) - sd->status.hp = sd->status.max_hp; - if (sd->status.hp <= 0) - { - sd->status.hp = 0; - pc_damage(nullptr, sd, 1); - hp = 0; - } - } - } - if (sp) - { - if (sp >= 100) - { - sd->status.sp = sd->status.max_sp; - } - else if (sp <= -100) - { - sd->status.sp = 0; - } - else - { - sd->status.sp += sd->status.max_sp * sp / 100; - if (sd->status.sp > sd->status.max_sp) - sd->status.sp = sd->status.max_sp; - if (sd->status.sp < 0) - sd->status.sp = 0; - } - } - if (hp) - clif_updatestatus(sd, SP::HP); - if (sp) - clif_updatestatus(sd, SP::SP); - - return 0; -} - -/*========================================== * 見た目変更 *------------------------------------------ */ diff --git a/src/map/pc.hpp b/src/map/pc.hpp index ba0a46f..14829d1 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -138,7 +138,6 @@ int pc_useitem(dumb_ptr<map_session_data>, IOff0); int pc_damage(dumb_ptr<block_list>, dumb_ptr<map_session_data>, int); int pc_heal(dumb_ptr<map_session_data>, int, int); int pc_itemheal(dumb_ptr<map_session_data> sd, int hp, int sp); -int pc_percentheal(dumb_ptr<map_session_data> sd, int, int); int pc_changelook(dumb_ptr<map_session_data>, LOOK, int); int pc_readparam(dumb_ptr<map_session_data>, SP); @@ -170,6 +169,8 @@ void pc_setstand(dumb_ptr<map_session_data> sd); void pc_cleanup(dumb_ptr<map_session_data> sd); // [Fate] Clean up after a logged-out PC int pc_read_gm_account(Session *, const std::vector<Packet_Repeat<0x2b15>>&); +int pc_setpvptimer(dumb_ptr<map_session_data> sd, interval_t); +int pc_delpvptimer(dumb_ptr<map_session_data> sd); int pc_setinvincibletimer(dumb_ptr<map_session_data> sd, interval_t); int pc_delinvincibletimer(dumb_ptr<map_session_data> sd); int pc_logout(dumb_ptr<map_session_data> sd); // [fate] Player logs out diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp index f412328..c3c6aa1 100644 --- a/src/map/script-call.cpp +++ b/src/map/script-call.cpp @@ -757,7 +757,7 @@ void run_script_main(ScriptState *st, Borrowed<const ScriptBuffer> rootscript) { rerun_pos = st->scriptp.pos; st->state = ScriptEndState::ZERO; - if (!st->freeloop && gotocount > 0 && (--gotocount) <= 0) + if (st->freeloop != 1 && gotocount > 0 && (--gotocount) <= 0) { PRINTF("run_script: infinity loop !\n"_fmt); st->state = ScriptEndState::END; @@ -806,7 +806,7 @@ void run_script_main(ScriptState *st, Borrowed<const ScriptBuffer> rootscript) st->state = ScriptEndState::END; break; } - if (!st->freeloop && cmdcount > 0 && (--cmdcount) <= 0) + if (st->freeloop != 1 && cmdcount > 0 && (--cmdcount) <= 0) { PRINTF("run_script: infinity loop !\n"_fmt); st->state = ScriptEndState::END; diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index da26e2b..4cb4448 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -402,38 +402,22 @@ static void builtin_heal(ScriptState *st) { int hp, sp; + dumb_ptr<map_session_data> sd = script_rid2sd(st); hp = conv_num(st, &AARG(0)); sp = conv_num(st, &AARG(1)); - pc_heal(script_rid2sd(st), hp, sp); -} - -/*========================================== - * - *------------------------------------------ - */ -static -void builtin_itemheal(ScriptState *st) -{ - int hp, sp; - - hp = conv_num(st, &AARG(0)); - sp = conv_num(st, &AARG(1)); - pc_itemheal(script_rid2sd(st), hp, sp); -} -/*========================================== - * - *------------------------------------------ - */ -static -void builtin_percentheal(ScriptState *st) -{ - int hp, sp; + if(sd != nullptr && (sd->status.hp < 1 && hp > 0)){ + pc_setstand(sd); + if (battle_config.player_invincible_time > interval_t::zero()) + pc_setinvincibletimer(sd, battle_config.player_invincible_time); + clif_resurrection(sd, 1); + } - hp = conv_num(st, &AARG(0)); - sp = conv_num(st, &AARG(1)); - pc_percentheal(script_rid2sd(st), hp, sp); + if(HARG(2) && bool(conv_num(st, &AARG(2))) && hp > 0) + pc_itemheal(sd, hp, sp); + else + pc_heal(sd, hp, sp); } /*========================================== @@ -2156,6 +2140,37 @@ void builtin_pvpoff(ScriptState *st) } } +static +void builtin_setpvpchannel(ScriptState *st) +{ + dumb_ptr<map_session_data> sd = script_rid2sd(st); + int flag; + flag = conv_num(st, &AARG(0)); + if (flag < 1) + flag = 0; + + sd->state.pvpchannel = flag; +} + +static +void builtin_getpvpflag(ScriptState *st) +{ + dumb_ptr<map_session_data> sd = script_rid2sd(st); + int num = conv_num(st, &AARG(0)); + int flag = 0; + + switch (num){ + case 0: + flag = sd->state.pvpchannel; + break; + case 1: + flag = bool(sd->status.option & Opt0::HIDE); + break; + } + + push_int<ScriptDataInt>(st->stack, flag); +} + /*========================================== * NPCエモーション *------------------------------------------ @@ -2296,11 +2311,11 @@ void builtin_getitemlink(ScriptState *st) { OMATCH_CASE_SOME (item_data) { - buf = STRPRINTF("[@@%d|%s@@]"_fmt, item_data->nameid, item_data->jname); + buf = STRPRINTF("@@%d|@@"_fmt, item_data->nameid); } OMATCH_CASE_NONE () { - buf = STRPRINTF("Unknown Item: %s"_fmt, name); + buf = "Unknown Item"_s; } } OMATCH_END (); @@ -3095,9 +3110,7 @@ BuiltinFunction builtin_functions[] = BUILTIN(isat, "Mxy"_s, 'i'), BUILTIN(warp, "Mxy"_s, '\0'), BUILTIN(areawarp, "MxyxyMxy"_s, '\0'), - BUILTIN(heal, "ii"_s, '\0'), - BUILTIN(itemheal, "ii"_s, '\0'), - BUILTIN(percentheal, "ii"_s, '\0'), + BUILTIN(heal, "ii?"_s, '\0'), BUILTIN(input, "N"_s, '\0'), BUILTIN(if, "iF*"_s, '\0'), BUILTIN(set, "Ne"_s, '\0'), @@ -3163,6 +3176,8 @@ BuiltinFunction builtin_functions[] = BUILTIN(getmapflag, "Mi"_s, 'i'), BUILTIN(pvpon, "M"_s, '\0'), BUILTIN(pvpoff, "M"_s, '\0'), + BUILTIN(setpvpchannel, "i"_s, '\0'), + BUILTIN(getpvpflag, "i"_s, 'i'), BUILTIN(emotion, "i"_s, '\0'), BUILTIN(mapwarp, "MMxy"_s, '\0'), BUILTIN(mobcount, "ME"_s, 'i'), diff --git a/tools/config.py b/tools/config.py index 88b7644..a32e8ca 100755 --- a/tools/config.py +++ b/tools/config.py @@ -613,6 +613,7 @@ def build_config(): battle_conf.opt('mob_count_rate', percent, '100') battle_conf.opt('basic_skill_check', bool, 'true') battle_conf.opt('player_invincible_time', milliseconds, '5_s') + battle_conf.opt('player_pvp_time', milliseconds, '5_s') battle_conf.opt('skill_min_damage', bool, 'false') battle_conf.opt('natural_healhp_interval', milliseconds, '6_s', {map_h}, min='NATURAL_HEAL_INTERVAL') battle_conf.opt('natural_healsp_interval', milliseconds, '8_s', {map_h}, min='NATURAL_HEAL_INTERVAL') |