summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/clif.cpp89
-rw-r--r--src/map/clif.hpp1
-rw-r--r--src/map/map.hpp11
-rw-r--r--src/map/pc.cpp33
-rw-r--r--src/map/script-fun.cpp4
5 files changed, 137 insertions, 1 deletions
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index a2f3b3a..7d5ff59 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -35,6 +35,8 @@
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
+#include "../generic/random.hpp"
+
#include "../io/cxxstdio.hpp"
#include "../io/extract.hpp"
#include "../io/write.hpp"
@@ -612,6 +614,13 @@ int clif_clearchar(dumb_ptr<block_list> bl, BeingRemoveWhy type)
type == BeingRemoveWhy::DEAD ? SendWho::AREA : SendWho::AREA_WOS);
}
+ if (bl->bl_type == BL::PC)
+ {
+ dumb_ptr<map_session_data> sd = bl->is_player();
+ if (sd->automod == AutoMod::autoblock)
+ clif_gm_collision(sd, 0);
+ }
+
return 0;
}
@@ -2499,6 +2508,9 @@ void clif_getareachar_pc(dumb_ptr<map_session_data> sd,
clif_changelook_accessories(sd, dstsd);
clif_changelook_accessories(dstsd, sd);
+
+ if (dstsd->automod == AutoMod::autoblock && pc_issit(dstsd))
+ clif_update_collision(sd, dstsd->bl_x, dstsd->bl_y, dstsd->bl_x, dstsd->bl_y, dstsd->bl_m->name_, 5); // BlockType::PLAYERWALL
}
/*==========================================
@@ -2759,6 +2771,9 @@ void clif_pcoutsight(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> sd)
{
clif_clearchar_id(dstsd->bl_id, BeingRemoveWhy::GONE, sd->sess);
clif_clearchar_id(sd->bl_id, BeingRemoveWhy::GONE, dstsd->sess);
+
+ if (dstsd->automod == AutoMod::autoblock)
+ clif_update_collision(sd, dstsd->bl_x, dstsd->bl_y, dstsd->bl_x, dstsd->bl_y, dstsd->bl_m->name_, 0);
}
break;
case BL::NPC:
@@ -3369,6 +3384,61 @@ void clif_sitting(Session *, dumb_ptr<map_session_data> sd)
fixed_8a.damage_type = DamageType::SIT;
Buffer buf = create_fpacket<0x008a, 29>(fixed_8a);
clif_send(buf, sd, SendWho::AREA);
+
+ if (sd->automod == AutoMod::autoblock)
+ clif_gm_collision(sd, 5);
+
+ // Prsm-sitting countermeasures
+ dumb_ptr<block_list> d_bl = sd->bl_m->blocks.ref(sd->bl_x / BLOCK_SIZE, sd->bl_y / BLOCK_SIZE).normal;
+ for (; d_bl; d_bl = d_bl->bl_next)
+ {
+ if (d_bl->bl_type == BL::PC && d_bl->bl_x == sd->bl_x && d_bl->bl_y == sd->bl_y && d_bl->bl_id != sd->bl_id)
+ {
+ dumb_ptr<map_session_data> d_sd = d_bl->is_player();
+
+ switch (d_sd->automod)
+ {
+ case AutoMod::autoblock:
+ // at this point, this should be impossible, so fallback to kill
+ case AutoMod::autokill:
+ pc_damage(nullptr, sd, sd->status.hp);
+ clif_displaymessage(sd->sess, "The holy messenger has given judgement."_s);
+ // now fallthrough to move
+ case AutoMod::automove:
+ {
+ unsigned short x0 = std::max(0, sd->bl_x - 5),
+ y0 = std::max(0, sd->bl_y - 5),
+ x1 = std::min(sd->bl_m->xs, (short)(sd->bl_x + 5)),
+ y1 = std::min(sd->bl_m->ys, (short)(sd->bl_y + 5));
+ unsigned short x = x0,
+ y = y0;
+
+ for (unsigned short i = 0; i < 1000; i++)
+ {
+ x = random_::in(x0, x1);
+ y = random_::in(y0, y1);
+
+ if (!bool(map_getcell(sd->bl_m, x, y) & MapCell::UNWALKABLE))
+ break;
+ }
+ pc_setpos(sd, sd->bl_m->name_, x, y, BeingRemoveWhy::WARPED);
+
+ if (sd->status.hp > 0)
+ {
+ // we're still sitting
+ Packet_Fixed<0x008a> fixed_8a_2;
+ fixed_8a_2.src_id = sd->bl_id;
+ fixed_8a_2.damage_type = DamageType::SIT;
+ Buffer buf2 = create_fpacket<0x008a, 29>(fixed_8a_2);
+ clif_send(buf2, sd, SendWho::SELF);
+ }
+ }
+ break;
+ case AutoMod::autokick:
+ clif_GM_kick(d_sd, sd, 1);
+ }
+ }
+ }
}
static
@@ -4075,6 +4145,25 @@ void clif_remote_command(dumb_ptr<map_session_data> sd, XString cmd)
clif_send(buf, sd, SendWho::SELF, wrap<ClientVersion>(6));
}
+void clif_gm_collision(dumb_ptr<map_session_data> sd, int mask)
+{
+ nullpo_retv(sd);
+
+ VString<15> gat_name = STRPRINTF("%s.gat"_fmt, sd->bl_m->name_);
+
+ Packet_Fixed<0x0231> fixed_231;
+ fixed_231.x1 = sd->bl_x;
+ fixed_231.y1 = sd->bl_y;
+ fixed_231.x2 = sd->bl_x;
+ fixed_231.y2 = sd->bl_y;
+ fixed_231.mask = mask;
+ fixed_231.unused_layer = 0;
+ fixed_231.map = gat_name;
+ Buffer buf = create_fpacket<0x0231, 34>(fixed_231);
+
+ clif_send(buf, sd, SendWho::AREA_WOS, wrap<ClientVersion>(7));
+}
+
void clif_update_collision(dumb_ptr<map_session_data> sd, short x1, short y1,
short x2, short y2, MapName map_name, int mask)
{
diff --git a/src/map/clif.hpp b/src/map/clif.hpp
index 1abcfe3..99baea8 100644
--- a/src/map/clif.hpp
+++ b/src/map/clif.hpp
@@ -108,6 +108,7 @@ void clif_npc_send_title(Session *s, BlockId npcid, XString msg);
void clif_server_message(dumb_ptr<map_session_data>, uint8_t, XString msg);
void clif_remote_command(dumb_ptr<map_session_data>, XString);
void clif_update_collision(dumb_ptr<map_session_data>, short, short, short, short, MapName, int);
+void clif_gm_collision(dumb_ptr<map_session_data>, int);
void clif_change_music(dumb_ptr<map_session_data> sd, XString music);
void clif_npc_action(dumb_ptr<map_session_data>, BlockId, short, int, short, short);
void clif_send_mask(dumb_ptr<map_session_data>, int);
diff --git a/src/map/map.hpp b/src/map/map.hpp
index 60b3462..eddbfad 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -121,6 +121,15 @@ struct quick_regeneration
unsigned char tickdelay; // number of ticks to next update
};
+enum class AutoMod
+{
+ off = 0,
+ autokill,
+ automove,
+ autoblock,
+ autokick,
+};
+
struct map_session_data : block_list, SessionData
{
struct
@@ -298,6 +307,8 @@ struct map_session_data : block_list, SessionData
unsigned guild:1;
} mute;
+ AutoMod automod;
+
tick_t flood_rates[0x220];
tick_t packet_flood_reset_due;
int packet_flood_in;
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index 3986113..b9b41d9 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -833,6 +833,8 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version,
sd->mute.whisper = 0;
sd->mute.guild = 0;
+ sd->automod = AutoMod::off;
+
for (tick_t& t : sd->flood_rates)
t = tick_t();
sd->packet_flood_reset_due = tick_t();
@@ -2414,6 +2416,27 @@ void pc_walk(TimerData *, tick_t tick, BlockId id, unsigned char data)
return;
}
+ // Prsm-sitting countermeasures
+ dumb_ptr<block_list> d_bl = sd->bl_m->blocks.ref((x + dx) / BLOCK_SIZE, (y + dy) / BLOCK_SIZE).normal;
+ for (; d_bl; d_bl = d_bl->bl_next)
+ {
+ if (d_bl->bl_type == BL::PC && d_bl->bl_x == (x + dx) && d_bl->bl_y == (y + dy))
+ {
+ dumb_ptr<map_session_data> d_sd = d_bl->is_player();
+
+ if (pc_issit(d_sd))
+ {
+ switch (d_sd->automod)
+ {
+ case AutoMod::autoblock:
+ clif_update_collision(sd, x + dx, y + dy, x + dx, y + dy, sd->bl_m->name_, 5); // BlockType::PLAYERWALL
+ pc_stop_walking(sd, 1);
+ return;
+ }
+ }
+ }
+ }
+
moveblock = (x / BLOCK_SIZE != (x + dx) / BLOCK_SIZE
|| y / BLOCK_SIZE != (y + dy) / BLOCK_SIZE);
@@ -3571,6 +3594,9 @@ int pc_readparam(dumb_ptr<block_list> bl, SP type)
case SP::MUTE_GUILD:
val = sd ? sd->mute.guild : 0;
break;
+ case SP::AUTOMOD:
+ val = sd ? (int)sd->automod : 0;
+ break;
}
return val;
@@ -3816,6 +3842,10 @@ int pc_setparam(dumb_ptr<block_list> bl, SP type, int val)
nullpo_retz(sd);
sd->mute.guild = (val == 1);
break;
+ case SP::AUTOMOD:
+ nullpo_retz(sd);
+ sd->automod = (AutoMod)val;
+ break;
}
return 0;
@@ -5205,6 +5235,9 @@ void pc_setstand(dumb_ptr<map_session_data> sd)
nullpo_retv(sd);
sd->state.dead_sit = 0;
+
+ if (sd->automod == AutoMod::autoblock)
+ clif_gm_collision(sd, 0);
}
static
diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp
index ab60535..8c90052 100644
--- a/src/map/script-fun.cpp
+++ b/src/map/script-fun.cpp
@@ -4637,7 +4637,9 @@ void builtin_getmap(ScriptState *st)
else
sd = script_rid2sd(st);
- nullpo_retv(sd);
+ if (!sd || !as_raw_pointer(Some(sd->bl_m)) || sd->bl_m == borrow(undefined_gat))
+ return;
+
push_str<ScriptDataStr>(st->stack, sd->bl_m->name_);
}