diff options
author | HoraK-FDF <horak-fdf@web.de> | 2022-11-11 18:05:41 +0100 |
---|---|---|
committer | HoraK-FDF <horak-fdf@web.de> | 2022-11-11 18:05:41 +0100 |
commit | f8292b7c0c706223694edcbeab1097baa2127168 (patch) | |
tree | df9ec65b182a8f662c945d2c7f12da60c60d4fe6 /src | |
parent | 9a3566484f2345db599552a6c18311978a0071ea (diff) | |
download | tmwa-f8292b7c0c706223694edcbeab1097baa2127168.tar.gz tmwa-f8292b7c0c706223694edcbeab1097baa2127168.tar.bz2 tmwa-f8292b7c0c706223694edcbeab1097baa2127168.tar.xz tmwa-f8292b7c0c706223694edcbeab1097baa2127168.zip |
mobinfo
Diffstat (limited to 'src')
-rw-r--r-- | src/map/atcommand.cpp | 209 | ||||
-rw-r--r-- | src/map/clif.cpp | 4 | ||||
-rw-r--r-- | src/map/globals.cpp | 2 | ||||
-rw-r--r-- | src/map/globals.hpp | 3 | ||||
-rw-r--r-- | src/map/mob.cpp | 7 | ||||
-rw-r--r-- | src/map/mob.hpp | 6 | ||||
-rw-r--r-- | src/map/script-fun.cpp | 385 | ||||
-rw-r--r-- | src/map/script-fun.hpp | 2 | ||||
-rw-r--r-- | src/map/script-fun.t.hpp | 96 | ||||
-rw-r--r-- | src/map/skill.cpp | 61 | ||||
-rw-r--r-- | src/mmo/skill.t.hpp | 4 |
11 files changed, 695 insertions, 84 deletions
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 459672d..0de297f 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1822,6 +1822,169 @@ ATCE atcommand_hair_color(Session *s, dumb_ptr<map_session_data> sd, } static +ATCE atcommand_mobinfo(Session *s, dumb_ptr<map_session_data> sd, + ZString message) +{ + MobName name; + Species mob_id; + int exp; + + if (!extract(message, &name) || !name) + return ATCE::USAGE; + + if ((mob_id = wrap<Species>(static_cast<uint16_t>(atoi(name.c_str())))) == Species()) + mob_id = mobdb_searchname(name); + 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"_fmt, get_mob_db(mob_id).range, get_mob_db(mob_id).atk1, get_mob_db(mob_id).atk2, get_mob_db(mob_id).def, get_mob_db(mob_id).mdef)); + clif_displaymessage(s, STRPRINTF("Stats: STR: %i, AGI: %i, VIT: %i, INT: %i, DEX:, %i LUK:, %i"_fmt, get_mob_db(mob_id).attrs[ATTR::STR], get_mob_db(mob_id).attrs[ATTR::AGI], get_mob_db(mob_id).attrs[ATTR::VIT], get_mob_db(mob_id).attrs[ATTR::INT], get_mob_db(mob_id).attrs[ATTR::DEX], get_mob_db(mob_id).attrs[ATTR::LUK])); + clif_displaymessage(s, STRPRINTF("Range2: %i, Range3: %i, Scale: %i, Race: %i, Element: %i, Element Level: %i, Mode: %i"_fmt, get_mob_db(mob_id).range2, get_mob_db(mob_id).range3, get_mob_db(mob_id).size, get_mob_db(mob_id).race, get_mob_db(mob_id).element.element, get_mob_db(mob_id).element.level, get_mob_db(mob_id).mode)); + clif_displaymessage(s, STRPRINTF("Speed: %i, Adelay: %i, Amotion: %i, Dmotion: %i"_fmt, get_mob_db(mob_id).speed.count(), get_mob_db(mob_id).adelay.count(), get_mob_db(mob_id).amotion.count(), get_mob_db(mob_id).dmotion.count())); + if (get_mob_db(mob_id).mutations_nr) + 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)); + + for (int i = 0; i < MaxDrops; ++i) + if (get_mob_db(mob_id).dropitem[i].nameid) + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[i].nameid)); + RString item_name = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + + int drop_rate = get_mob_db(mob_id).dropitem[i].p.num; + + char str[6]; + char strpos = 0; + + char min = 0; + char mod = 0; + char fraction = drop_rate % 100; + char integer = drop_rate / 100; + + if (fraction) + { + if (fraction < 10) + min = 1; + do + { + mod = fraction % 10; + fraction = fraction / 10; + if (!(strpos == 0 && mod == 0)) + { + str[strpos] = '0' + mod; + ++strpos; + } + } while (fraction > 0); + if (min) + { + str[strpos] = '0'; + ++strpos; + } + str[strpos] = '.'; + ++strpos; + } + if (integer) + { + do + { + mod = integer % 10; + integer = integer / 10; + str[strpos] = '0' + mod; + ++strpos; + } while (integer > 0); + } + else + { + str[strpos] = '0'; + ++strpos; + } + // flip string + for (char i=0, tmpstrpos=strpos-1; i <= tmpstrpos/2; ++i, --tmpstrpos) + { + char tmp = str[tmpstrpos]; + str[tmpstrpos]=str[i]; + str[i]=tmp; + } + str[strpos] = '\0'; + + int drop_rate2 = 10000/drop_rate; + clif_displaymessage(s, STRPRINTF("Drop ID %i: %i, Item Name: %s, Drop Chance: %s%% (1:%i)"_fmt,i+1, get_mob_db(mob_id).dropitem[i].nameid, item_name, str, drop_rate2)); + } + else + break; + + clif_displaymessage(s, STRPRINTF("Mob Mode Info:"_fmt)); + if (!bool(get_mob_db(mob_id).mode & MobMode::ZERO)) + { + if (bool(get_mob_db(mob_id).mode & MobMode::CAN_MOVE)) + clif_displaymessage(s, STRPRINTF("Mobile"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::LOOTER)) + clif_displaymessage(s, STRPRINTF("Picks up loot"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::AGGRESSIVE)) + clif_displaymessage(s, STRPRINTF("Aggro"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::ASSIST)) + clif_displaymessage(s, STRPRINTF("Assists"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::CAST_SENSOR)) + clif_displaymessage(s, STRPRINTF("Cast Sensor"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::BOSS)) + clif_displaymessage(s, STRPRINTF("Boss"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::PLANT)) + clif_displaymessage(s, STRPRINTF("Plant"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::CAN_ATTACK)) + clif_displaymessage(s, STRPRINTF("Can attack"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::DETECTOR)) + clif_displaymessage(s, STRPRINTF("Detector"_fmt)); + if (bool(get_mob_db(mob_id).mode & MobMode::CHANGE_TARGET)) + clif_displaymessage(s, STRPRINTF("Change Target"_fmt)); + /* + Not needed here i guess + SUMMONED + TURNS_AGAINST_BAD_MASTER + SENSIBLE_MASK + */ + } + return ATCE::OKAY; +} + +static +ATCE atcommand_summon(Session *, dumb_ptr<map_session_data> sd, + ZString message) +{ + MobName name; + Species mob_id; + int x = 0; + int y = 0; + tick_t tick = gettick(); + + if (!extract(message, &name) || !name) + return ATCE::USAGE; + + if ((mob_id = wrap<Species>(static_cast<uint16_t>(atoi(name.c_str())))) == Species()) + mob_id = mobdb_searchname(name); + if (mob_id == Species()) + return ATCE::EXIST; + + x = sd->bl_x + random_::in(-5, 4); + y = sd->bl_y + random_::in(-5, 4); + + BlockId id = mob_once_spawn(sd, MOB_THIS_MAP, x, y, JAPANESE_NAME, mob_id, 1, NpcEvent()); + dumb_ptr<mob_data> md = map_id_is_mob(id); + if (md) + { + md->master_id = sd->bl_id; + md->state.special_mob_ai = 1; + md->mode = get_mob_db(md->mob_class).mode | MobMode::AGGRESSIVE; + md->deletetimer = Timer(tick + 1_min, + std::bind(mob_timer_delete, ph::_1, ph::_2, + id)); + clif_misceffect(md, 344); + } + + return ATCE::OKAY; +} + +static ATCE atcommand_spawn(Session *s, dumb_ptr<map_session_data> sd, ZString message) { @@ -4552,43 +4715,6 @@ ATCE atcommand_leaves(Session *, dumb_ptr<map_session_data> sd, } static -ATCE atcommand_summon(Session *, dumb_ptr<map_session_data> sd, - ZString message) -{ - MobName name; - Species mob_id; - int x = 0; - int y = 0; - tick_t tick = gettick(); - - if (!extract(message, &name) || !name) - return ATCE::USAGE; - - if ((mob_id = wrap<Species>(static_cast<uint16_t>(atoi(name.c_str())))) == Species()) - mob_id = mobdb_searchname(name); - if (mob_id == Species()) - return ATCE::EXIST; - - x = sd->bl_x + random_::in(-5, 4); - y = sd->bl_y + random_::in(-5, 4); - - BlockId id = mob_once_spawn(sd, MOB_THIS_MAP, x, y, JAPANESE_NAME, mob_id, 1, NpcEvent()); - dumb_ptr<mob_data> md = map_id_is_mob(id); - if (md) - { - md->master_id = sd->bl_id; - md->state.special_mob_ai = 1; - md->mode = get_mob_db(md->mob_class).mode | MobMode::AGGRESSIVE; - md->deletetimer = Timer(tick + 1_min, - std::bind(mob_timer_delete, ph::_1, ph::_2, - id)); - clif_misceffect(md, 344); - } - - return ATCE::OKAY; -} - -static ATCE atcommand_adjcmdlvl(Session *s, dumb_ptr<map_session_data>, ZString message) { @@ -5325,6 +5451,12 @@ Map<XString, AtCommandInfo> atcommand_info = {"model"_s, {"<style> [color] [dye]"_s, 98, atcommand_model, "Change your hairstyle and hair color"_s}}, + {"mobinfo"_s, {"<mob-id-or-name>"_s, + 0, atcommand_mobinfo, + "Show stats of a monster."_s}}, + {"summon"_s, {"<mob-id-or-name>"_s, + 50, atcommand_summon, + "Summon a slave monster temporarily"_s}}, {"spawn"_s, {"<mob-name-or-id> [count] [x] [y]"_s, 50, atcommand_spawn, "Spawn normal monsters at location."_s}}, @@ -5577,9 +5709,6 @@ Map<XString, AtCommandInfo> atcommand_info = {"leaves"_s, {""_s, 98, atcommand_leaves, "Enable the leaves mapflag"_s}}, - {"summon"_s, {"<mob-id-or-name>"_s, - 50, atcommand_summon, - "Summon a slave monster temporarily"_s}}, {"adjgmlvl"_s, {"<level> <charname>"_s, 98, atcommand_adjgmlvl, "Temporarily adjust the GM level of a player"_s}}, diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 1c78cd0..f71feb6 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -1691,6 +1691,8 @@ int clif_storageequiplist(dumb_ptr<map_session_data> sd, Borrowed<Storage> stor) /*========================================== * ステータスを送りつける * 表示専用数字はこの中で計算して送る + * send status + * Display-only numbers are calculated and sent here *------------------------------------------ */ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) @@ -2189,6 +2191,7 @@ void clif_pvpstatus(dumb_ptr<map_session_data> sd) /*========================================== * 表示オプション変更 + * Change display options *------------------------------------------ */ int clif_changeoption(dumb_ptr<block_list> bl) @@ -2992,6 +2995,7 @@ int clif_skill_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, /*========================================== * 状態異常アイコン/メッセージ表示 + * Abnormal status icon/message display *------------------------------------------ */ int clif_status_change(dumb_ptr<block_list> bl, StatusChange type, int flag) diff --git a/src/map/globals.cpp b/src/map/globals.cpp index 97533c8..8a4d22b 100644 --- a/src/map/globals.cpp +++ b/src/map/globals.cpp @@ -70,7 +70,7 @@ namespace tmwa block_list bl_head; std::unique_ptr<io::AppendFile> map_logfile; long map_logfile_index; - mob_db_ mob_db[2001]; + mob_db_ mob_db[MaxMobs]; std::list<AString> npc_srcs; int npc_warp, npc_shop, npc_script, npc_mob; BlockId npc_id = START_NPC_NUM; diff --git a/src/map/globals.hpp b/src/map/globals.hpp index 107ed5e..f33f316 100644 --- a/src/map/globals.hpp +++ b/src/map/globals.hpp @@ -36,6 +36,7 @@ #include "../mmo/skill.t.hpp" #include "consts.hpp" +#include "mob.hpp" #include "script-buffer.hpp" @@ -63,7 +64,7 @@ namespace tmwa extern block_list bl_head; extern std::unique_ptr<io::AppendFile> map_logfile; extern long map_logfile_index; - extern mob_db_ mob_db[2001]; + extern mob_db_ mob_db[MaxMobs]; extern std::list<AString> npc_srcs; extern int npc_warp, npc_shop, npc_script, npc_mob; extern BlockId npc_id; diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 0da946a..787f9fe 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -307,7 +307,6 @@ void mob_mutate(dumb_ptr<mob_data> md, mob_stat stat, int intensity) } // This calculates the exp of a given mob -static int mob_gen_exp(mob_db_ *mob) { if (mob->max_hp <= 1) @@ -2647,7 +2646,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, // item drop if (!(type & 1)) { - for (int i = 0; i < 8; i++) + for (int i = 0; i < MaxDrops; i++) { if (md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) // Added [Valaris] break; // End @@ -3439,7 +3438,7 @@ int mob_makedummymobdb(Species mob_class) get_mob_db(mob_class).adelay = 1000_ms; get_mob_db(mob_class).amotion = 500_ms; get_mob_db(mob_class).dmotion = 500_ms; - for (i = 0; i < 8; i++) + for (i = 0; i < MaxDrops; i++) { get_mob_db(mob_class).dropitem[i].nameid = ItemNameId(); get_mob_db(mob_class).dropitem[i].p.num = 0; @@ -3577,7 +3576,7 @@ bool mob_readdb(ZString filename) // TODO move this lower get_mob_db(mob_class) = std::move(mdbv); - for (int i = 0; i < 8; i++) + for (int i = 0; i < MaxDrops; i++) { int rate = get_mob_db(mob_class).dropitem[i].p.num; if (rate < 1) rate = 1; diff --git a/src/map/mob.hpp b/src/map/mob.hpp index a466d0b..0530329 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -43,6 +43,9 @@ namespace map #define JAPANESE_NAME stringish<MobName>("--ja--"_s) #define MOB_THIS_MAP stringish<MapName>("this"_s) +#define MaxDrops 8 +#define MaxMobs 2001 + struct mob_skill { MobSkillState state; @@ -79,7 +82,7 @@ struct mob_db_ { ItemNameId nameid; random_::Fixed<int, 10000> p; - } dropitem[8]; + } dropitem[MaxDrops]; short hair, hair_color, weapon; ItemNameId shield, head_top, head_mid, head_buttom; short option, clothes_color; // [Valaris] @@ -99,6 +102,7 @@ BlockId mob_once_spawn_area(dumb_ptr<map_session_data> sd, MobName mobname, Species class_, int amount, NpcEvent event); +int mob_gen_exp(mob_db_ *mob); int mob_target(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl, int dist); int mob_aggravate(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl); int mob_stop_walking(dumb_ptr<mob_data> md, int type); diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 135aef9..34e14b0 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -2628,6 +2628,341 @@ void builtin_getexp(ScriptState *st) *------------------------------------------ */ static +void builtin_mobinfo(ScriptState *st) +{ + Species mob_id = wrap<Species>(conv_num(st, &AARG(0))); + MobInfo request = MobInfo(conv_num(st, &AARG(1))); + int info = 0; + AString info_str; + char mode = 0; // 0 = int, 1 = str + + switch (request) + { + case MobInfo::ID: + info = unwrap<Species>(mob_id); + break; + case MobInfo::ENG_NAME: + info_str = get_mob_db(mob_id).name; + mode = 1; + break; + case MobInfo::JAP_NAME: + info_str = get_mob_db(mob_id).jname; + mode = 1; + break; + case MobInfo::LVL: + info = get_mob_db(mob_id).lv; + break; + case MobInfo::HP: + info = get_mob_db(mob_id).max_hp; + break; + case MobInfo::SP: + info = get_mob_db(mob_id).max_sp; + break; + case MobInfo::BASE_EXP: + info = get_mob_db(mob_id).base_exp; + break; + case MobInfo::JOB_EXP: + info = get_mob_db(mob_id).job_exp; + break; + case MobInfo::RANGE1: + info = get_mob_db(mob_id).range; + break; + case MobInfo::ATK1: + info = get_mob_db(mob_id).atk1; + break; + case MobInfo::ATK2: + info = get_mob_db(mob_id).atk2; + break; + case MobInfo::DEF: + info = get_mob_db(mob_id).def; + break; + case MobInfo::MDEF: + info = get_mob_db(mob_id).mdef; + break; + case MobInfo::STR: + info = get_mob_db(mob_id).attrs[ATTR::STR]; + break; + case MobInfo::AGI: + info = get_mob_db(mob_id).attrs[ATTR::AGI]; + break; + case MobInfo::VIT: + info = get_mob_db(mob_id).attrs[ATTR::VIT]; + break; + case MobInfo::INT: + info = get_mob_db(mob_id).attrs[ATTR::INT]; + break; + case MobInfo::DEX: + info = get_mob_db(mob_id).attrs[ATTR::DEX]; + break; + case MobInfo::LUK: + info = get_mob_db(mob_id).attrs[ATTR::LUK]; + break; + case MobInfo::RANGE2: + info = get_mob_db(mob_id).range2; + break; + case MobInfo::RANGE3: + info = get_mob_db(mob_id).range3; + break; + case MobInfo::SCALE: + info = get_mob_db(mob_id).size; + break; + case MobInfo::RACE: + info = int(get_mob_db(mob_id).race); + break; + case MobInfo::ELEMENT: + info = int(get_mob_db(mob_id).element.element); + break; + case MobInfo::ELEMENT_LVL: + info = get_mob_db(mob_id).element.level; + break; + case MobInfo::MODE: + info = int(get_mob_db(mob_id).mode); + break; + case MobInfo::SPEED: + info = get_mob_db(mob_id).speed.count(); + break; + case MobInfo::ADELAY: + info = get_mob_db(mob_id).adelay.count(); + break; + case MobInfo::AMOTION: + info = get_mob_db(mob_id).amotion.count(); + break; + case MobInfo::DMOTION: + info = get_mob_db(mob_id).dmotion.count(); + break; + case MobInfo::MUTATION_NUM: + info = get_mob_db(mob_id).mutations_nr; + break; + case MobInfo::MUTATION_POWER: + info = get_mob_db(mob_id).mutation_power; + break; + case MobInfo::DROPID1: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[0].nameid); + break; + case MobInfo::DROPNAME1: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[0].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT1: + info = get_mob_db(mob_id).dropitem[0].p.num; + break; + case MobInfo::DROPID2: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[1].nameid); + break; + case MobInfo::DROPNAME2: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[1].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT2: + info = get_mob_db(mob_id).dropitem[1].p.num; + break; + case MobInfo::DROPID3: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[2].nameid); + break; + case MobInfo::DROPNAME3: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[2].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT3: + info = get_mob_db(mob_id).dropitem[2].p.num; + break; + case MobInfo::DROPID4: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[3].nameid); + break; + case MobInfo::DROPNAME4: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[3].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT4: + info = get_mob_db(mob_id).dropitem[3].p.num; + break; + case MobInfo::DROPID5: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[4].nameid); + break; + case MobInfo::DROPNAME5: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[4].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT5: + info = get_mob_db(mob_id).dropitem[4].p.num; + break; + case MobInfo::DROPID6: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[5].nameid); + break; + case MobInfo::DROPNAME6: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[5].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT6: + info = get_mob_db(mob_id).dropitem[5].p.num; + break; + case MobInfo::DROPID7: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[6].nameid); + break; + case MobInfo::DROPNAME7: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[6].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT7: + info = get_mob_db(mob_id).dropitem[6].p.num; + break; + case MobInfo::DROPID8: + info = unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[7].nameid); + break; + case MobInfo::DROPNAME8: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[7].nameid)); + info_str = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + mode = 1; + } + break; + case MobInfo::DROPPERCENT8: + info = get_mob_db(mob_id).dropitem[7].p.num; + break; + default: + PRINTF("builtin_mobinfo: unknown request\n"_fmt); + info_str = "mobinfo: unknown request"_s; + mode = 1; + break; + } + if (!mode) + push_int<ScriptDataInt>(st->stack, info); + else + push_str<ScriptDataStr>(st->stack, info_str); +} + +/*========================================== + * + * + *------------------------------------------ + */ +static +void builtin_mobinfo_droparrays(ScriptState *st) +{ + dumb_ptr<block_list> bl = nullptr; + + Species mob_id = wrap<Species>(conv_num(st, &AARG(0))); + + MobInfo_DropArrays request = MobInfo_DropArrays(conv_num(st, &AARG(1))); + + SIR reg = AARG(2).get_if<ScriptDataVariable>()->reg; + ZString name = variable_names.outtern(reg.base()); + + char prefix = name.front(); + char postfix = name.back(); + + if (prefix != '$' && prefix != '@' && prefix != '.') + { + PRINTF("builtin_mobinfo_droparrays: illegal scope!\n"_fmt); + return; + } + + if (prefix == '.' && !name.startswith(".@"_s)) + bl = map_id_is_npc(st->oid); + else if (prefix != '$' && !name.startswith(".@"_s)) + { + bl = map_id_is_player(st->rid); + script_nullpo_end(bl, "player not found"); + } + + switch (request) + { + case MobInfo_DropArrays::IDS: + if (postfix == '$') + { + PRINTF("builtin_mobinfo_droparrays: wrong array type for ID's (Int expected but String found)!\n"_fmt); + return; + } + break; + case MobInfo_DropArrays::NAMES: + if (postfix != '$') + { + PRINTF("builtin_mobinfo_droparrays: wrong array type for Names (String expected but Int found)!\n"_fmt); + return; + } + break; + case MobInfo_DropArrays::PERCENTS: + if (postfix == '$') + { + PRINTF("builtin_mobinfo_droparrays: wrong array type for Percents (Int expected but String found)!\n"_fmt); + return; + } + break; + default: + PRINTF("builtin_mobinfo_droparrays: unknown request\n"_fmt); + break; + } + + for (int i = 0; i < MaxDrops; ++i) + if (get_mob_db(mob_id).dropitem[i].nameid) + { + switch (request) + { + case MobInfo_DropArrays::IDS: + if (name.startswith(".@"_s)) + { + struct script_data vd = script_data(ScriptDataInt{unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[i].nameid)}); + set_scope_reg(st, reg.iplus(i), &vd); + } + else + set_reg(bl, VariableCode::VARIABLE, reg.iplus(i), unwrap<ItemNameId>(get_mob_db(mob_id).dropitem[i].nameid)); + break; + case MobInfo_DropArrays::NAMES: + { + Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[i].nameid)); + RString item_name = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s)); + + if (name.startswith(".@"_s)) + { + struct script_data vd = script_data(ScriptDataStr{item_name}); + set_scope_reg(st, reg.iplus(i), &vd); + } + else + set_reg(bl, VariableCode::VARIABLE, reg.iplus(i), item_name); + break; + } + case MobInfo_DropArrays::PERCENTS: + if (name.startswith(".@"_s)) + { + struct script_data vd = script_data(ScriptDataInt{get_mob_db(mob_id).dropitem[i].p.num}); + set_scope_reg(st, reg.iplus(i), &vd); + } + else + set_reg(bl, VariableCode::VARIABLE, reg.iplus(i), get_mob_db(mob_id).dropitem[i].p.num); + break; + } + } + else + break; + +} + +/*========================================== + * + *------------------------------------------ + */ +static void builtin_summon(ScriptState *st) { NpcEvent event; @@ -2636,11 +2971,12 @@ void builtin_summon(ScriptState *st) int y = conv_num(st, &AARG(2)); dumb_ptr<block_list> owner_e = map_id2bl(wrap<BlockId>(conv_num(st, &AARG(3)))); dumb_ptr<map_session_data> owner = nullptr; - Species monster_id = wrap<Species>(conv_num(st, &AARG(4))); - MonsterAttitude monster_attitude = static_cast<MonsterAttitude>(conv_num(st, &AARG(5))); - interval_t lifespan = static_cast<interval_t>(conv_num(st, &AARG(6))); + MobName str = stringish<MobName>(ZString(conv_str(st, &AARG(4)))); + Species monster_id = wrap<Species>(conv_num(st, &AARG(5))); + MonsterAttitude monster_attitude = static_cast<MonsterAttitude>(conv_num(st, &AARG(6))); + interval_t lifespan = static_cast<interval_t>(conv_num(st, &AARG(7))); if (HARG(7)) - extract(ZString(conv_str(st, &AARG(7))), &event); + extract(ZString(conv_str(st, &AARG(8))), &event); if (!owner_e) { @@ -2652,7 +2988,9 @@ void builtin_summon(ScriptState *st) && owner_e->bl_type == BL::PC) owner = owner_e->is_player(); // XXX in the future this should also work with mobs as owner - BlockId mob_id = mob_once_spawn(owner, map, x, y, MobName(), monster_id, 1, event); + if (!str) + str = MobName(); + BlockId mob_id = mob_once_spawn(owner, map, x, y, str, monster_id, 1, event); dumb_ptr<mob_data> mob = map_id_is_mob(mob_id); if (mob) @@ -3393,14 +3731,31 @@ void builtin_sc_start(ScriptState *st) StatusChange type = static_cast<StatusChange>(conv_num(st, &AARG(0))); interval_t tick = static_cast<interval_t>(conv_num(st, &AARG(1))); if (tick < 1_s) - // work around old behaviour of: - // speed potion - // atk potion - // matk potion - // - // which used to use seconds - // all others used milliseconds - tick *= 1000; + switch (type) + { + // 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_MBARRIER: + case StatusChange::SC_COOLDOWN: + case StatusChange::SC_COOLDOWN_MG: + case StatusChange::SC_COOLDOWN_MT: + case StatusChange::SC_COOLDOWN_R: + case StatusChange::SC_COOLDOWN_AR: + case StatusChange::SC_COOLDOWN_ENCH: + case StatusChange::SC_COOLDOWN_KOY: + break; + + default: + // work around old behaviour of: + // speed potion + // atk potion + // matk potion + // + // which used to use seconds + // all others used milliseconds + tick *= 1000; + } val1 = conv_num(st, &AARG(2)); if (HARG(3)) //指定したキャラを状態異常にする | Make the specified character abnormal bl = map_id2bl(wrap<BlockId>(conv_num(st, &AARG(3)))); @@ -5114,7 +5469,9 @@ BuiltinFunction builtin_functions[] = BUILTIN(gettime, "i"_s, 'i'), BUILTIN(openstorage, ""_s, '\0'), BUILTIN(getexp, "ii"_s, '\0'), - BUILTIN(summon, "Mxysmii?"_s, '\0'), + BUILTIN(mobinfo, "ii"_s, 'v'), + BUILTIN(mobinfo_droparrays, "iiN"_s, '\0'), + BUILTIN(summon, "Mxyssmii?"_s, '\0'), BUILTIN(monster, "Mxysmi?"_s, '\0'), BUILTIN(areamonster, "Mxyxysmi?"_s, '\0'), BUILTIN(killmonster, "ME"_s, '\0'), diff --git a/src/map/script-fun.hpp b/src/map/script-fun.hpp index 81d68fe..61feb17 100644 --- a/src/map/script-fun.hpp +++ b/src/map/script-fun.hpp @@ -20,6 +20,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. +#include "script-fun.t.hpp" + #include "fwd.hpp" #include "../strings/literal.hpp" diff --git a/src/map/script-fun.t.hpp b/src/map/script-fun.t.hpp new file mode 100644 index 0000000..f08925c --- /dev/null +++ b/src/map/script-fun.t.hpp @@ -0,0 +1,96 @@ +#pragma once +// script-call.t.hpp - EAthena script frontend, engine, and library. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include "fwd.hpp" + +namespace tmwa +{ +namespace map +{ +enum class MobInfo : uint8_t +{ + ID = 0, + ENG_NAME = 1, + JAP_NAME = 2, + LVL = 3, + HP = 4, + SP = 5, + BASE_EXP = 6, + JOB_EXP = 7, + RANGE1 = 8, + ATK1 = 9, + ATK2 = 10, + DEF = 11, + MDEF = 12, + STR = 13, + AGI = 14, + VIT = 15, + INT = 16, + DEX = 17, + LUK = 18, + RANGE2 = 19, + RANGE3 = 20, + SCALE = 21, + RACE = 22, + ELEMENT = 23, + ELEMENT_LVL = 24, + MODE = 25, + SPEED = 26, + ADELAY = 27, + AMOTION = 28, + DMOTION = 29, + MUTATION_NUM = 30, + MUTATION_POWER = 31, + DROPID1 = 32, + DROPNAME1 = 33, + DROPPERCENT1 = 34, + DROPID2 = 35, + DROPNAME2 = 36, + DROPPERCENT2 = 37, + DROPID3 = 38, + DROPNAME3 = 39, + DROPPERCENT3 = 40, + DROPID4 = 41, + DROPNAME4 = 42, + DROPPERCENT4 = 43, + DROPID5 = 44, + DROPNAME5 = 45, + DROPPERCENT5 = 46, + DROPID6 = 47, + DROPNAME6 = 48, + DROPPERCENT6 = 49, + DROPID7 = 50, + DROPNAME7 = 51, + DROPPERCENT7 = 52, + DROPID8 = 53, + DROPNAME8 = 54, + DROPPERCENT8 = 55, +}; + +enum class MobInfo_DropArrays : uint8_t +{ + IDS = 0, + NAMES = 1, + PERCENTS = 2, +}; +} // namespace map +} // namespace tmwa diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 4207b93..4182f5a 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -662,11 +662,13 @@ int skill_castcancel(dumb_ptr<block_list> bl, int) /*---------------------------------------------------------------------------- * ステータス異常 + * Status anomalies *---------------------------------------------------------------------------- */ /*========================================== * ステータス異常終了 + * Abnormal end of status *------------------------------------------ */ int skill_status_change_active(dumb_ptr<block_list> bl, StatusChange type) @@ -732,26 +734,32 @@ void skill_status_change_end(dumb_ptr<block_list> bl, StatusChange type, TimerDa assert (!sc_data[type].timer); switch (type) - { /* 異常の種類ごとの処理 */ - case StatusChange::SC_SPEEDPOTION0: /* 増速ポーション */ + { /* 異常の種類ごとの処理 | Processing by type of anomaly */ + case StatusChange::SC_SPEEDPOTION0: /* 増速ポーション | Speed Increasing Potion */ case StatusChange::SC_ATKPOT: /* attack potion [Valaris] */ case StatusChange::SC_MATKPOT: /* magic attack potion [Valaris] */ case StatusChange::SC_PHYS_SHIELD: case StatusChange::SC_HASTE: + calc_flag = 1; + break; + case StatusChange::SC_COOLDOWN: case StatusChange::SC_COOLDOWN_MG: case StatusChange::SC_COOLDOWN_MT: - calc_flag = 1; + case StatusChange::SC_COOLDOWN_R: + case StatusChange::SC_COOLDOWN_AR: + case StatusChange::SC_COOLDOWN_ENCH: + case StatusChange::SC_COOLDOWN_KOY: break; /* option2 */ - case StatusChange::SC_POISON: /* 毒 */ + case StatusChange::SC_POISON: /* 毒 | poison */ calc_flag = 1; break; } if (bl->bl_type == BL::PC && type < StatusChange::SC_SENDMAX) - clif_status_change(bl, type, 0); /* アイコン消去 */ + clif_status_change(bl, type, 0); /* アイコン消去 | Icon Clearing */ switch (type) { @@ -778,11 +786,11 @@ void skill_status_change_end(dumb_ptr<block_list> bl, StatusChange type, TimerDa break; } - if (opt_flag) /* optionの変更を伝える */ + if (opt_flag) /* optionの変更を伝える | Communicate option changes */ clif_changeoption(bl); if (bl->bl_type == BL::PC && calc_flag) - pc_calcstatus(bl->is_player(), 0); /* ステータス再計算 */ + pc_calcstatus(bl->is_player(), 0); /* ステータス再計算 | Status Recalculation */ } int skill_update_heal_animation(dumb_ptr<map_session_data> sd) @@ -806,6 +814,7 @@ int skill_update_heal_animation(dumb_ptr<map_session_data> sd) /*========================================== * ステータス異常終了タイマー + * Status abnormal end timer *------------------------------------------ */ void skill_status_change_timer(TimerData *tid, tick_t tick, BlockId id, StatusChange type) @@ -816,7 +825,7 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, BlockId id, StatusCh if ((bl = map_id2bl(id)) == nullptr) return; - //該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる + // 該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる | It seems that the corresponding ID has already disappeared, so let's go through it sc_data = battle_get_sc_data(bl); if (not sc_data) return; @@ -870,7 +879,7 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, BlockId id, StatusCh // If you manually reschedule the timer, you MUST skip the // call to skill_status_change_end below. - /* 時間切れ無し?? */ + /* 時間切れ無し?? | No time out? ? */ case StatusChange::SC_WEIGHT50: case StatusChange::SC_WEIGHT90: sc_data[type].timer = Timer(tick + 10_min, @@ -889,6 +898,7 @@ void skill_status_change_timer(TimerData *tid, tick_t tick, BlockId id, StatusCh /*========================================== * ステータス異常開始 + * Abnormal status start *------------------------------------------ */ int skill_status_change_start(dumb_ptr<block_list> bl, StatusChange type, @@ -948,7 +958,7 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, } if (sc_data[type].timer) - { /* すでに同じ異常になっている場合タイマ解除 */ + { /* すでに同じ異常になっている場合タイマ解除 | Cancel the timer if the same error has already occurred */ if (sc_data[type].val1 > val1 && type != StatusChange::SC_SPEEDPOTION0 && type != StatusChange::SC_ATKPOT @@ -957,7 +967,7 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, if (type == StatusChange::SC_POISON) return 0; - /* 継ぎ足しができない状態異常である時は状態異常を行わない */ + /* 継ぎ足しができない状態異常である時は状態異常を行わない | If the status ailment cannot be replenished, the status ailment will not be applied. */ { sc_data[type].timer.cancel(); } @@ -965,13 +975,13 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, switch (type) { - /* 異常の種類ごとの処理 */ + /* 異常の種類ごとの処理 | Actions by type of anomaly */ case StatusChange::SC_SLOWPOISON: if (!sc_data[StatusChange::SC_POISON].timer) return 0; break; - case StatusChange::SC_SPEEDPOTION0: /* 増速ポーション */ + case StatusChange::SC_SPEEDPOTION0: /* 増速ポーション | speed boost potion */ *opt2 |= Opt2::_speedpotion0; calc_flag = 1; // val2 = 5*(2+type-StatusChange::SC_SPEEDPOTION0); @@ -986,7 +996,7 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, break; /* option2 */ - case StatusChange::SC_POISON: /* 毒 */ + case StatusChange::SC_POISON: /* 毒 | poison */ calc_flag = 1; { int sc_def = @@ -1006,13 +1016,17 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, case StatusChange::SC_HASTE: case StatusChange::SC_PHYS_SHIELD: case StatusChange::SC_MBARRIER: - case StatusChange::SC_COOLDOWN: - case StatusChange::SC_COOLDOWN_MG: - case StatusChange::SC_COOLDOWN_MT: calc_flag = 1; break; case StatusChange::SC_HALT_REGENERATE: case StatusChange::SC_HIDE: + case StatusChange::SC_COOLDOWN: + case StatusChange::SC_COOLDOWN_MG: + case StatusChange::SC_COOLDOWN_MT: + case StatusChange::SC_COOLDOWN_R: + case StatusChange::SC_COOLDOWN_AR: + case StatusChange::SC_COOLDOWN_ENCH: + case StatusChange::SC_COOLDOWN_KOY: break; case StatusChange::SC_FLYING_BACKPACK: updateflag = SP::WEIGHT; @@ -1024,9 +1038,9 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, } if (bl->bl_type == BL::PC && type < StatusChange::SC_SENDMAX) - clif_status_change(bl, type, 1); /* アイコン表示 */ + clif_status_change(bl, type, 1); /* アイコン表示 | Icon display */ - /* optionの変更 */ + /* optionの変更 | Changing an Option */ switch (type) { case StatusChange::SC_POISON: @@ -1044,27 +1058,28 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, break; } - if (opt_flag) /* optionの変更 */ + if (opt_flag) /* optionの変更 | Changing an Option */ clif_changeoption(bl); sc_data[type].val1 = val1; - /* タイマー設定 */ + /* タイマー設定 | timer setting */ sc_data[type].timer = Timer(gettick() + tick, std::bind(skill_status_change_timer, ph::_1, ph::_2, bl->bl_id, type)); if (bl->bl_type == BL::PC && calc_flag) - pc_calcstatus(sd, 0); /* ステータス再計算 */ + pc_calcstatus(sd, 0); /* ステータス再計算 | Status recalculation */ if (bl->bl_type == BL::PC && updateflag != SP::ZERO) - clif_updatestatus(sd, updateflag); /* ステータスをクライアントに送る */ + clif_updatestatus(sd, updateflag); /* ステータスをクライアントに送る | Send status to client */ return 0; } /*========================================== * ステータス異常全解除 + * Remove all status abnormalities *------------------------------------------ */ int skill_status_change_clear(dumb_ptr<block_list> bl, int type) diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp index 4d9a766..1509852 100644 --- a/src/mmo/skill.t.hpp +++ b/src/mmo/skill.t.hpp @@ -55,6 +55,10 @@ enum class StatusChange : uint16_t SC_COOLDOWN = 71, // Spell cooldown SC_COOLDOWN_MG = 72, // Mana Guardian cooldown SC_COOLDOWN_MT = 73, // Mana Tyrant cooldown + SC_COOLDOWN_R = 74, // Kaflosh cooldown + SC_COOLDOWN_AR = 75, // Frillyar cooldown + SC_COOLDOWN_ENCH = 76, // Enchanter cooldown + SC_COOLDOWN_KOY = 77, // Koyntety cooldown SC_POISON = 132, // bad; actually used |