summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgumi <git@gumi.ca>2019-08-23 14:06:56 -0400
committergumi <git@gumi.ca>2019-08-23 14:11:00 -0400
commit93595818978b50428c311d5ba20f2b8f102b6a4b (patch)
treec048e007dfb7bf2f82f4341ed16ba783240a0dd5
parente1c1b70df9d58223aa8d0ed851ee7179832ce662 (diff)
downloadtmwa-93595818978b50428c311d5ba20f2b8f102b6a4b.tar.gz
tmwa-93595818978b50428c311d5ba20f2b8f102b6a4b.tar.bz2
tmwa-93595818978b50428c311d5ba20f2b8f102b6a4b.tar.xz
tmwa-93595818978b50428c311d5ba20f2b8f102b6a4b.zip
allow to summon multiple mobs with @summon
-rw-r--r--src/map/atcommand.cpp84
-rw-r--r--src/map/battle.cpp4
-rw-r--r--src/map/map.hpp3
-rw-r--r--src/map/mob.cpp29
-rw-r--r--src/map/skill.cpp2
5 files changed, 86 insertions, 36 deletions
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index a9774f0..868daa6 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -4523,37 +4523,81 @@ ATCE atcommand_leaves(Session *, dumb_ptr<map_session_data> sd,
}
static
-ATCE atcommand_summon(Session *, dumb_ptr<map_session_data> sd,
+ATCE atcommand_summon(Session *s, dumb_ptr<map_session_data> sd,
ZString message)
{
MobName name;
Species mob_id;
- int x = 0;
- int y = 0;
- tick_t tick = gettick();
+ int number = 0;
+ int minutes = 0;
- if (!extract(message, &name) || !name)
+ if (!extract(message, record<' ', 1>(&name, &number, &minutes)))
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 = mobdb_searchname(name)) == Species())
+ mob_id = mobdb_checkid(wrap<Species>(atoi(name.c_str())));
+
if (mob_id == Species())
return ATCE::EXIST;
- x = sd->bl_x + random_::in(-5, 4);
- y = sd->bl_y + random_::in(-5, 4);
+ if (number <= 0)
+ number = 1;
+
+ if (minutes <= 0)
+ minutes = 10;
+
+ if (battle_config.atcommand_spawn_quantity_limit >= 1
+ && number > battle_config.atcommand_spawn_quantity_limit)
+ number = battle_config.atcommand_spawn_quantity_limit;
+
+ int count = 0;
+ int range = (sqrt(number) / 2) * 2 + 5;
+
+ for (int i = 0; i < number; i++)
+ {
+ int j = 0;
+ BlockId k;
+
+ while (j++ < 8 && !k)
+ {
+ // try 8 times to spawn the monster (needed for close area)
+ int mx = sd->bl_x + random_::in(-range / 2, range / 2 );
+ int my = sd->bl_y + random_::in(-range / 2, range / 2);
+ k = mob_once_spawn(sd, MOB_THIS_MAP, mx, my, MobName(), mob_id, 1, NpcEvent());
+ }
+
+ if (k)
+ {
+ dumb_ptr<mob_data> md = map_id_is_mob(k);
+ tick_t tick = gettick();
+
+ 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 + (std::max(minutes, 120) * 1_min),
+ std::bind(mob_timer_delete, ph::_1, ph::_2,
+ k));
+ count++;
+ }
+ }
- 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)
+ if (count != 0)
{
- 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);
+ if (number == count)
+ {
+ clif_displaymessage(s, "All monster summoned!"_s);
+ }
+ else
+ {
+ AString output = STRPRINTF("%d monster(s) summoned!"_fmt,
+ count);
+ clif_displaymessage(s, output);
+ }
+ }
+ else
+ {
+ clif_displaymessage(s, "Invalid monster ID or name."_s);
+ return ATCE::EXIST;
}
return ATCE::OKAY;
@@ -5548,7 +5592,7 @@ Map<XString, AtCommandInfo> atcommand_info =
{"leaves"_s, {""_s,
98, atcommand_leaves,
"Enable the leaves mapflag"_s}},
- {"summon"_s, {"<mob-id-or-name>"_s,
+ {"summon"_s, {"<mob-id-or-name> [count] [minutes]"_s,
50, atcommand_summon,
"Summon a slave monster temporarily"_s}},
{"adjgmlvl"_s, {"<level> <charname>"_s,
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index df01a5c..a4596e9 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -2070,9 +2070,9 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target,
if (src->bl_type == BL::MOB)
{
dumb_ptr<mob_data> md = src->is_mob();
- if (md && md->master_id)
+ if (md && (md->master_id || md->parent_id))
{
- if (md->master_id == target->bl_id) // 主なら肯定
+ if (md->master_id == target->bl_id || md->parent_id == target->bl_id) // 主なら肯定
return 1;
if (md->state.special_mob_ai)
{
diff --git a/src/map/map.hpp b/src/map/map.hpp
index eddbfad..42ca151 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -482,7 +482,8 @@ struct mob_data : block_list
struct mob_skill *skillidx;
std::unique_ptr<tick_t[]> skilldelayup; // [MAX_MOBSKILL];
LevelElement def_ele;
- BlockId master_id;
+ BlockId parent_id; // monster that spawned this mob
+ BlockId master_id; // player that owns the parent
BlockId last_master_id;
int master_dist;
int exclusion_src, exclusion_party;
diff --git a/src/map/mob.cpp b/src/map/mob.cpp
index 0da946a..1614fe5 100644
--- a/src/map/mob.cpp
+++ b/src/map/mob.cpp
@@ -1152,6 +1152,7 @@ int mob_spawn(BlockId id)
md->stats[mob_stat::SPEED] = get_mob_db(md->mob_class).speed.count();
md->def_ele = get_mob_db(md->mob_class).element;
md->master_id = BlockId();
+ md->parent_id = BlockId();
md->master_dist = 0;
md->state.state = MS::IDLE;
@@ -1573,13 +1574,13 @@ int mob_ai_sub_hard_slavemob(dumb_ptr<mob_data> md, tick_t tick)
nullpo_retz(md);
- if ((bl = map_id2bl(md->master_id)) != nullptr)
+ if ((bl = map_id2bl(md->parent_id)) != nullptr)
mmd = bl->is_mob();
mode = get_mob_db(md->mob_class).mode;
// It is not main monster/leader.
- if (!mmd || mmd->bl_type != BL::MOB || mmd->bl_id != md->master_id)
+ if (!mmd || mmd->bl_type != BL::MOB || mmd->bl_id != md->parent_id)
return 0;
// Since it is in the map on which the master is not, teleport is carried out and it pursues.
@@ -1861,6 +1862,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick)
if (((bl = map_id2bl(md->last_master_id)) != nullptr && md->bl_m != bl->bl_m) || (bl = map_id2bl(md->last_master_id)) == nullptr)
{
md->last_master_id = BlockId();
+ md->parent_id = BlockId();
md->state.special_mob_ai = 0;
md->mode = get_mob_db(md->mob_class).mode;
md->target_id = BlockId();
@@ -1868,7 +1870,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick)
}
}
// Processing of slave monster
- if (md->master_id && md->state.special_mob_ai == 0)
+ if (md->parent_id && md->state.special_mob_ai == 0)
mob_ai_sub_hard_slavemob(md, tick);
// アクティヴモンスターの策敵 (?? of a bitter taste TIVU monster)
@@ -2071,7 +2073,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick)
// mobs that are not slaves can random-walk
if (bool(mode & MobMode::CAN_MOVE)
&& mob_can_move(md)
- && (!md->master_id || md->state.special_mob_ai
+ && (!md->parent_id || md->state.special_mob_ai
|| md->master_dist > 10))
{
// if walktime is more than 7 seconds in the future,
@@ -2162,7 +2164,7 @@ void mob_ai_sub_lazy(dumb_ptr<block_list> bl, tick_t tick)
// MOB which is not not the summons MOB but BOSS, either sometimes reboils.
else if (random_::chance(MOB_LAZYWARPPERC)
&& md->spawn.x0 <= 0
- && md->master_id
+ && md->parent_id
&& !bool(get_mob_db(md->mob_class).mode & MobMode::BOSS))
mob_spawn(md->bl_id);
@@ -2174,7 +2176,7 @@ void mob_ai_sub_lazy(dumb_ptr<block_list> bl, tick_t tick)
// MOB which is not BOSS which is not Summons MOB, either -- a case -- sometimes -- leaping
if (random_::chance(MOB_LAZYWARPPERC)
&& md->spawn.x0 <= 0
- && md->master_id
+ && md->parent_id
&& !bool(get_mob_db(md->mob_class).mode & MobMode::BOSS))
mob_warp(md, nullptr, -1, -1, BeingRemoveWhy::NEGATIVE1);
}
@@ -2334,7 +2336,7 @@ void mob_deleteslave_sub(dumb_ptr<block_list> bl, BlockId id)
nullpo_retv(bl);
md = bl->is_mob();
- if (md->master_id && md->master_id == id)
+ if (md->parent_id && md->parent_id == id)
mob_damage(nullptr, md, md->hp, 1);
}
@@ -2381,6 +2383,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
{
/* If the master hits a monster, have the monster turn against him */
md->last_master_id = md->master_id;
+ //md->parent_id = BlockId();
md->master_id = BlockId();
md->mode = MobMode::war; /* Regular war mode */
md->target_id = src->bl_id;
@@ -2757,7 +2760,7 @@ void mob_warpslave_sub(dumb_ptr<block_list> bl, BlockId id, int x, int y)
{
dumb_ptr<mob_data> md = bl->is_mob();
- if (md->master_id == id)
+ if (md->parent_id == id)
{
mob_warp(md, nullptr, x, y, BeingRemoveWhy::QUIT);
}
@@ -2873,7 +2876,7 @@ void mob_countslave_sub(dumb_ptr<block_list> bl, BlockId id, int *c)
nullpo_retv(bl);
md = bl->is_mob();
- if (md->master_id == id)
+ if (md->parent_id == id)
(*c)++;
}
@@ -2969,8 +2972,10 @@ int mob_summonslave(dumb_ptr<mob_data> md2, int *value_, int amount, int flag)
map_addiddb(md);
mob_spawn(md->bl_id);
- if (flag)
- md->master_id = md2->bl_id;
+ if (flag) {
+ md->master_id = md2->master_id; // tell the subslave who actually owns them
+ md->parent_id = md2->bl_id; // tell the subslave who spawned them
+ }
}
}
return 0;
@@ -3292,7 +3297,7 @@ int mobskill_use(dumb_ptr<mob_data> md, tick_t tick,
if (battle_config.mob_skill_use == 0 || md->skilltimer)
return 0;
- if (md->state.special_mob_ai)
+ if (md->state.special_mob_ai && md->parent_id)
return 0;
for (mob_skill& msii : ms)
diff --git a/src/map/skill.cpp b/src/map/skill.cpp
index d9a7717..789dd8a 100644
--- a/src/map/skill.cpp
+++ b/src/map/skill.cpp
@@ -532,7 +532,7 @@ int skill_castend_nodamage_id(dumb_ptr<block_list> src, dumb_ptr<block_list> bl,
switch (skillid)
{
case SkillID::NPC_SUMMONSLAVE:
- if (md && !md->master_id)
+ if (md && !md->parent_id)
{
mob_summonslave(md,
md->skillidx->val,