From e8ab2885e6c07cdff08e66b55ac6bf5572e39402 Mon Sep 17 00:00:00 2001 From: skotlex Date: Fri, 7 Mar 2008 15:02:32 +0000 Subject: - 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 --- src/map/battle.c | 6 ++- src/map/battle.h | 2 + src/map/clif.c | 11 +++--- src/map/map.h | 2 +- src/map/mob.c | 113 ++++++++++++++++++++++++++++++++++--------------------- src/map/script.c | 6 +-- 6 files changed, 87 insertions(+), 53 deletions(-) (limited to 'src') 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; } -- cgit v1.2.3-60-g2f50