summaryrefslogtreecommitdiff
path: root/src/map/mob.c
diff options
context:
space:
mode:
authorskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-12-06 18:21:32 +0000
committerskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-12-06 18:21:32 +0000
commitf4edc7e4431b929acc62e4c2427e815ba9d69779 (patch)
treeac82447101de9f643bef0fa7a5b3a56bd1e37194 /src/map/mob.c
parentf7ff1f208a2ce086fe6636b8359c65cf14ab68f4 (diff)
downloadhercules-f4edc7e4431b929acc62e4c2427e815ba9d69779.tar.gz
hercules-f4edc7e4431b929acc62e4c2427e815ba9d69779.tar.bz2
hercules-f4edc7e4431b929acc62e4c2427e815ba9d69779.tar.xz
hercules-f4edc7e4431b929acc62e4c2427e815ba9d69779.zip
- Cleaned up the implementation of map_foreachinmovearea so that the number of arguments passed is less.
- Moved setting a mob's chase/attack states from the mob_ai to unit_attack and unit_walktobl. - Cleaned the change-target/cast-sensor code to account for the new mob modes. - Cleaned up a bit the mob ai sub hard function. - Made the monster_active_enable config setting take effect on mob load. - Updated the doc explaining mob modes. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9422 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map/mob.c')
-rw-r--r--src/map/mob.c233
1 files changed, 116 insertions, 117 deletions
diff --git a/src/map/mob.c b/src/map/mob.c
index 5f22c8212..fb26a9d26 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -726,13 +726,12 @@ static int mob_can_changetarget(struct mob_data* md, struct block_list* target,
}
switch (md->state.skillstate) {
- case MSS_BERSERK: //Only Assist, Angry or Aggressive+CastSensor mobs can change target while attacking.
- if (mode&(MD_ASSIST|MD_ANGRY|MD_CHANGETARGET) || (mode&(MD_AGGRESSIVE|MD_CASTSENSOR)) == (MD_AGGRESSIVE|MD_CASTSENSOR))
- return (battle_config.mob_ai&0x4 || check_distance_bl(&md->bl, target, 3));
- else
+ case MSS_BERSERK:
+ if (!mode&MD_CHANGETARGET_MELEE)
return 0;
+ return (battle_config.mob_ai&0x4 || check_distance_bl(&md->bl, target, 3));
case MSS_RUSH:
- return (mode&MD_AGGRESSIVE);
+ return (mode&MD_CHANGETARGET_CHASE);
case MSS_FOLLOW:
case MSS_ANGRY:
case MSS_IDLE:
@@ -1156,7 +1155,6 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
{ //Change if the new target is closer than the actual one
//or if the previous target is not attacking the mob. [Skotlex]
md->target_id = md->attacked_id; // set target
- md->state.aggressive = 0; //Retaliating.
if (md->attacked_count)
md->attacked_count--; //Should we reset rude attack count?
md->min_chase = dist+md->db->range3;
@@ -1167,7 +1165,13 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
}
}
if (md->state.aggressive && md->attacked_id == md->target_id)
- md->state.aggressive = 0; //No longer aggressive, change to retaliate AI.
+ { //No longer aggressive, change to retaliate AI.
+ md->state.aggressive = 0;
+ if(md->state.skillstate== MSS_ANGRY)
+ md->state.skillstate = MSS_BERSERK;
+ if(md->state.skillstate== MSS_FOLLOW)
+ md->state.skillstate = MSS_RUSH;
+ }
//Clear it since it's been checked for already.
md->attacked_players = 0;
md->attacked_id = 0;
@@ -1185,135 +1189,126 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
view_range, BL_ITEM, md, &tbl);
}
- if ((!tbl && mode&MD_AGGRESSIVE && battle_config.monster_active_enable) ||
- (mode&MD_ANGRY && md->state.skillstate == MSS_FOLLOW)
- ) {
+ if ((!tbl && mode&MD_AGGRESSIVE) || md->state.skillstate == MSS_FOLLOW)
+ {
map_foreachinrange (mob_ai_sub_hard_activesearch, &md->bl,
view_range, md->special_state.ai?BL_CHAR:BL_PC|BL_HOM, md, &tbl);
- if(!tbl && mode&MD_ANGRY && !md->state.aggressive)
- md->state.aggressive = 1; //Restore angry state when no targets are visible.
- } else if (mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW)) {
+ } else
+ if (mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW))
+ {
search_size = view_range<md->status.rhw.range ? view_range:md->status.rhw.range;
map_foreachinrange (mob_ai_sub_hard_changechase, &md->bl,
search_size, (md->special_state.ai?BL_CHAR:BL_PC|BL_HOM), md, &tbl);
}
- if (tbl)
- { //Target exists, attack or loot as applicable.
- if (tbl->type != BL_ITEM)
- { //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)
- {
- if (md->state.skillstate!=(md->state.aggressive?MSS_ANGRY:MSS_BERSERK))
- md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK; //Correct the state.
- return 0; //Already locked.
- }
-
- if (!battle_check_range (&md->bl, tbl, md->status.rhw.range))
- { //Out of range...
- if (!(mode&MD_CANMOVE))
- { //Can't chase. Attempt to use a ranged skill at least?
- md->state.skillstate = MSS_IDLE;
- if (!mobskill_use(md, tick, -1))
- mob_unlocktarget(md,tick);
- return 0;
- }
+ if (!tbl) { //No targets available.
+ if (mode&MD_ANGRY && !md->state.aggressive)
+ md->state.aggressive = 1; //Restore angry state when no targets are available.
- if (!can_move)
- { //Stuck. Use an idle skill. o.O'
- md->state.skillstate = MSS_IDLE;
- if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL))
- mobskill_use(md, tick, -1);
- return 0;
- }
-
- md->state.skillstate = md->state.aggressive?MSS_FOLLOW:MSS_RUSH;
- if (md->ud.walktimer != -1 && md->ud.target == tbl->id &&
- (
- !(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;
-
- //Follow up
- if (!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) ||
- !unit_walktobl(&md->bl, tbl, md->status.rhw.range, 2))
- //Give up.
- mob_unlocktarget(md,tick);
+ if(md->ud.walktimer == -1) {
+ // Idle skill.
+ md->state.skillstate = MSS_IDLE;
+ if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL) && mobskill_use(md, tick, -1))
return 0;
- }
- //Target within range, engage
- md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK;
- unit_attack(&md->bl,tbl->id,1);
+ }
+ // Random walk.
+ if (can_move && !md->master_id && DIFF_TICK(md->next_walktime, tick) <= 0)
+ mob_randomwalk(md,tick);
+ return 0;
+ }
+
+ //Target exists, attack or loot as applicable.
+ if (tbl->type == BL_ITEM)
+ { //Loot time.
+ struct flooritem_data *fitem;
+ if (md->ud.target == tbl->id && md->ud.walktimer != -1)
+ return 0; //Already locked.
+ if (md->lootitem == NULL)
+ { //Can't loot...
+ mob_unlocktarget (md, tick);
+ mob_stop_walking(md,0);
return 0;
- } else { //Target is BL_ITEM, attempt loot.
- struct flooritem_data *fitem;
- int i;
- if (md->ud.target == tbl->id && md->ud.walktimer != -1)
- return 0; //Already locked.
- if (md->lootitem == NULL)
- { //Can't loot...
- mob_unlocktarget (md, tick);
- mob_stop_walking(md,0);
+ }
+ 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;
}
-
- 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;
- }
- if (!can_move) //Stuck. Wait before walking.
- return 0;
- md->state.skillstate = MSS_LOOT; // ルート時スキル使用
- if (!unit_walktobl(&md->bl, tbl, 0, 1))
- mob_unlocktarget(md, tick); //Can't loot...
+ if (!can_move) //Stuck. Wait before walking.
return 0;
- }
- //Within looting range.
- if (md->ud.attacktimer != -1)
- return 0; //Busy attacking?
-
- fitem = (struct flooritem_data *)tbl;
- if (md->lootitem_count < LOOTITEM_SIZE) {
- memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0]));
- if(log_config.enable_logs&0x10) //Logs items, taken by (L)ooter Mobs [Lupus]
- log_pick_mob(md, "L", md->lootitem[md->lootitem_count-1].nameid, md->lootitem[md->lootitem_count-1].amount, &md->lootitem[md->lootitem_count-1]);
- } else { //Destroy first looted item...
- if (md->lootitem[0].card[0] == (short)0xff00)
- intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) );
- for (i = 0; i < LOOTITEM_SIZE - 1; i++)
- memcpy (&md->lootitem[i], &md->lootitem[i+1], sizeof(md->lootitem[0]));
- memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item_data, sizeof(md->lootitem[0]));
- }
- //Clear item.
- if (pcdb_checkid(md->vd->class_))
- { //Give them walk act/delay to properly mimic players. [Skotlex]
- clif_takeitem(&md->bl,tbl);
- md->ud.canact_tick = tick + md->status.amotion;
- unit_set_walkdelay(&md->bl, tick, md->status.amotion, 1);
- }
- map_clearflooritem (tbl->id);
- mob_unlocktarget (md,tick);
+ md->state.skillstate = MSS_LOOT;
+ if (!unit_walktobl(&md->bl, tbl, 0, 1))
+ mob_unlocktarget(md, tick); //Can't loot...
return 0;
}
+ //Within looting range.
+ if (md->ud.attacktimer != -1)
+ return 0; //Busy attacking?
+
+ fitem = (struct flooritem_data *)tbl;
+ if(log_config.enable_logs&0x10) //Logs items, taken by (L)ooter Mobs [Lupus]
+ log_pick_mob(md, "L", fitem->item_data.nameid, fitem->item_data.amount, &fitem->item_data);
+
+ if (md->lootitem_count < LOOTITEM_SIZE) {
+ memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0]));
+ } else { //Destroy first looted item...
+ if (md->lootitem[0].card[0] == CARD0_PET)
+ intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) );
+ memmove(&md->lootitem[0], &md->lootitem[1], sizeof(md->lootitem) - sizeof(md->lootitem[0]));
+ memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item_data, sizeof(md->lootitem[0]));
+ }
+ if (pcdb_checkid(md->vd->class_))
+ { //Give them walk act/delay to properly mimic players. [Skotlex]
+ clif_takeitem(&md->bl,tbl);
+ md->ud.canact_tick = tick + md->status.amotion;
+ unit_set_walkdelay(&md->bl, tick, md->status.amotion, 1);
+ }
+ //Clear item.
+ map_clearflooritem (tbl->id);
+ mob_unlocktarget (md,tick);
+ return 0;
+ }
+ //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;
+
+ if (battle_check_range (&md->bl, tbl, md->status.rhw.range))
+ { //Target within range, engage
+ unit_attack(&md->bl,tbl->id,1);
+ return 0;
}
- if(md->ud.walktimer == -1) {
- // When there's no target, it is idling.
- // Is it terribly exploitable to reuse the walkcounter for idle state skills? [Skotlex]
+ //Out of range...
+ if (!(mode&MD_CANMOVE))
+ { //Can't chase. Attempt an idle skill before unlocking.
md->state.skillstate = MSS_IDLE;
- if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL) && mobskill_use(md, tick, -1))
- return 0;
+ if (!mobskill_use(md, tick, -1))
+ mob_unlocktarget(md,tick);
+ return 0;
}
- // Nothing else to do... except random walking.
- // Slaves do not random walk! [Skotlex]
- if (can_move && !md->master_id && DIFF_TICK(md->next_walktime, tick) <= 0)
- mob_randomwalk(md,tick);
+ if (!can_move)
+ { //Stuck. Attempt an idle skill
+ md->state.skillstate = MSS_IDLE;
+ if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL))
+ mobskill_use(md, tick, -1);
+ return 0;
+ }
+
+ if (md->ud.walktimer != -1 && md->ud.target == tbl->id &&
+ (
+ !(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;
+
+ //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 0;
}
@@ -3315,7 +3310,9 @@ static int mob_readdb(void)
ShowWarning("Mob with ID: %d has invalid element level %d (max is 4)\n", class_, status->ele_lv);
status->ele_lv = 1;
}
- status->mode=atoi(str[25]);
+ status->mode=(int)strtol(str[25],NULL,0);
+ if (!battle_config.monster_active_enable)
+ status->mode&=~MD_AGGRESSIVE;
status->speed=atoi(str[26]);
status->aspd_rate = 1000;
db->min_thinktime=atoi(str[27]);
@@ -4002,6 +3999,8 @@ static int mob_read_sqldb(void)
status->ele_lv = 1;
}
status->mode = TO_INT(25);
+ if (!battle_config.monster_active_enable)
+ status->mode&=~MD_AGGRESSIVE;
status->speed = TO_INT(26);
status->aspd_rate = 1000;
db->min_thinktime = TO_INT(27);