diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.cpp | 212 | ||||
-rw-r--r-- | src/map/globals.cpp | 2 | ||||
-rw-r--r-- | src/map/globals.hpp | 3 | ||||
-rw-r--r-- | src/map/mob.cpp | 8 | ||||
-rw-r--r-- | src/map/mob.hpp | 6 | ||||
-rw-r--r-- | src/map/script-fun.cpp | 441 | ||||
-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 | 4 |
9 files changed, 719 insertions, 55 deletions
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 459672d..b4faed5 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1822,6 +1822,172 @@ 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); + else + mob_id = mobdb_checkid(mob_id); + + 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 +4718,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 +5454,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, + 20, 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 +5712,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/globals.cpp b/src/map/globals.cpp index 97533c8..d2c1993 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[MaxMobID+1]; 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..2fcdd95 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[MaxMobID+1]; 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..0f273a8 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -115,7 +115,7 @@ Species mobdb_searchname(MobName str) Species mobdb_checkid(Species id) { // value range is [1001, 2000] - if (wrap<Species>(1000) < id && id < wrap<Species>(2001)) + if (wrap<Species>(MinMobID-1) < id && id < wrap<Species>(MaxMobID+1)) return id; return Species(); } @@ -2647,7 +2647,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 +3439,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 +3577,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..47da095 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -43,6 +43,10 @@ namespace map #define JAPANESE_NAME stringish<MobName>("--ja--"_s) #define MOB_THIS_MAP stringish<MapName>("this"_s) +#define MaxDrops 8 +#define MinMobID 1001 +#define MaxMobID 2000 + struct mob_skill { MobSkillState state; @@ -79,7 +83,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] diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index bcb5a45..58646bc 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -2624,6 +2624,423 @@ void builtin_getexp(ScriptState *st) } /*========================================== + * Returns attributes of a monster + * return value -1 = mob not found + *------------------------------------------ + */ +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 + + if (mobdb_checkid(mob_id) == Species()) + { + push_int<ScriptDataInt>(st->stack, -1); + return; + } + + 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); + push_int<ScriptDataInt>(st->stack, -1); + return; + break; + } + if (!mode) + push_int<ScriptDataInt>(st->stack, info); + else + push_str<ScriptDataStr>(st->stack, info_str); +} + +/*========================================== + * Returns drops of a monster to an array + * return values: + * 0 = mob not found or error + * 1 = mob found and has drops + * 2 = mob found and has no drops + *------------------------------------------ + */ +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(); + + int status = 0; // 0 = mob not found or error, 1 = mob found and has drops, 2 = mob found and has no drops + + if (prefix != '$' && prefix != '@' && prefix != '.') + { + PRINTF("builtin_mobinfo_droparrays: illegal scope!\n"_fmt); + push_int<ScriptDataInt>(st->stack, 0); + 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); + push_int<ScriptDataInt>(st->stack, 0); + return; + } + break; + case MobInfo_DropArrays::NAMES: + if (postfix != '$') + { + PRINTF("builtin_mobinfo_droparrays: wrong array type for Names (String expected but Int found)!\n"_fmt); + push_int<ScriptDataInt>(st->stack, 0); + return; + } + break; + case MobInfo_DropArrays::PERCENTS: + if (postfix == '$') + { + PRINTF("builtin_mobinfo_droparrays: wrong array type for Percents (Int expected but String found)!\n"_fmt); + push_int<ScriptDataInt>(st->stack, 0); + return; + } + break; + default: + PRINTF("builtin_mobinfo_droparrays: unknown request\n"_fmt); + push_int<ScriptDataInt>(st->stack, 0); + return; + break; + } + + if (mobdb_checkid(mob_id) == Species()) + { + push_int<ScriptDataInt>(st->stack, status); + return; + } + + for (int i = 0; i < MaxDrops; ++i) + if (get_mob_db(mob_id).dropitem[i].nameid) + { + status = 1; + 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 + { + if (i == 0) + status = 2; + break; + } + + push_int<ScriptDataInt>(st->stack, status); +} + +/*========================================== + * Returns drops of a monster to standardized arrays + * return values: + * 0 = mob not found + * 1 = mob found and has drops + * 2 = mob found and has no drops + *------------------------------------------ + */ +static +void builtin_getmobdrops(ScriptState *st) +{ + dumb_ptr<block_list> bl = nullptr; + + Species mob_id = wrap<Species>(conv_num(st, &AARG(0))); + + int status = 0; // 0 = mob not found, 1 = mob found and has drops, 2 = mob found and has no drops + int i = 0; + + if (mobdb_checkid(mob_id) == Species()) + { + push_int<ScriptDataInt>(st->stack, status); + return; + } + + status = 1; + + for (; i < MaxDrops; ++i) + if (get_mob_db(mob_id).dropitem[i].nameid) + { + set_reg(bl, VariableCode::VARIABLE, SIR::from(variable_names.intern("$@MobDrop_item"_s), i), get_mob_db(mob_id).dropitem[i].p.num); + + 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)); + set_reg(bl, VariableCode::VARIABLE, SIR::from(variable_names.intern("$@MobDrop_name$"_s), i), item_name); + + set_reg(bl, VariableCode::VARIABLE, SIR::from(variable_names.intern("$@MobDrop_rate"_s), i), get_mob_db(mob_id).dropitem[i].p.num); + } + else + { + if (i == 0) + status = 2; + break; + } + + if (status == 1) + set_reg(bl, VariableCode::VARIABLE, SIR::from(variable_names.intern("$@MobDrop_count"_s), 0), i); + else + set_reg(bl, VariableCode::VARIABLE, SIR::from(variable_names.intern("$@MobDrop_count"_s), 0), 0); + + push_int<ScriptDataInt>(st->stack, status); +} + +/*========================================== * *------------------------------------------ */ @@ -2636,11 +3053,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 +3070,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) @@ -3157,9 +3577,9 @@ void builtin_getusers(ScriptState *st) int val = 0; switch (flag & 0x07) { - /*case 0: + case 0: val = bl->bl_m->users; - break;*/ + break; case 1: val = map_getusers(); break; @@ -3404,6 +3824,8 @@ void builtin_sc_start(ScriptState *st) 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: @@ -5129,7 +5551,10 @@ 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, 'i'), + BUILTIN(getmobdrops, "i"_s, 'i'), + 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..d0c753b --- /dev/null +++ b/src/map/script-fun.t.hpp @@ -0,0 +1,96 @@ +#pragma once +// script-fun.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 b90207f..4182f5a 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -748,6 +748,8 @@ void skill_status_change_end(dumb_ptr<block_list> bl, StatusChange type, TimerDa 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; /* option2 */ @@ -1023,6 +1025,8 @@ int skill_status_effect(dumb_ptr<block_list> bl, StatusChange type, 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; |