summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoraK-FDF <horak-fdf@web.de>2022-11-11 18:05:41 +0100
committerHoraK-FDF <horak-fdf@web.de>2022-11-11 18:05:41 +0100
commitf8292b7c0c706223694edcbeab1097baa2127168 (patch)
treedf9ec65b182a8f662c945d2c7f12da60c60d4fe6
parent9a3566484f2345db599552a6c18311978a0071ea (diff)
downloadtmwa-f8292b7c0c706223694edcbeab1097baa2127168.tar.gz
tmwa-f8292b7c0c706223694edcbeab1097baa2127168.tar.bz2
tmwa-f8292b7c0c706223694edcbeab1097baa2127168.tar.xz
tmwa-f8292b7c0c706223694edcbeab1097baa2127168.zip
mobinfo
-rw-r--r--src/map/atcommand.cpp209
-rw-r--r--src/map/clif.cpp4
-rw-r--r--src/map/globals.cpp2
-rw-r--r--src/map/globals.hpp3
-rw-r--r--src/map/mob.cpp7
-rw-r--r--src/map/mob.hpp6
-rw-r--r--src/map/script-fun.cpp385
-rw-r--r--src/map/script-fun.hpp2
-rw-r--r--src/map/script-fun.t.hpp96
-rw-r--r--src/map/skill.cpp61
-rw-r--r--src/mmo/skill.t.hpp4
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