summaryrefslogtreecommitdiff
path: root/src/map/mob.c
diff options
context:
space:
mode:
authorskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2008-03-07 15:02:32 +0000
committerskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2008-03-07 15:02:32 +0000
commite8ab2885e6c07cdff08e66b55ac6bf5572e39402 (patch)
tree252a6f6b5d8b5fe93f18041e8b55b543cde956e1 /src/map/mob.c
parent88d795a036a4f954df1987fe3b241964df182a65 (diff)
downloadhercules-e8ab2885e6c07cdff08e66b55ac6bf5572e39402.tar.gz
hercules-e8ab2885e6c07cdff08e66b55ac6bf5572e39402.tar.bz2
hercules-e8ab2885e6c07cdff08e66b55ac6bf5572e39402.tar.xz
hercules-e8ab2885e6c07cdff08e66b55ac6bf5572e39402.zip
- 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).
- 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 mob_ai_sub_hard to return a bool indicating whether the AI was executed 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. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12315 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map/mob.c')
-rw-r--r--src/map/mob.c113
1 files changed, 70 insertions, 43 deletions
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)