Created
October 31, 2020 07:20
-
-
Save AnnieRuru/b6ed52d55baad1a587dc9eeff2902c99 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//===== Hercules Plugin ====================================== | |
//= cell_pvp | |
//===== By: ================================================== | |
//= AnnieRuru | |
//= based on [Ize] source code | |
//===== Current Version: ===================================== | |
//= 1.7 | |
//===== Compatible With: ===================================== | |
//= Hercules 2020-10-30 | |
//===== Description: ========================================= | |
//= create a custom zone for players to pvp | |
//===== Topic ================================================ | |
//= https://herc.ws/board/topic/19033-cell_pvp/ | |
//===== Additional Comments: ================================= | |
//= this plugin overload `@pvpoff` atcommand and `*pvpoff` script command | |
//= | |
//= -- AtCommands -- | |
//= @cell_pvp <x1> <y1> <x2> <y2> <respawn> <skillallow> <bonedrop> | |
//= @pvpoff | |
//= | |
//= -- Script Commands -- | |
//= *cell_pvp "<mapname>", <x1>, <y1>, <x2>, <y2>, <respawn>, <skillallow>, <bonedrop>; | |
//= <respawn> flag are: | |
//= CELL_PVP_RESPAWN_DISABLE | |
//= CELL_PVP_RESPAWN_INSTANT | |
//= CELL_PVP_RESPAWN_NORMAL | |
//= <skillallow> : disallow skill usage outside pvp zone. This will disallow receiving buffs from players outside PvP Zone | |
//= CELL_PVP_SKILL_DISALLOW | |
//= CELL_PVP_SKILL_ALLOW | |
//= <bonedrop> : drop player's name bone inside pvp zone when dead. This will always overwrite the `battle_config.bone_drop` value from conf\map\battle\player.conf | |
//= CELL_PVP_BONEDROP_NONE | |
//= CELL_PVP_BONEDROP_ALWAYS | |
//= | |
//= remember MF_PVP_NOPARTY and MF_PVP_NOGUILD mapflag | |
//============================================================ | |
#include "common/hercules.h" | |
#include "map/pc.h" | |
#include "map/map.h" | |
#include "map/battle.h" | |
#include "map/atcommand.h" | |
#include "common/timer.h" | |
#include "common/memmgr.h" | |
#include "common/nullpo.h" | |
#include "plugins/HPMHooking.h" | |
#include "common/HPMDataCheck.h" | |
HPExport struct hplugin_info pinfo = { | |
"cell_pvp", | |
SERVER_TYPE_MAP, | |
"1.7", | |
HPM_VERSION, | |
}; | |
enum cellpvp_respawn_flag { | |
CELL_PVP_RESPAWN_DISABLE, | |
CELL_PVP_RESPAWN_INSTANT, | |
CELL_PVP_RESPAWN_NORMAL, | |
}; | |
enum cellpvp_skillonoff_flag { | |
CELL_PVP_SKILL_DISALLOW, | |
CELL_PVP_SKILL_ALLOW, | |
}; | |
enum cellpvp_bonedrop_flag { | |
CELL_PVP_BONEDROP_NONE, | |
CELL_PVP_BONEDROP_ALWAYS, | |
}; | |
int bone_drop_value = 0; | |
int pvp_mapflag = 0; | |
struct player_data { | |
unsigned cellpvp_flag : 1; | |
}; | |
struct map_cellpvp_data { | |
unsigned map_cellpvp_flag : 1; | |
int x1; | |
int y1; | |
int x2; | |
int y2; | |
unsigned map_cellpvp_respawn : 2; | |
unsigned map_cellpvp_skillonoff : 1; | |
unsigned bonedrop : 1; | |
}; | |
void walkin_cellpvp(struct map_session_data *sd) { | |
nullpo_retv(sd); | |
// clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); | |
// clif->maptypeproperty2(&sd->bl, SELF); | |
if (sd->pvp_timer == INVALID_TIMER) { | |
// sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); | |
sd->pvp_rank = 0; | |
sd->pvp_lastusers = 0; | |
sd->pvp_point = 5; | |
sd->pvp_won = 0; | |
sd->pvp_lost = 0; | |
} | |
struct player_data *ssd = getFromMSD(sd, 0); | |
nullpo_retv(ssd); | |
ssd->cellpvp_flag = 1; | |
return; | |
} | |
void walkout_cellpvp(struct map_session_data *sd) { | |
nullpo_retv(sd); | |
// clif->map_property(sd, MAPPROPERTY_NOTHING); | |
// clif->maptypeproperty2(&sd->bl, SELF); | |
clif->pvpset(sd, 0, 0, 2); | |
if (sd->pvp_timer != INVALID_TIMER) { | |
timer->delete(sd->pvp_timer, pc->calc_pvprank_timer); | |
sd->pvp_timer = INVALID_TIMER; | |
} | |
struct player_data *ssd = getFromMSD(sd, 0); | |
nullpo_retv(ssd); | |
ssd->cellpvp_flag = 0; | |
return; | |
} | |
int buildin_cellpvp(struct block_list *bl, va_list ap) { | |
nullpo_ret(bl); | |
Assert_ret(bl->type == BL_PC); | |
struct map_session_data *sd = BL_CAST(BL_PC, bl); | |
nullpo_ret(sd); | |
walkin_cellpvp(sd); | |
return true; | |
} | |
static int pc_reg_received_post(int retVal, struct map_session_data *sd) { | |
if (retVal == 0 || sd == NULL) | |
return retVal; | |
struct player_data *ssd; | |
CREATE(ssd, struct player_data, true); | |
ssd->cellpvp_flag = 0; | |
addToMSD(sd, ssd, 0, true); | |
return 1; | |
} | |
void clif_parse_LoadEndAck_pre(int *fd, struct map_session_data **sd) { | |
if (*sd == NULL) | |
return; | |
if (pc_isinvisible(*sd)) | |
return; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[(*sd)->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return; | |
pvp_mapflag = map->list[(*sd)->bl.m].flag.pvp; | |
map->list[(*sd)->bl.m].flag.pvp = 0; | |
return; | |
} | |
void clif_parse_LoadEndAck_post(int fd, struct map_session_data *sd) { | |
if (sd == NULL) | |
return; | |
if (pc_isinvisible(sd)) | |
return; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return; | |
if (sd->bl.x < mf->x1 || sd->bl.y < mf->y1 || sd->bl.x > mf->x2 || sd->bl.y > mf->y2) | |
walkout_cellpvp(sd); | |
else | |
walkin_cellpvp(sd); | |
map->list[sd->bl.m].flag.pvp = pvp_mapflag; | |
pvp_mapflag = 0; | |
return; | |
} | |
static int pc_calc_pvprank_sub(struct block_list *bl, va_list ap) { | |
struct map_session_data *sd1 = NULL; | |
struct map_session_data *sd2 = va_arg(ap,struct map_session_data *); | |
int *count = va_arg(ap, int *); | |
nullpo_ret(bl); | |
Assert_ret(bl->type == BL_PC); | |
sd1 = BL_CAST(BL_PC, bl); | |
nullpo_ret(sd2); | |
if (pc_isinvisible(sd1) || pc_isinvisible(sd2)) | |
return 0; | |
if (sd1->pvp_point > sd2->pvp_point) | |
sd2->pvp_rank++; | |
(*count)++; | |
return 0; | |
} | |
static int pc_calc_pvprank_pre(struct map_session_data **sd) { | |
nullpo_ret(*sd); | |
int count = 0; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[(*sd)->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return (*sd)->pvp_rank; | |
int old = (*sd)->pvp_rank; | |
(*sd)->pvp_rank = 1; | |
map->foreachinarea(pc_calc_pvprank_sub, (*sd)->bl.m, mf->x1, mf->y1, mf->x2, mf->y2, BL_PC, *sd, &count); | |
if (old != (*sd)->pvp_rank || (*sd)->pvp_lastusers != count) | |
clif->pvpset(*sd, (*sd)->pvp_rank, (*sd)->pvp_lastusers = count, 0); | |
hookStop(); | |
return (*sd)->pvp_rank; | |
} | |
int pc_dead_pre(struct map_session_data **sd, struct block_list **src) { | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[(*sd)->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return 0; | |
if (mf->bonedrop == true && (*sd)->bl.x >= mf->x1 && (*sd)->bl.y >= mf->y1 && (*sd)->bl.x <= mf->x2 && (*sd)->bl.y <= mf->y2) | |
battle->bc->bone_drop = 1; | |
else | |
battle->bc->bone_drop = 0; | |
return 0; | |
} | |
static int pc_dead_post(int retVal, struct map_session_data *sd, struct block_list *src) { | |
if (sd == NULL) | |
return retVal; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return retVal; | |
battle->bc->bone_drop = bone_drop_value; | |
if (battle->bc->pk_mode != 0) { | |
sd->pvp_point -= 5; | |
sd->pvp_lost++; | |
if (src != NULL && src->type == BL_PC) { | |
struct map_session_data *ssd = BL_CAST(BL_PC, src); | |
ssd->pvp_point++; | |
ssd->pvp_won++; | |
} | |
if (mf->map_cellpvp_respawn == CELL_PVP_RESPAWN_NORMAL && sd->pvp_point < 0) { | |
timer->add(timer->gettick() + 1, pc->respawn_timer, sd->bl.id, 0); | |
return 1|8; | |
} | |
} | |
if (mf->map_cellpvp_respawn == CELL_PVP_RESPAWN_INSTANT) | |
timer->add(timer->gettick() + 1, pc->respawn_timer, sd->bl.id, 0); | |
return retVal; | |
} | |
static int pc_respawn_timer_pre(int *tid, int64 *tick, int *id, intptr_t *data) { | |
struct map_session_data *sd = map->id2sd(*id); | |
if (sd == NULL) | |
return 0; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return 0; | |
if (mf->map_cellpvp_respawn == CELL_PVP_RESPAWN_DISABLE) { | |
sd->pvp_point = 0; | |
hookStop(); | |
} | |
return 0; | |
} | |
// flush all cell_pvp data back to default upon @reloadscript | |
void map_flags_init_pre(void) { | |
for (int i = 0; i < map->count; ++i) { | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[i], 0); | |
if (mf != NULL) | |
removeFromMAPD(&map->list[i], 0); | |
} | |
return; | |
} | |
bool battle_config_read_post(bool retVal, const char *filename, bool imported) { | |
bone_drop_value = battle->bc->bone_drop; | |
return retVal; | |
} | |
static int battle_check_target_post(int retVal, struct block_list *src, struct block_list *target, int flag) { | |
if (src == NULL || target == NULL) | |
return retVal; | |
struct block_list *s_bl = src, *t_bl = target; | |
if ((t_bl = battle->get_master(target)) == NULL) | |
t_bl = target; | |
if ((s_bl = battle->get_master(src)) == NULL) | |
s_bl = src; | |
if (s_bl->type != BL_PC || t_bl->type != BL_PC) | |
return retVal; | |
struct map_session_data *sd = BL_CAST(BL_PC, s_bl), *tsd = BL_CAST(BL_PC, t_bl); | |
nullpo_ret(sd); | |
nullpo_ret(tsd); | |
if (retVal != 1) | |
return retVal; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return retVal; | |
if (sd->bl.x < mf->x1 || tsd->bl.x < mf->x1 || sd->bl.y < mf->y1 || tsd->bl.y < mf->y1 || sd->bl.x > mf->x2 || tsd->bl.x > mf->x2 || sd->bl.y > mf->y2 || tsd->bl.y > mf->y2) { | |
if (mf->map_cellpvp_skillonoff == CELL_PVP_SKILL_ALLOW && (flag & BCT_ENEMY) != 0) | |
return 0; | |
if (mf->map_cellpvp_skillonoff == CELL_PVP_SKILL_DISALLOW) | |
return 0; | |
} | |
return retVal; | |
} | |
static int skill_check_condition_castbeginend_post(int retVal, struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) { | |
if (sd == NULL || retVal == 0) | |
return 0; | |
if (((sd->auto_cast_current.itemskill_conditions_checked || !sd->auto_cast_current.itemskill_check_conditions) | |
&& sd->auto_cast_current.type == AUTOCAST_ITEM) || sd->auto_cast_current.type == AUTOCAST_IMPROVISE) { | |
return 1; | |
} | |
if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->auto_cast_current.type != AUTOCAST_ITEM) { | |
sd->state.arrow_atk = skill->get_ammotype(skill_id)? 1:0; | |
sd->spiritball_old = sd->spiritball; | |
return 1; | |
} | |
struct status_change *sc = &sd->sc; | |
if (!sc->count) | |
sc = NULL; | |
switch(skill_id) { // Turn off check. | |
case BS_MAXIMIZE: | |
case NV_TRICKDEAD: | |
case TF_HIDING: | |
case AS_CLOAKING: | |
case CR_AUTOGUARD: | |
case ML_AUTOGUARD: | |
case CR_DEFENDER: | |
case ML_DEFENDER: | |
case ST_CHASEWALK: | |
case PA_GOSPEL: | |
case CR_SHRINK: | |
case TK_RUN: | |
case GS_GATLINGFEVER: | |
case TK_READYCOUNTER: | |
case TK_READYDOWN: | |
case TK_READYSTORM: | |
case TK_READYTURN: | |
case SG_FUSION: | |
case RA_WUGDASH: | |
case KO_YAMIKUMO: | |
case SU_HIDE: | |
if (sc && sc->data[status->skill2sc(skill_id)]) | |
return 1; | |
default: | |
break; | |
} | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return retVal; | |
if (sd->bl.x < mf->x1 || sd->bl.y < mf->y1 || sd->bl.x > mf->x2 || sd->bl.y > mf->y2) { | |
if (mf->map_cellpvp_skillonoff == CELL_PVP_SKILL_DISALLOW) | |
return 0; | |
} | |
return retVal; | |
} | |
static int unit_walk_toxy_timer_post(int retVal, int tid, int64 tick, int id, intptr_t data) { | |
struct block_list *bl = map->id2bl(id); | |
if (bl == NULL) | |
return retVal; | |
if (bl->type != BL_PC) | |
return retVal; | |
struct map_session_data *sd = BL_CAST(BL_PC, bl); | |
if (sd == NULL) | |
return retVal; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return retVal; | |
struct player_data *ssd = getFromMSD(sd, 0); | |
nullpo_ret(ssd); | |
if (sd->bl.x < mf->x1 || sd->bl.y < mf->y1 || sd->bl.x > mf->x2 || sd->bl.y > mf->y2) { | |
if (ssd->cellpvp_flag == true) | |
walkout_cellpvp(sd); | |
} | |
else { | |
if (ssd->cellpvp_flag == false) | |
walkin_cellpvp(sd); | |
} | |
return retVal; | |
} | |
static int unit_blown_post(int retVal, struct block_list *bl, int dx, int dy, int count, int flag) { | |
if (bl == NULL) | |
return retVal; | |
if (bl->type != BL_PC) | |
return retVal; | |
struct map_session_data *sd = BL_CAST(BL_PC, bl); | |
if (sd == NULL) | |
return retVal; | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL || mf->map_cellpvp_flag == false) | |
return retVal; | |
struct player_data *ssd = getFromMSD(sd, 0); | |
nullpo_ret(ssd); | |
if (sd->bl.x < mf->x1 || sd->bl.y < mf->y1 || sd->bl.x > mf->x2 || sd->bl.y > mf->y2) { | |
if (ssd->cellpvp_flag == true) | |
walkout_cellpvp(sd); | |
} | |
else { | |
if (ssd->cellpvp_flag == false) | |
walkin_cellpvp(sd); | |
} | |
return retVal; | |
} | |
ACMD(cell_pvp) { | |
if (map->list[sd->bl.m].flag.pvp) { | |
clif->message(fd, "PvP is already On."); | |
return false; | |
} | |
char msg[CHAT_SIZE_MAX]; | |
int x_1, y_1, x_2, y_2, respawn, skillonoff, bone_drop_flag; | |
if (sscanf(message, "%d %d %d %d %d %d %d", &x_1, &y_1, &x_2, &y_2, &respawn, &skillonoff, &bone_drop_flag) < 7) { | |
clif->message(fd, "Syntax: @cell_pvp <x1> <y1> <x2> <y2> <respawn> <skillallow> <bonedrop>"); | |
clif->message(fd, " <respawn> : when player is dead -> 0 - no respawn. 1 - respawn instantly."); | |
clif->message(fd, " 2 - respawn normally from counting official PvP Points. "); | |
clif->message(fd, " <skillallow> : 0 - disallow skill outside pvp zone. 1 - allow skill outside pvp zone"); | |
clif->message(fd, " <bonedrop> : 0 - don't drop skull. 1 - always drop skull"); | |
safesnprintf(msg, CHAT_SIZE_MAX, "Example: @cell_pvp %d %d %d %d 1 0 0", sd->bl.x, sd->bl.y, sd->bl.x +10, sd->bl.y +10); | |
clif->message(fd, msg); | |
clif->message(fd, " Create a PvP zone for an Event with spectators."); | |
clif->message(fd, " When participant dead they respawn instantly."); | |
clif->message(fd, " Spectators can't interupt by casting skill outside PvP zone."); | |
safesnprintf(msg, CHAT_SIZE_MAX, "Example: @cell_pvp %d %d %d %d 0 1 0", sd->bl.x, sd->bl.y, sd->bl.x +10, sd->bl.y +10); | |
clif->message(fd, msg); | |
clif->message(fd, " Create a PvP zone just for fun or practice combat."); | |
clif->message(fd, " Useful for friendly PvP inside a custom house."); | |
clif->message(fd, " Allow interruption and doesn't annoy other players on the map."); | |
return false; | |
} | |
if (respawn < CELL_PVP_RESPAWN_DISABLE || respawn > CELL_PVP_RESPAWN_NORMAL) { | |
clif->message(fd, "<respawn> flag must within the value 0-2."); | |
clif->message(fd, "Syntax: @cell_pvp <x1> <y1> <x2> <y2> <respawn> <skillallow> <bonedrop>"); | |
clif->message(fd, " <respawn> : when player is dead -> 0 - no respawn. 1 - respawn instantly."); | |
clif->message(fd, " 2 - respawn normally from counting official PvP Points. "); | |
return false; | |
} | |
if (skillonoff < CELL_PVP_SKILL_DISALLOW || skillonoff > CELL_PVP_SKILL_ALLOW) { | |
clif->message(fd, "<skillallow> flag must within the value 0-1."); | |
clif->message(fd, "Syntax: @cell_pvp <x1> <y1> <x2> <y2> <respawn> <skillallow> <bonedrop>"); | |
clif->message(fd, " <skillallow> : 0 - no skill allow outside pvp zone. 1 - allow skill casting outside pvp zone"); | |
return false; | |
} | |
if (bone_drop_flag < CELL_PVP_BONEDROP_NONE || bone_drop_flag > CELL_PVP_BONEDROP_ALWAYS) { | |
clif->message(fd, "<bonedrop> flag must within the value 0-1."); | |
clif->message(fd, "Syntax: @cell_pvp <x1> <y1> <x2> <y2> <respawn> <skillallow> <bonedrop>"); | |
clif->message(fd, " <bonedrop> : 0 - don't drop skull. 1 - always drop skull"); | |
return false; | |
} | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf == NULL) { | |
CREATE(mf, struct map_cellpvp_data, 1); | |
mf->map_cellpvp_flag = true; | |
mf->x1 = x_1; | |
mf->y1 = y_1; | |
mf->x2 = x_2; | |
mf->y2 = y_2; | |
mf->map_cellpvp_respawn = respawn; | |
mf->map_cellpvp_skillonoff = skillonoff; | |
mf->bonedrop = bone_drop_flag; | |
addToMAPD(&map->list[sd->bl.m], mf, 0, true); | |
} | |
else { | |
mf->map_cellpvp_flag = true; | |
mf->x1 = x_1; | |
mf->y1 = y_1; | |
mf->x2 = x_2; | |
mf->y2 = y_2; | |
mf->map_cellpvp_respawn = respawn; | |
mf->map_cellpvp_skillonoff = skillonoff; | |
mf->bonedrop = bone_drop_flag; | |
} | |
map->zone_change2(sd->bl.m, strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)); | |
map->list[sd->bl.m].flag.pvp = 1; | |
map->foreachinarea(buildin_cellpvp, sd->bl.m, x_1, y_1, x_2, y_2, BL_PC); | |
char msg_respawn[CHAT_SIZE_MAX]; | |
if (respawn == CELL_PVP_RESPAWN_DISABLE) | |
safesnprintf(msg_respawn, CHAT_SIZE_MAX, "%s", "no respawn"); | |
else if (respawn == CELL_PVP_RESPAWN_INSTANT) | |
safesnprintf(msg_respawn, CHAT_SIZE_MAX, "%s", "instant respawn"); | |
else if (respawn == CELL_PVP_RESPAWN_NORMAL) | |
safesnprintf(msg_respawn, CHAT_SIZE_MAX, "%s", "normal respawn"); | |
char msg_skillonoff[CHAT_SIZE_MAX]; | |
if (skillonoff == CELL_PVP_SKILL_DISALLOW) | |
safesnprintf(msg_skillonoff, CHAT_SIZE_MAX, "%s", "disallow skill"); | |
else if (skillonoff == CELL_PVP_SKILL_ALLOW) | |
safesnprintf(msg_skillonoff, CHAT_SIZE_MAX, "%s", "allow skill"); | |
safesnprintf(msg, CHAT_SIZE_MAX, "%s has created a PvP Zone with %s and %s outside PvP Zone.", sd->status.name, msg_respawn, msg_skillonoff); | |
clif->broadcast(&sd->bl, msg, CHAT_SIZE_MAX, BC_DEFAULT, ALL_SAMEMAP); | |
return true; | |
} | |
BUILDIN(cell_pvp) { | |
char mapname[MAP_NAME_LENGTH]; | |
if (strlen(script_getstr(st,2)) > MAP_NAME_LENGTH) { | |
ShowError("buildin_cell_pvp: the map name must not longer than %d characters.\n", MAP_NAME_LENGTH); | |
return false; | |
} | |
safestrncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH); | |
int16 map_id = map->mapname2mapid(mapname); | |
if (map_id < 0) { | |
return false; | |
} | |
if (map->list[map_id].flag.pvp) { | |
ShowError("buildin_cell_pvp: this map '%s' PvP is already On.\n", mapname); | |
return false; | |
} | |
int respawn = script_getnum(st,7); | |
if (respawn < CELL_PVP_RESPAWN_DISABLE || respawn > CELL_PVP_RESPAWN_NORMAL) { | |
ShowError("buildin_cell_pvp: respawn flag must within constant value CELL_PVP_RESPAWN_DISABLE and CELL_PVP_RESPAWN_NORMAL.\n"); | |
return false; | |
} | |
int skillonoff = script_getnum(st,8); | |
if (skillonoff < CELL_PVP_SKILL_DISALLOW || skillonoff > CELL_PVP_SKILL_ALLOW) { | |
ShowError("buildin_cell_pvp: skillallow flag must within constant value CELL_PVP_SKILL_DISALLOW and CELL_PVP_SKILL_ALLOW.\n"); | |
return false; | |
} | |
int bone_drop_flag = script_getnum(st,9); | |
if (bone_drop_flag < CELL_PVP_BONEDROP_NONE || bone_drop_flag > CELL_PVP_BONEDROP_ALWAYS) { | |
ShowError("buildin_cell_pvp: bonedrop flag must within constant value CELL_PVP_BONEDROP_NONE and CELL_PVP_BONEDROP_ALWAYS.\n"); | |
return false; | |
} | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[map_id], 0); | |
if (mf == NULL) { | |
CREATE(mf, struct map_cellpvp_data, 1); | |
mf->map_cellpvp_flag = true; | |
mf->x1 = script_getnum(st,3); | |
mf->y1 = script_getnum(st,4); | |
mf->x2 = script_getnum(st,5); | |
mf->y2 = script_getnum(st,6); | |
mf->map_cellpvp_respawn = respawn; | |
mf->map_cellpvp_skillonoff = skillonoff; | |
mf->bonedrop = bone_drop_flag; | |
addToMAPD(&map->list[map_id], mf, 0, true); | |
} | |
else { | |
mf->map_cellpvp_flag = true; | |
mf->x1 = script_getnum(st,3); | |
mf->y1 = script_getnum(st,4); | |
mf->x2 = script_getnum(st,5); | |
mf->y2 = script_getnum(st,6); | |
mf->map_cellpvp_respawn = respawn; | |
mf->map_cellpvp_skillonoff = skillonoff; | |
mf->bonedrop = bone_drop_flag; | |
} | |
map->zone_change2(map_id, strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)); | |
map->list[map_id].flag.pvp = 1; | |
map->foreachinarea(buildin_cellpvp, map_id, mf->x1, mf->y1, mf->x2, mf->y2, BL_PC); | |
return true; | |
} | |
ACMD(pvpoff) { | |
if (!map->list[sd->bl.m].flag.pvp) { | |
clif->message(fd, msg_fd(fd,160)); // PvP is already Off. | |
return false; | |
} | |
map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone); | |
map->list[sd->bl.m].flag.pvp = 0; | |
if (!battle->bc->pk_mode) { | |
clif->map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); | |
clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP); | |
} | |
map->foreachinmap(atcommand->pvpoff_sub,sd->bl.m, BL_PC); | |
map->foreachinmap(atcommand->stopattack,sd->bl.m, BL_CHAR, 0); | |
clif->message(fd, msg_fd(fd,31)); // PvP: Off. | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[sd->bl.m], 0); | |
if (mf != NULL && mf->map_cellpvp_flag == true) { | |
clif->map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); | |
clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP); | |
removeFromMAPD(&map->list[sd->bl.m], 0); | |
} | |
return true; | |
} | |
BUILDIN(pvpoff) { | |
int16 m; | |
const char *str; | |
struct block_list bl; | |
memset(&bl, 0, sizeof(bl)); | |
str=script_getstr(st,2); | |
m = map->mapname2mapid(str); | |
if(m < 0 || !map->list[m].flag.pvp) | |
return true; | |
map->zone_change2(m, map->list[m].prev_zone); | |
map->list[m].flag.pvp = 0; | |
clif->map_property_mapall(m, MAPPROPERTY_NOTHING); | |
bl.type = BL_NUL; | |
bl.m = m; | |
clif->maptypeproperty2(&bl,ALL_SAMEMAP); | |
if (!battle->bc->pk_mode) | |
map->foreachinmap(script->buildin_pvpoff_sub, m, BL_PC); | |
struct map_cellpvp_data *mf = getFromMAPD(&map->list[m], 0); | |
if (mf != NULL && mf->map_cellpvp_flag == true) { | |
map->foreachinmap(script->buildin_pvpoff_sub, m, BL_PC); | |
removeFromMAPD(&map->list[m], 0); | |
} | |
return true; | |
} | |
HPExport void plugin_init(void) { | |
bone_drop_value = battle->bc->bone_drop; | |
addHookPost(pc, reg_received, pc_reg_received_post); | |
addHookPre(clif, pLoadEndAck, clif_parse_LoadEndAck_pre); | |
addHookPost(clif, pLoadEndAck, clif_parse_LoadEndAck_post); | |
addHookPre(pc, calc_pvprank, pc_calc_pvprank_pre); | |
addHookPre(pc, dead, pc_dead_pre); | |
addHookPost(pc, dead, pc_dead_post); | |
addHookPre(pc, respawn_timer, pc_respawn_timer_pre); | |
addHookPre(map, flags_init, map_flags_init_pre); | |
addHookPost(battle, config_read, battle_config_read_post); | |
addHookPost(battle, check_target, battle_check_target_post); | |
addHookPost(skill, check_condition_castbegin, skill_check_condition_castbeginend_post); | |
addHookPost(skill, check_condition_castend, skill_check_condition_castbeginend_post); | |
addHookPost(unit, walk_toxy_timer, unit_walk_toxy_timer_post); | |
addHookPost(unit, blown, unit_blown_post); | |
addAtcommand("cell_pvp", cell_pvp); | |
addScriptCommand("cell_pvp", "siiiiiii", cell_pvp); | |
addAtcommand("pvpoff", pvpoff); // overwrite | |
addScriptCommand("pvpoff", "s", pvpoff); // overwrite | |
script->set_constant("CELL_PVP_RESPAWN_DISABLE", CELL_PVP_RESPAWN_DISABLE, false, false); | |
script->set_constant("CELL_PVP_RESPAWN_INSTANT", CELL_PVP_RESPAWN_INSTANT, false, false); | |
script->set_constant("CELL_PVP_RESPAWN_NORMAL", CELL_PVP_RESPAWN_NORMAL, false, false); | |
script->set_constant("CELL_PVP_SKILL_DISALLOW", CELL_PVP_SKILL_DISALLOW, false, false); | |
script->set_constant("CELL_PVP_SKILL_ALLOW", CELL_PVP_SKILL_ALLOW, false, false); | |
script->set_constant("CELL_PVP_BONEDROP_NONE", CELL_PVP_BONEDROP_NONE, false, false); | |
script->set_constant("CELL_PVP_BONEDROP_ALWAYS", CELL_PVP_BONEDROP_ALWAYS, false, false); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment