summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/atcommand.cpp212
-rw-r--r--src/map/globals.cpp2
-rw-r--r--src/map/globals.hpp3
-rw-r--r--src/map/mob.cpp8
-rw-r--r--src/map/mob.hpp6
-rw-r--r--src/map/script-fun.cpp441
-rw-r--r--src/map/script-fun.hpp2
-rw-r--r--src/map/script-fun.t.hpp96
-rw-r--r--src/map/skill.cpp4
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;