summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/map/atcommand.c85
-rw-r--r--src/map/battle.c38
-rw-r--r--src/map/battle.h4
-rw-r--r--src/map/guild.c10
-rw-r--r--src/map/map.h9
-rw-r--r--src/map/mob.c94
-rw-r--r--src/map/mob.h1
-rw-r--r--src/map/npc.c2
-rw-r--r--src/map/unit.c2
9 files changed, 216 insertions, 29 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 588eff87b..35e644681 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -6085,9 +6085,55 @@ int atcommand_autoloot(const int fd, struct map_session_data* sd, const char* co
clif_displaymessage(fd, atcmd_output);
}else
clif_displaymessage(fd, "Autoloot is now off.");
+
+ if (sd->state.autoloot && sd->state.autolootid) {
+ // Autolootitem should be turned off
+ sd->state.autolootid = 0;
+ clif_displaymessage(fd, "Autolootitem is now off.");
+ }
+
return 0;
-}
+}
+/*==========================================
+ * @autolootitem
+ *------------------------------------------*/
+int atcommand_autolootitem(const int fd, struct map_session_data* sd, const char* command, const char* message)
+{
+ struct item_data *item_data = NULL;
+
+ if (!message || !*message) {
+ if (sd->state.autolootid) {
+ sd->state.autolootid = 0;
+ clif_displaymessage(fd, "Autolootitem have been turned OFF.");
+ } else
+ clif_displaymessage(fd, "Please, enter Item name or its ID (usage: @autolootitem <item_name_or_ID>).");
+ return -1;
+ }
+
+ if ((item_data = itemdb_exists(atoi(message))) == NULL)
+ item_data = itemdb_searchname(message);
+
+ if (!item_data) {
+ // No items founds in the DB with Id or Name
+ clif_displaymessage(fd, "Item not found.");
+ return -1;
+ }
+
+ sd->state.autolootid = item_data->nameid; // Autoloot Activated
+
+ sprintf(atcmd_output, "Autolooting Item: '%s'/'%s' {%d}",
+ item_data->name, item_data->jname, item_data->nameid);
+ clif_displaymessage(fd, atcmd_output);
+
+ if (sd->state.autolootid && sd->state.autoloot) {
+ // Autoloot should be turned off
+ sd->state.autoloot = 0;
+ clif_displaymessage(fd, "Autoloot is now off (cannot be actitaved together).");
+ }
+
+ return 0;
+}
/*==========================================
* It is made to rain.
@@ -8115,8 +8161,42 @@ int atcommand_feelreset(const int fd, struct map_session_data* sd, const char* c
return 0;
}
+/*==========================================
+ * Kill Steal Protection
+ *------------------------------------------*/
+int atcommand_ksprotection(const int fd, struct map_session_data *sd, const char *command, const char *message)
+{
+ nullpo_retr(-1,sd);
+ if( sd->state.noks ) {
+ sd->state.noks = 0;
+ sprintf(atcmd_output, "[ K.S Protection Inactive ]");
+ } else {
+ sprintf(atcmd_output, "[ K.S Protection Active ]");
+ sd->state.noks = 1;
+ }
+ clif_displaymessage(fd, atcmd_output);
+ return 0;
+}
+/*==========================================
+ * Map Kill Steal Protection Setting
+ *------------------------------------------*/
+int atcommand_allowks(const int fd, struct map_session_data *sd, const char *command, const char *message)
+{
+ nullpo_retr(-1,sd);
+
+ if( map[sd->bl.m].flag.allowks ) {
+ map[sd->bl.m].flag.allowks = 0;
+ sprintf(atcmd_output, "[ Map K.S Protection Active ]");
+ } else {
+ map[sd->bl.m].flag.allowks = 1;
+ sprintf(atcmd_output, "[ Map K.S Protection Inactive ]");
+ }
+
+ clif_displaymessage(fd, atcmd_output);
+ return 0;
+}
/*==========================================
* atcommand_info[] structure definition
@@ -8348,6 +8428,7 @@ AtCommandInfo atcommand_info[] = {
{ "disguiseall", 99, atcommand_disguiseall },
{ "changelook", 60, atcommand_changelook },
{ "autoloot", 10, atcommand_autoloot },
+ { "alootid", 10, atcommand_autolootitem },
{ "mobinfo", 1, atcommand_mobinfo },
{ "monsterinfo", 1, atcommand_mobinfo },
{ "mi", 1, atcommand_mobinfo },
@@ -8407,6 +8488,8 @@ AtCommandInfo atcommand_info[] = {
{ "showmobs", 10, atcommand_showmobs },
{ "feelreset", 10, atcommand_feelreset },
{ "mail", 1, atcommand_mail },
+ { "noks", 0, atcommand_ksprotection },
+ { "allowks", 6, atcommand_allowks },
};
diff --git a/src/map/battle.c b/src/map/battle.c
index cd54a2e39..21c2c751d 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -259,6 +259,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
if (!damage)
return 0;
+ if( mob_ksprotected(src, bl) )
+ return 0;
+
if (bl->type == BL_PC) {
sd=(struct map_session_data *)bl;
//Special no damage states
@@ -3139,23 +3142,22 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
case BL_PC:
{
TBL_PC *sd = (TBL_PC*) s_bl;
- if (sd->state.killer && s_bl != t_bl)
+ if( s_bl != t_bl )
{
- state |= BCT_ENEMY; //Is on a killing rampage :O
- strip_enemy = 0;
- } else
- if (sd->duel_group && t_bl != s_bl && // Duel [LuzZza]
- !(
- (!battle_config.duel_allow_pvp && map[m].flag.pvp) ||
- (!battle_config.duel_allow_gvg && map_flag_gvg(m))
- ))
- {
- if (t_bl->type == BL_PC &&
- (sd->duel_group == ((TBL_PC*)t_bl)->duel_group))
- //Duel targets can ONLY be your enemy, nothing else.
- return (BCT_ENEMY&flag)?1:-1;
- else // You can't target anything out of your duel
- return 0;
+ if( sd->state.killer )
+ {
+ state |= BCT_ENEMY; //Is on a killing rampage :O
+ strip_enemy = 0;
+ }
+ else if( sd->duel_group && !((!battle_config.duel_allow_pvp && map[m].flag.pvp) || (!battle_config.duel_allow_gvg && map_flag_gvg(m))) )
+ {
+ if (t_bl->type == BL_PC &&
+ (sd->duel_group == ((TBL_PC*)t_bl)->duel_group))
+ //Duel targets can ONLY be your enemy, nothing else.
+ return (BCT_ENEMY&flag)?1:-1;
+ else // You can't target anything out of your duel
+ return 0;
+ }
}
if (map_flag_gvg(m) && !sd->status.guild_id &&
t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->guardian_data)
@@ -3650,6 +3652,10 @@ static const struct _battle_data {
{ "sg_miracle_skill_duration", &battle_config.sg_miracle_skill_duration, 3600000, 0, INT_MAX, },
{ "hvan_explosion_intimate", &battle_config.hvan_explosion_intimate, 45000, 0, 100000, },
{ "quest_exp_rate", &battle_config.quest_exp_rate, 100, 0, INT_MAX, },
+ { "homunculus_autoloot", &battle_config.homunculus_autoloot, 0, 0, 1, },
+ { "idle_no_autoloot", &battle_config.idle_no_autoloot, 0, 0, INT_MAX, },
+ { "max_guild_alliance", &battle_config.max_guild_alliance, 3, 1, 3, },
+ { "ksprotection", &battle_config.ksprotection, 5000, 0, INT_MAX, },
};
diff --git a/src/map/battle.h b/src/map/battle.h
index cc956453b..1483d8915 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -438,6 +438,10 @@ extern struct Battle_Config
int homunculus_show_growth ; //[orn]
int homunculus_friendly_rate;
int quest_exp_rate;
+ int homunculus_autoloot;
+ int idle_no_autoloot;
+ int max_guild_alliance;
+ int ksprotection;
} battle_config;
void do_init_battle(void);
diff --git a/src/map/guild.c b/src/map/guild.c
index a9670400a..e591fc838 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -1250,11 +1250,11 @@ int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd)
if(sd->status.guild_id == tsd->status.guild_id)
return 0;
- if( guild_get_alliance_count(g[0],0)>=3 ) {
+ if( guild_get_alliance_count(g[0],0) >= battle_config.max_guild_alliance ) {
clif_guild_allianceack(sd,4);
return 0;
}
- if( guild_get_alliance_count(g[1],0)>=3 ) {
+ if( guild_get_alliance_count(g[1],0) >= battle_config.max_guild_alliance ) {
clif_guild_allianceack(sd,3);
return 0;
}
@@ -1300,12 +1300,12 @@ int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag)
g=guild_search(sd->status.guild_id);
tg=guild_search(tsd->status.guild_id);
- if(g==NULL || guild_get_alliance_count(g,0)>=3){
+ if(g==NULL || guild_get_alliance_count(g,0) >= battle_config.max_guild_alliance){
clif_guild_allianceack(sd,4);
clif_guild_allianceack(tsd,3);
return 0;
}
- if(tg==NULL || guild_get_alliance_count(tg,0)>=3){
+ if(tg==NULL || guild_get_alliance_count(tg,0) >= battle_config.max_guild_alliance){
clif_guild_allianceack(sd,3);
clif_guild_allianceack(tsd,4);
return 0;
@@ -1367,7 +1367,7 @@ int guild_opposition(struct map_session_data *sd,struct map_session_data *tsd)
if(sd->status.guild_id == tsd->status.guild_id)
return 0;
- if( guild_get_alliance_count(g,1)>=3 ) {
+ if( guild_get_alliance_count(g,1) >= battle_config.max_guild_alliance ) {
clif_guild_oppositionack(sd,1);
return 0;
}
diff --git a/src/map/map.h b/src/map/map.h
index 84d041569..69f007b60 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -551,6 +551,8 @@ struct map_session_data {
unsigned doridori : 1;
unsigned ignoreAll : 1;
unsigned short autoloot;
+ unsigned short autolootid; // [Zephyrus]
+ unsigned noks : 1; // [Zeph Kill Steal Protection]
struct guild *gmaster_flag;
} state;
struct {
@@ -612,6 +614,7 @@ struct map_session_data {
unsigned int canuseitem_tick; // [Skotlex]
unsigned int cantalk_tick;
unsigned int cansendmail_tick; // [Mail System Flood Protection]
+ unsigned int ks_floodprotect_tick; // [Kill Steal Protection]
short weapontype1,weapontype2;
short disguise; // [Valaris]
@@ -911,6 +914,11 @@ struct mob_data {
unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex]
int level;
int target_id,attacked_id;
+
+ // Kill Steal Protection
+ int owner_id;
+ unsigned int ks_tick;
+
unsigned int next_walktime,last_thinktime,last_linktime;
short move_fail_count;
short lootitem_count;
@@ -1168,6 +1176,7 @@ struct map_data {
int npc_num;
int users;
struct map_flag {
+ unsigned allowks : 1; // [Kill Steal Protection]
unsigned nomemo : 1;
unsigned noteleport : 1;
unsigned noreturn : 1;
diff --git a/src/map/mob.c b/src/map/mob.c
index 1f78ec8d5..2f1a8f2cc 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -10,6 +10,7 @@
#include "../common/ers.h"
#include "../common/strlib.h"
#include "../common/utils.h"
+#include "../common/socket.h"
#include "map.h"
#include "path.h"
@@ -275,6 +276,80 @@ int mob_get_random_id(int type, int flag, int lv)
return class_;
}
+/*==========================================
+ * Kill Steal Protection [Zephyrus]
+ *------------------------------------------*/
+bool mob_ksprotected (struct block_list *src, struct block_list *target)
+{
+ struct block_list *s_bl;
+ struct map_session_data *sd, *pl_sd;
+ struct mob_data *md;
+ unsigned int tick = gettick();
+ char output[128];
+
+ if( !battle_config.ksprotection )
+ return false; // KS Protection Disabled
+
+ if( !(md = BL_CAST(BL_MOB,target)) )
+ return false; // Tarjet is not MOB
+
+ if( (s_bl = battle_get_master(src)) == NULL )
+ s_bl = src;
+
+ if( !(sd = BL_CAST(BL_PC,s_bl)) )
+ return false; // Master is not PC
+
+ do {
+ if( map[md->bl.m].flag.allowks || map[md->bl.m].flag.gvg || map[md->bl.m].flag.pvp )
+ return false; // Ignores GVG, PVP and AllowKS map flags
+
+ if( md->db->mexp || md->master_id )
+ return false; // MVP and Slaves ignores KS
+
+ if( sd->bl.id == md->owner_id )
+ break; // Same player
+
+ if( !md->owner_id || !(pl_sd = map_id2sd(md->owner_id)) )
+ break; // Not owner or owner offline
+
+ if( pl_sd->bl.m != md->bl.m )
+ break; // Owner on different map
+
+ if( DIFF_TICK(md->ks_tick, tick) <= 0 )
+ break; // Protection Time's Out
+
+ if( !pl_sd->state.noks )
+ return false; // No KS Protected, but this is necessary to protect normal players
+
+ if( pl_sd->status.party_id && pl_sd->status.party_id == sd->status.party_id )
+ break; // Same Party Allow KS
+
+ // Message to KS
+ if( DIFF_TICK(sd->ks_floodprotect_tick, tick) <= 0 )
+ {
+ sprintf(output, "[KS Warning!! - Owner : %s]", pl_sd->status.name);
+ clif_disp_onlyself(sd, output, strlen(output));
+
+ sd->ks_floodprotect_tick = tick + 2000;
+ }
+
+ // Message to Owner
+ if( DIFF_TICK(pl_sd->ks_floodprotect_tick, tick) <= 0 )
+ {
+ sprintf(output, "[Warning!! - %s is KS you]", sd->status.name);
+ clif_disp_onlyself(pl_sd, output, strlen(output));
+
+ pl_sd->ks_floodprotect_tick = tick + 2000;
+ }
+
+ return true;
+ } while(0);
+
+ md->owner_id = sd->bl.id;
+ md->ks_tick = tick + battle_config.ksprotection;
+
+ return false;
+}
struct mob_data *mob_once_spawn_sub(struct block_list *bl, int m, short x, short y, const char *mobname, int class_, const char *event)
{
@@ -1522,8 +1597,9 @@ static int mob_delay_item_drop(int tid, unsigned int tick, int id, int data)
* Sets the item_drop into the item_drop_list.
* Also performs logging and autoloot if enabled.
* rate is the drop-rate of the item, required for autoloot.
+ * flag : Killed only by homunculus?
*------------------------------------------*/
-static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate)
+static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag)
{
TBL_PC* sd;
@@ -1538,7 +1614,7 @@ static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, str
sd = map_charid2sd(dlist->first_charid);
if( sd == NULL ) sd = map_charid2sd(dlist->second_charid);
if( sd == NULL ) sd = map_charid2sd(dlist->third_charid);
- if( sd && drop_rate <= sd->state.autoloot
+ if( sd && (drop_rate <= sd->state.autoloot || ditem->item_data.nameid == sd->state.autolootid) && sd->idletime >= (last_tick - battle_config.idle_no_autoloot) && (battle_config.homunculus_autoloot?1:!flag)
#ifdef AUTOLOOT_DISTANCE
&& check_distance_blxy(&sd->bl, dlist->x, dlist->y, AUTOLOOT_DISTANCE)
#endif
@@ -1777,6 +1853,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
} pt[DAMAGELOG_SIZE];
int i,temp,count,pnum=0,m=md->bl.m;
unsigned int mvp_damage, tick = gettick();
+ unsigned short flaghom = 1; // [Zephyrus] Does the mob only received damage from homunculus?
if(src && src->type == BL_PC) {
sd = (struct map_session_data *)src;
@@ -1851,6 +1928,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
tmpsd[i] = tsd; // record as valid damage-log entry
+
+ if(!md->dmglog[i].flag && flaghom)
+ flaghom = 0; // Damage received from other Types != Homunculus
}
if(!battle_config.exp_calc_type && count > 1)
@@ -2045,13 +2125,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
// Announce first, or else ditem will be freed. [Lance]
// By popular demand, use base drop rate for autoloot code. [Skotlex]
- mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p);
+ mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, flaghom);
}
// Ore Discovery [Celest]
if (sd == mvp_sd && pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rand()%10000) {
ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE), 1);
- mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10);
+ mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, 0);
}
if(sd) {
@@ -2077,7 +2157,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
if (rand()%10000 >= drop_rate)
continue;
itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb_searchrandomid(sd->add_drop[i].group);
- mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate);
+ mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, 0);
}
}
@@ -2093,7 +2173,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
// process items looted by the mob
if(md->lootitem) {
for(i = 0; i < md->lootitem_count; i++)
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000);
+ mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
}
if (dlist->item) //There are drop items.
add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, (int)dlist, 0);
@@ -2109,7 +2189,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
dlist->third_charid = (third_sd ? third_sd->status.char_id : 0);
dlist->item = NULL;
for(i = 0; i < md->lootitem_count; i++)
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000);
+ mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, (int)dlist, 0);
}
diff --git a/src/map/mob.h b/src/map/mob.h
index bdb35a21f..2590c90ed 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -157,6 +157,7 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int m,
int mob_once_spawn(struct map_session_data* sd,int m,short x,short y,const char* mobname,int class_,int amount,const char* event);
int mob_once_spawn_area(struct map_session_data* sd,int m,int x0,int y0,int x1,int y1,const char* mobname,int class_,int amount,const char* event);
+bool mob_ksprotected (struct block_list *src, struct block_list *target);
int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian); // Spawning Guardians [Valaris]
int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardian's ownership. [Skotlex]
diff --git a/src/map/npc.c b/src/map/npc.c
index dbb190ebb..6f1c59806 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -2318,6 +2318,8 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
}
map[m].flag.nosave = state;
}
+ else if (!strcmpi(w3,"allowks"))
+ map[m].flag.allowks=state; // [Kill Steal Protection]
else if (!strcmpi(w3,"nomemo"))
map[m].flag.nomemo=state;
else if (!strcmpi(w3,"noteleport"))
diff --git a/src/map/unit.c b/src/map/unit.c
index 3ae4aa091..d0d06ff06 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -807,6 +807,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
if(skillnotok(skill_num, sd)) // [MouseJstr]
return 0;
+ mob_ksprotected(src, map_id2bl(target_id));
+
switch(skill_num)
{ //Check for skills that auto-select target
case MO_CHAINCOMBO: