summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt7
-rw-r--r--conf/Changelog.txt5
-rw-r--r--conf/battle/monster.conf5
-rw-r--r--src/map/battle.c6
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/clif.c11
-rw-r--r--src/map/map.h2
-rw-r--r--src/map/mob.c113
-rw-r--r--src/map/script.c6
9 files changed, 104 insertions, 53 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 9fb7dcd39..9c5b82da3 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -3,6 +3,13 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
+2008/03/07
+ * Script induced status changes can now be reduced by stats/cards (but
+ only trigger rate is reduced, not duration).
+ * Battle delay timers will now check if the target player has the
+ invincible timer active or not.
+ * Adjusted clif_damage and clif_skill_damage to set the endure type value
+ based on dmotion and damage, rather than hardchecking for SC_ENDURE.
2008/03/06
* Fixed song/dance cells to appear even on top of walls and pits.
* Fixed non-chatroom owners being able to kick others from the chatroom.
diff --git a/conf/Changelog.txt b/conf/Changelog.txt
index 9e96b527a..e24f97ea1 100644
--- a/conf/Changelog.txt
+++ b/conf/Changelog.txt
@@ -1,5 +1,10 @@
Date Added
+2008/03/07
+ * Added config settings mob_active_time and boss_active_time, what they do
+ is specify a duration during which monsters will keep running their active
+ AI after all players have left their vecinity. Their current defaults are
+ set to 0 (disabled). [Skotlex]
2008/02/29
*Rev. 12273 Added some additional map flags for some newer maps. [L0ne_W0lf]
2008/02/27
diff --git a/conf/battle/monster.conf b/conf/battle/monster.conf
index 2208d8da3..aeb54c929 100644
--- a/conf/battle/monster.conf
+++ b/conf/battle/monster.conf
@@ -71,6 +71,11 @@ monster_ai: 0
// 4: Disable warping when the target map is a 'nobranch' map.
mob_warp: 0
+// If these are set above 0, they define the time (in ms) during which monsters
+// will have their 'AI' active after all players have left their vecinity.
+mob_active_time: 0
+boss_active_time: 0
+
// Mobs and Pets view-range adjustment (range2 column in the mob_db) (Note 2)
view_range_rate: 100
diff --git a/src/map/battle.c b/src/map/battle.c
index 3c467ff2e..7b58dd419 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -154,7 +154,9 @@ int battle_delay_damage_sub (int tid, unsigned int tick, int id, int data)
struct delay_damage *dat = (struct delay_damage *)data;
struct block_list *target = map_id2bl(dat->target);
if (target && dat && map_id2bl(id) == dat->src && target->prev != NULL && !status_isdead(target) &&
- target->m == dat->src->m && check_distance_bl(dat->src, target, dat->distance)) //Check to see if you haven't teleported. [Skotlex]
+ target->m == dat->src->m &&
+ (target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == -1) &&
+ check_distance_bl(dat->src, target, dat->distance)) //Check to see if you haven't teleported. [Skotlex]
{
map_freeblock_lock();
status_fix_damage(dat->src, target, dat->damage, dat->delay);
@@ -3643,6 +3645,8 @@ static const struct _battle_data {
{ "day_duration", &battle_config.day_duration, 0, 0, INT_MAX, },
{ "night_duration", &battle_config.night_duration, 0, 0, INT_MAX, },
{ "mob_remove_delay", &battle_config.mob_remove_delay, 60000, 15000, INT_MAX, },
+ { "mob_active_time", &battle_config.mob_active_time, 0, 0, INT_MAX, },
+ { "boss_active_time", &battle_config.boss_active_time, 0, 0, INT_MAX, },
{ "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, },
diff --git a/src/map/battle.h b/src/map/battle.h
index 042b83cda..9c7bd2fb0 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -383,6 +383,8 @@ extern struct Battle_Config
int dynamic_mobs; // Dynamic Mobs [Wizputer] - battle_athena flag implemented by [random]
int mob_remove_damaged; // Dynamic Mobs - Remove mobs even if damaged [Wizputer]
int mob_remove_delay; // Dynamic Mobs - delay before removing mobs from a map [Skotlex]
+ int mob_active_time; //Duration through which mobs execute their Hard AI after players leave their area of sight.
+ int boss_active_time;
int show_hp_sp_drain, show_hp_sp_gain; //[Skotlex]
diff --git a/src/map/clif.c b/src/map/clif.c
index 032fb275a..694e6d987 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -3472,6 +3472,9 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl)
}
}
+//Modifies the type of damage according to status changes [Skotlex]
+#define clif_calc_delay(type,damage,delay) ((type)==0x0a?type:((delay)==0&&(damage)>0?9:type))
+
/*==========================================
* Estimates walk delay based on the damage criteria. [Skotlex]
*------------------------------------------*/
@@ -3515,10 +3518,9 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic
nullpo_retr(0, src);
nullpo_retr(0, dst);
+ type = clif_calc_delay(type,damage+damage2,ddelay);
sc = status_get_sc(dst);
if(sc && sc->count) {
- if(type != 4 && dst->type == BL_PC && sc->data[SC_ENDURE] && !map_flag_gvg(dst->m))
- type = 9;
if(sc->data[SC_HALLUCINATION]) {
if(damage) damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
if(damage2) damage2 = damage2*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
@@ -4090,10 +4092,9 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int
nullpo_retr(0, src);
nullpo_retr(0, dst);
+ type = clif_calc_delay(type,damage,ddelay);
sc = status_get_sc(dst);
if(sc && sc->count) {
- if(type != 4 && dst->type == BL_PC && sc->data[SC_ENDURE] && !map_flag_gvg(dst->m))
- type = 9;
if(sc->data[SC_HALLUCINATION] && damage)
damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
}
@@ -4179,7 +4180,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in
nullpo_retr(0, dst);
type = (type>0)?type:skill_get_hit(skill_id);
- type = clif_calc_delay(type, ddelay);
+ type = clif_calc_delay(type,damage,ddelay);
sc = status_get_sc(dst);
if(sc && sc->count) {
diff --git a/src/map/map.h b/src/map/map.h
index 8ded26f9d..eac91c219 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -918,7 +918,7 @@ struct mob_data {
int level;
int target_id,attacked_id;
- unsigned int next_walktime,last_thinktime,last_linktime;
+ unsigned int next_walktime,last_thinktime,last_linktime,last_pcneartime;
short move_fail_count;
short lootitem_count;
short min_chase;
diff --git a/src/map/mob.c b/src/map/mob.c
index 480442efb..4c7da69cb 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -781,6 +781,7 @@ int mob_spawn (struct mob_data *md)
md->state.skillstate = MSS_IDLE;
md->next_walktime = tick+rand()%5000+1000;
md->last_linktime = tick;
+ md->last_pcneartime = 0;
for (i = 0, c = tick-1000*3600*10; i < MAX_MOBSKILL; i++)
md->skilldelay[i] = c;
@@ -1199,40 +1200,33 @@ int mob_warpchase(struct mob_data *md, struct block_list *target)
/*==========================================
* AI of MOB whose is near a Player
*------------------------------------------*/
-static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
+static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
{
- struct mob_data *md;
struct block_list *tbl = NULL, *abl = NULL;
- unsigned int tick;
int dist;
int mode;
int search_size;
int view_range, can_move;
- md = (struct mob_data*)bl;
- tick = va_arg(ap, unsigned int);
-
if(md->bl.prev == NULL || md->status.hp <= 0)
- return 1;
+ return false;
- if(!md->state.spotted) //Hard AI triggered.
- md->state.spotted = 1;
-
if (DIFF_TICK(tick, md->last_thinktime) < MIN_MOBTHINKTIME)
- return 0;
+ return false;
+
md->last_thinktime = tick;
if (md->ud.skilltimer != -1)
- return 0;
+ return false;
if(md->ud.walktimer != -1 && md->ud.walkpath.path_pos <= 3)
- return 0;
+ return false;
// Abnormalities
if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP])
{ //Should reset targets.
md->target_id = md->attacked_id = 0;
- return 0;
+ return false;
}
if (md->sc.count && md->sc.data[SC_BLIND])
@@ -1255,7 +1249,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
((TBL_PC*)tbl)->invincible_timer != INVALID_TIMER)
)) { //Unlock current target.
if (mob_warpchase(md, tbl))
- return 0; //Chasing this target.
+ return true; //Chasing this target.
mob_unlocktarget(md, tick-(battle_config.mob_ai&0x8?3000:0)); //Imediately do random walk.
tbl = NULL;
}
@@ -1274,17 +1268,17 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
) &&
md->state.attacked_count++ >= RUDE_ATTACKED_COUNT &&
!mobskill_use(md, tick, MSC_RUDEATTACKED) && //If can't rude Attack
- can_move && unit_escape(bl, tbl, rand()%10 +1)) //Attempt escape
+ can_move && unit_escape(&md->bl, tbl, rand()%10 +1)) //Attempt escape
{ //Escaped
md->attacked_id = 0;
- return 0;
+ return true;
}
} else
if ((abl= map_id2bl(md->attacked_id)) && (!tbl || mob_can_changetarget(md, abl, mode))) {
if (md->bl.m != abl->m || abl->prev == NULL ||
(dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE ||
- battle_check_target(bl, abl, BCT_ENEMY) <= 0 ||
- (battle_config.mob_ai&0x2 && !status_check_skilluse(bl, abl, 0, 0)) || //Retaliate check
+ battle_check_target(&md->bl, abl, BCT_ENEMY) <= 0 ||
+ (battle_config.mob_ai&0x2 && !status_check_skilluse(&md->bl, abl, 0, 0)) || //Retaliate check
(!battle_check_range(&md->bl, abl, md->status.rhw.range) &&
( //Reach check
(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 &&
@@ -1295,13 +1289,13 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
) { //Rude attacked
if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT &&
!mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move &&
- !tbl && unit_escape(bl, abl, rand()%10 +1))
+ !tbl && unit_escape(&md->bl, abl, rand()%10 +1))
{ //Escaped.
//TODO: Maybe it shouldn't attempt to run if it has another, valid target?
md->attacked_id = 0;
- return 0;
+ return true;
}
- } else if (!(battle_config.mob_ai&0x2) && !status_check_skilluse(bl, abl, 0, 0)) {
+ } else if (!(battle_config.mob_ai&0x2) && !status_check_skilluse(&md->bl, abl, 0, 0)) {
//Can't attack back, but didn't invoke a rude attacked skill...
} else { //Attackable
if (!tbl || dist < md->status.rhw.range || !check_distance_bl(&md->bl, tbl, dist)
@@ -1324,7 +1318,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
// Processing of slave monster
if (md->master_id > 0 && mob_ai_sub_hard_slavemob(md, tick))
- return 0;
+ return true;
// Scan area for targets
if (!tbl && mode&MD_LOOTER && md->lootitem && DIFF_TICK(tick, md->ud.canact_tick) > 0 &&
@@ -1351,7 +1345,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
md->state.aggressive = 1; //Restore angry state when no targets are available.
//This handles triggering idle walk/skill.
mob_unlocktarget(md, tick);
- return 0;
+ return true;
}
//Target exists, attack or loot as applicable.
@@ -1359,29 +1353,29 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
{ //Loot time.
struct flooritem_data *fitem;
if (md->ud.target == tbl->id && md->ud.walktimer != -1)
- return 0; //Already locked.
+ return true; //Already locked.
if (md->lootitem == NULL)
{ //Can't loot...
mob_unlocktarget (md, tick);
- return 0;
+ return true;
}
if (!check_distance_bl(&md->bl, tbl, 1))
{ //Still not within loot range.
if (!(mode&MD_CANMOVE))
{ //A looter that can't move? Real smart.
mob_unlocktarget(md,tick);
- return 0;
+ return true;
}
if (!can_move) //Stuck. Wait before walking.
- return 0;
+ return true;
md->state.skillstate = MSS_LOOT;
if (!unit_walktobl(&md->bl, tbl, 0, 1))
mob_unlocktarget(md, tick); //Can't loot...
- return 0;
+ return true;
}
//Within looting range.
if (md->ud.attacktimer != -1)
- return 0; //Busy attacking?
+ return true; //Busy attacking?
fitem = (struct flooritem_data *)tbl;
if(log_config.enable_logs&0x10) //Logs items, taken by (L)ooter Mobs [Lupus]
@@ -1404,17 +1398,17 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
//Clear item.
map_clearflooritem (tbl->id);
mob_unlocktarget (md,tick);
- return 0;
+ return true;
}
//Attempt to attack.
//At this point we know the target is attackable, we just gotta check if the range matches.
if (md->ud.target == tbl->id && md->ud.attacktimer != -1) //Already locked.
- return 0;
+ return true;
if (battle_check_range (&md->bl, tbl, md->status.rhw.range))
{ //Target within range, engage
unit_attack(&md->bl,tbl->id,1);
- return 0;
+ return true;
}
//Out of range...
@@ -1423,7 +1417,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
md->state.skillstate = MSS_IDLE;
if (!mobskill_use(md, tick, -1))
mob_unlocktarget(md,tick);
- return 0;
+ return true;
}
if (!can_move)
@@ -1431,7 +1425,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
md->state.skillstate = MSS_IDLE;
if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL))
mobskill_use(md, tick, -1);
- return 0;
+ return true;
}
if (md->ud.walktimer != -1 && md->ud.target == tbl->id &&
@@ -1439,13 +1433,26 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
!(battle_config.mob_ai&0x1) ||
check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, md->status.rhw.range)
)) //Current target tile is still within attack range.
- return 0;
+ return true;
//Follow up if possible.
if(!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) ||
!unit_walktobl(&md->bl, tbl, md->status.rhw.range, 2))
mob_unlocktarget(md,tick);
+ return true;
+}
+
+static int mob_ai_sub_hard_timer(struct block_list *bl,va_list ap)
+{
+ struct mob_data *md = (struct mob_data*)bl;
+ unsigned int tick = va_arg(ap, unsigned int);
+ if (mob_ai_sub_hard(md, tick))
+ { //Hard AI triggered.
+ if(!md->state.spotted)
+ md->state.spotted = 1;
+ md->last_pcneartime = tick;
+ }
return 0;
}
@@ -1456,7 +1463,7 @@ static int mob_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
{
unsigned int tick;
tick=va_arg(ap,unsigned int);
- map_foreachinrange(mob_ai_sub_hard,&sd->bl, AREA_SIZE+ACTIVE_AI_RANGE, BL_MOB,tick);
+ map_foreachinrange(mob_ai_sub_hard_timer,&sd->bl, AREA_SIZE+ACTIVE_AI_RANGE, BL_MOB,tick);
return 0;
}
@@ -1475,20 +1482,39 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list ap)
if(md->bl.prev == NULL)
return 0;
+ tick=va_arg(ap,unsigned int);
+
if (md->nd || (battle_config.mob_ai&0x20 && map[md->bl.m].users>0))
- return mob_ai_sub_hard(&md->bl, ap);
+ return (int)mob_ai_sub_hard(md, tick);
- tick=va_arg(ap,unsigned int);
+ if (md->bl.prev==NULL || md->status.hp == 0)
+ return 1;
+
+ if(battle_config.mob_active_time &&
+ md->last_pcneartime &&
+ !(md->status.mode&MD_BOSS) &&
+ DIFF_TICK(tick,md->last_thinktime) > MIN_MOBTHINKTIME)
+ {
+ if (DIFF_TICK(tick,md->last_pcneartime) < battle_config.mob_active_time)
+ return (int)mob_ai_sub_hard(md, tick);
+ md->last_pcneartime = 0;
+ }
+
+ if(battle_config.boss_active_time &&
+ md->last_pcneartime &&
+ (md->status.mode&MD_BOSS) &&
+ DIFF_TICK(tick,md->last_thinktime) > MIN_MOBTHINKTIME)
+ {
+ if (DIFF_TICK(tick,md->last_pcneartime) < battle_config.boss_active_time)
+ return (int)mob_ai_sub_hard(md, tick);
+ md->last_pcneartime = 0;
+ }
if(DIFF_TICK(tick,md->last_thinktime)< 10*MIN_MOBTHINKTIME)
return 0;
md->last_thinktime=tick;
- if (md->bl.prev==NULL || md->status.hp == 0)
- return 1;
-
- // 取り巻きモンスターの処理(呼び戻しされた時)
if (md->master_id) {
mob_ai_sub_hard_slavemob (md,tick);
return 0;
@@ -2345,6 +2371,7 @@ void mob_revive(struct mob_data *md, unsigned int hp)
md->last_thinktime = tick;
md->next_walktime = tick+rand()%50+5000;
md->last_linktime = tick;
+ md->last_pcneartime = 0;
if (!md->bl.prev)
map_addblock(&md->bl);
if(pcdb_checkid(md->vd->class_) && md->nd)
diff --git a/src/map/script.c b/src/map/script.c
index e0b1db6db..ee5bbbdc5 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -8123,7 +8123,7 @@ BUILDIN_FUNC(sc_start)
}
if( bl )
- status_change_start(bl, type, 10000, val1, 0, 0, val4, tick, 1|2|8);
+ status_change_start(bl, type, 10000, val1, 0, 0, val4, tick, 2);
return 0;
}
@@ -8161,7 +8161,7 @@ BUILDIN_FUNC(sc_start2)
}
if( bl )
- status_change_start(bl, type, rate, val1, 0, 0, val4, tick, 1|2|8);
+ status_change_start(bl, type, rate, val1, 0, 0, val4, tick, 2);
return 0;
}
@@ -8202,7 +8202,7 @@ BUILDIN_FUNC(sc_start4)
}
if( bl )
- status_change_start(bl, type, 10000, val1, val2, val3, val4, tick, 1|2|8);
+ status_change_start(bl, type, 10000, val1, val2, val3, val4, tick, 2);
return 0;
}