From bcb283d696d5ec4d7b6a2dfd2ba52cf2a3011fb4 Mon Sep 17 00:00:00 2001 From: zephyrus Date: Thu, 14 Feb 2008 01:18:19 +0000 Subject: - Added some new config settings: homunculus_autoloot, idle_no_autoloot, max_guild_alliance. - Added a code to activate a Kill Steal protection and the required mapflags. * (I will explain this later on forums). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12203 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/atcommand.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++- src/map/battle.c | 38 +++++++++++++--------- src/map/battle.h | 4 +++ src/map/guild.c | 10 +++--- src/map/map.h | 9 +++++ src/map/mob.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++---- src/map/mob.h | 1 + src/map/npc.c | 2 ++ src/map/unit.c | 2 ++ 9 files changed, 216 insertions(+), 29 deletions(-) (limited to 'src/map') 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 )."); + 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: -- cgit v1.2.3-60-g2f50