- Modified the unit_data structure to handle automatically switching between chasing and attacking a character. Note that it's a work in progress and not yet properly tested/finished...
git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@5979 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
parent
b6fa7be9e9
commit
418c98ea0a
@ -4,9 +4,14 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO
|
||||
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
|
||||
|
||||
2006/04/10
|
||||
- Updated the subnet support to not require specifying the subnet mask, it
|
||||
* Modified the unit_data structure to handle automatically switching
|
||||
between chasing and attacking a character. Note that it's a work in
|
||||
progress and not yet properly tested/finished... [Skotlex]
|
||||
- DON'T USE THIS YET. There's much testing that needs be done, but I had to
|
||||
commit now so I may continue work on it later....
|
||||
* Updated the subnet support to not require specifying the subnet mask, it
|
||||
is auto-acquired from the char/map IP and the subnet-mask. [Skotlex]
|
||||
- skill_wall_check defaults to yes now. [Skotlex]
|
||||
* skill_wall_check defaults to yes now. [Skotlex]
|
||||
2006/04/09
|
||||
* Added the missing last_thinktime initialization to pets. [Skotlex]
|
||||
* Reverted the change in skill_wall_check to let skills go over pits.
|
||||
|
@ -1412,7 +1412,7 @@ int map_search_freecell(struct block_list *src, int m, int *x,int *y, int rx, in
|
||||
|
||||
if (map_getcell(m,*x,*y,CELL_CHKREACH))
|
||||
{
|
||||
if(flag&2 && !unit_can_reach(src, *x, *y))
|
||||
if(flag&2 && !unit_can_reach_pos(src, *x, *y, 1))
|
||||
continue;
|
||||
if(flag&4 && spawn++ < battle_config.no_spawn_on_player &&
|
||||
map_foreachinarea(map_count_sub, m,
|
||||
|
@ -359,7 +359,9 @@ struct unit_data {
|
||||
int skilltimer;
|
||||
int attacktarget;
|
||||
int attacktimer;
|
||||
int walktarget;
|
||||
int walktimer;
|
||||
int chaserange;
|
||||
unsigned int attackabletime;
|
||||
unsigned int canact_tick;
|
||||
unsigned int canmove_tick;
|
||||
|
171
src/map/mob.c
171
src/map/mob.c
@ -515,9 +515,7 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
|
||||
*/
|
||||
int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state)
|
||||
{
|
||||
int dx,dy;
|
||||
struct walkpath_data wpd;
|
||||
int i, easy = 0;
|
||||
int easy = 0;
|
||||
|
||||
nullpo_retr(0, md);
|
||||
nullpo_retr(0, bl);
|
||||
@ -531,41 +529,7 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state
|
||||
easy = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if( md->bl.m != bl->m) // ˆá‚¤ƒƒbƒv
|
||||
return 0;
|
||||
|
||||
if( md->bl.x==bl->x && md->bl.y==bl->y ) // “¯‚¶ƒ}ƒX
|
||||
return 1;
|
||||
|
||||
if( range>0 && !check_distance_bl(&md->bl, bl, range))
|
||||
return 0;
|
||||
|
||||
// Obstacle judging
|
||||
wpd.path_len=0;
|
||||
wpd.path_pos=0;
|
||||
wpd.path_half=0;
|
||||
if(path_search_real(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x,bl->y,easy,CELL_CHKNOREACH)!=-1)
|
||||
return 1;
|
||||
|
||||
// It judges whether it can adjoin or not.
|
||||
dx=bl->x - md->bl.x;
|
||||
dy=bl->y - md->bl.y;
|
||||
dx=(dx>0)?1:((dx<0)?-1:0);
|
||||
dy=(dy>0)?1:((dy<0)?-1:0);
|
||||
if (map_getcell(md->bl.m,bl->x+dx,bl->y+dy,CELL_CHKNOREACH))
|
||||
{ //Look for a suitable cell to place in.
|
||||
for(i=0;i<9 && map_getcell(md->bl.m,bl->x-1+i/3,bl->y-1+i%3,CELL_CHKNOREACH);i++);
|
||||
if (i<9) {
|
||||
dx = 1-i/3;
|
||||
dy = 1-i%3;
|
||||
}
|
||||
}
|
||||
|
||||
if(path_search_real(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-dx,bl->y-dy,easy,CELL_CHKNOREACH)!=-1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return unit_can_reach_bl(&md->bl, bl, range, easy, NULL, NULL);
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
@ -952,24 +916,8 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
|
||||
(md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) &&
|
||||
unit_can_move(&md->bl))
|
||||
{
|
||||
int i=0,dx,dy;
|
||||
mob_stop_attack(md);
|
||||
do {
|
||||
if(i<=5){
|
||||
dx=bl->x - md->bl.x;
|
||||
dy=bl->y - md->bl.y;
|
||||
|
||||
if(dx<0) dx+=rand()%MOB_SLAVEDISTANCE +1;
|
||||
else if(dx>0) dx-=rand()%MOB_SLAVEDISTANCE +1;
|
||||
if(dy<0) dy+=rand()%MOB_SLAVEDISTANCE +1;
|
||||
else if(dy>0) dy-=rand()%MOB_SLAVEDISTANCE +1;
|
||||
|
||||
}else{
|
||||
old_dist = MOB_SLAVEDISTANCE*2+1;
|
||||
dx=bl->x - md->bl.x + rand()%old_dist - MOB_SLAVEDISTANCE;
|
||||
dy=bl->y - md->bl.y + rand()%old_dist - MOB_SLAVEDISTANCE;
|
||||
}
|
||||
} while(!unit_walktoxy(&md->bl,md->bl.x+dx,md->bl.y+dy,0)&& ++i<10);
|
||||
unit_walktobl(&md->bl, bl, MOB_SLAVEDISTANCE, 0);
|
||||
}
|
||||
} else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) {
|
||||
//Delete the summoned mob if it's in a gvg ground and the master is elsewhere. [Skotlex]
|
||||
@ -1033,7 +981,7 @@ int mob_randomwalk(struct mob_data *md,int tick)
|
||||
nullpo_retr(0, md);
|
||||
|
||||
speed=status_get_speed(&md->bl);
|
||||
if(DIFF_TICK(md->next_walktime,tick)<0){
|
||||
if(DIFF_TICK(md->next_walktime,tick)<0 && unit_can_move(&md->bl)){
|
||||
int i,x,y,c,d=12-md->move_fail_count;
|
||||
if(d<5) d=5;
|
||||
for(i=0;i<retrycount;i++){ // Search of a movable place
|
||||
@ -1079,7 +1027,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
|
||||
struct mob_data *md;
|
||||
struct block_list *tbl = NULL, *abl = NULL;
|
||||
unsigned int tick;
|
||||
int i, j, dx, dy, dist;
|
||||
int dist;
|
||||
int mode;
|
||||
int search_size;
|
||||
int view_range, can_move, can_walk;
|
||||
@ -1123,7 +1071,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
|
||||
tbl->type == BL_PC && !(mode&MD_BOSS) &&
|
||||
((struct map_session_data*)tbl)->state.gangsterparadise
|
||||
)) { //Unlock current target.
|
||||
if (md->ud.walktimer != -1 && (battle_config.mob_ai&8 || !tbl)) //Inmediately stop chasing.
|
||||
if (battle_config.mob_ai&8) //Inmediately stop chasing.
|
||||
mob_stop_walking(md,2);
|
||||
mob_unlocktarget(md, tick-(battle_config.mob_ai&8?3000:0)); //Imediately do random walk.
|
||||
tbl = NULL;
|
||||
@ -1234,91 +1182,27 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
|
||||
mob_unlocktarget(md,tick);
|
||||
return 0;
|
||||
}
|
||||
if (!check_distance_bl(&md->bl, tbl, view_range))
|
||||
{ //Run towards the enemy when out of range?
|
||||
if (!can_move)
|
||||
{ //Give it up.
|
||||
if (can_walk)
|
||||
mob_unlocktarget(md,tick);
|
||||
return 0;
|
||||
}
|
||||
dx = tbl->x+(tbl->x > md->bl.x?-1:+1);
|
||||
dy = tbl->y+(tbl->y > md->bl.y?-1:+1);
|
||||
unit_walktoxy(&md->bl, dx, dy, 0);
|
||||
return 0;
|
||||
}
|
||||
md->state.skillstate = md->state.aggressive?MSS_FOLLOW:MSS_RUSH;
|
||||
mobskill_use (md, tick, -1);
|
||||
if (!can_move) //Wait until you can move?
|
||||
return 0;
|
||||
if (md->ud.walktimer != -1 &&
|
||||
(!battle_config.mob_ai&1 ||
|
||||
check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, md->db->range)) //Current target tile is still within attack range.
|
||||
) {
|
||||
return 0; //No need to follow, already doing it?
|
||||
}
|
||||
md->state.skillstate = md->state.aggressive?MSS_FOLLOW:MSS_RUSH;
|
||||
if (md->ud.walktimer != -1 && md->ud.walktarget == tbl->id &&
|
||||
(
|
||||
!battle_config.mob_ai&1 ||
|
||||
check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, md->db->range)
|
||||
)) //Current target tile is still within attack range.
|
||||
return 0;
|
||||
//Target reachable. Locate suitable spot to move to.
|
||||
i = j = 0;
|
||||
dx = tbl->x - md->bl.x;
|
||||
dy = tbl->y - md->bl.y;
|
||||
if (dx < 0) dx=-1;
|
||||
else if (dx > 0) dx=1;
|
||||
if (dy < 0) dy=-1;
|
||||
else if (dy > 0) dy=1;
|
||||
if(!unit_walktoxy(&md->bl, tbl->x -dx, tbl->y -dy, 0)) {
|
||||
j = (dy+1) + 3*(dx+1);
|
||||
for (i = j+1; i%9 != j; i++) {
|
||||
dx = -1+(i%9)/3;
|
||||
dy = -1+(i%3);
|
||||
#ifdef CELL_NOSTACK
|
||||
if (map_getcell(md->bl.m, tbl->x-dx, tbl->y-dy, CELL_CHKSTACK))
|
||||
continue;
|
||||
#endif
|
||||
if (unit_walktoxy(&md->bl, tbl->x-dx, tbl->y-dy, 0))
|
||||
break;
|
||||
}
|
||||
#ifdef CELL_NOSTACK
|
||||
if (i%9 == j)
|
||||
{ //All adjacent cells are taken. Try roaming around on 5x5
|
||||
for (i = j+1; i%9 != j; i++) {
|
||||
dx = 2*(-1+(i%9)/3);
|
||||
dy = 2*(-1+(i%3));
|
||||
if (map_getcell(md->bl.m, tbl->x-dx, tbl->y-dy, CELL_CHKSTACK))
|
||||
continue;
|
||||
if (unit_walktoxy(&md->bl, tbl->x-dx, tbl->y-dy, 0)) {
|
||||
unit_set_walkdelay(&md->bl, tick, 1000, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i%9 == j)
|
||||
{
|
||||
//On stacked mode, it is much more likely that you just can't reach the target. So unlock it
|
||||
mob_unlocktarget(md, tick);
|
||||
unit_set_walkdelay(&md->bl, tick, 1000, 1);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (i%9 == j)
|
||||
{ //Failed? Try going to the other side of the target before retrying.
|
||||
if (dx < 0) dx = 2;
|
||||
else if (dx > 0) dx = -2;
|
||||
if (dy < 0) dy = 2;
|
||||
else if (dy > 0) dy = -2;
|
||||
unit_walktoxy (&md->bl, tbl->x+dx, tbl->y+dy, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
unit_walktobl(&md->bl, tbl, md->db->range, !battle_config.mob_ai&1);
|
||||
return 0;
|
||||
}
|
||||
//Target within range, engage
|
||||
md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK;
|
||||
mob_stop_walking(md,1);
|
||||
md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK;
|
||||
unit_attack(&md->bl,tbl->id,1);
|
||||
return 0;
|
||||
} else { //Target is BL_ITEM, attempt loot.
|
||||
struct flooritem_data *fitem;
|
||||
|
||||
int i;
|
||||
if (md->lootitem == NULL)
|
||||
{ //Can't loot...
|
||||
mob_unlocktarget (md, tick);
|
||||
@ -1335,15 +1219,10 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
|
||||
if (!can_move) // 動けない状態にある
|
||||
return 0;
|
||||
md->state.skillstate = MSS_LOOT; // ルート時スキル使用
|
||||
mobskill_use(md, tick, -1);
|
||||
if (md->ud.walktimer != -1 &&
|
||||
check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, 0))
|
||||
{ //Already on the way to looting.
|
||||
if (md->ud.walktimer != -1 && md->ud.walktarget == tbl->id)
|
||||
//Already on the way to looting.
|
||||
return 0;
|
||||
}
|
||||
dx = tbl->x - md->bl.x;
|
||||
dy = tbl->y - md->bl.y;
|
||||
if (!unit_walktoxy(&md->bl, md->bl.x+dx, md->bl.y+dy, 0))
|
||||
if (!unit_walktobl(&md->bl, tbl, 0, 1))
|
||||
mob_unlocktarget(md, tick); //Can't loot...
|
||||
return 0;
|
||||
}
|
||||
@ -1357,9 +1236,6 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
|
||||
memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0]));
|
||||
if(log_config.pick > 0) //Logs items, taken by (L)ooter Mobs [Lupus]
|
||||
log_pick((struct map_session_data*)md, "L", md->class_, md->lootitem[md->lootitem_count-1].nameid, md->lootitem[md->lootitem_count-1].amount, &md->lootitem[md->lootitem_count-1]);
|
||||
} else if (battle_config.monster_loot_type == 1) { //Can't loot, stuffed!
|
||||
mob_unlocktarget(md,tick);
|
||||
return 0;
|
||||
} 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]) );
|
||||
@ -1458,10 +1334,11 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list app)
|
||||
else if(rand()%1000<MOB_LAZYSKILLPERC) //Chance to do a mob's idle skill.
|
||||
mobskill_use(md, tick, -1);
|
||||
// MOB which is not not the summons MOB but BOSS, either sometimes reboils.
|
||||
else if( rand()%1000<MOB_LAZYWARPPERC
|
||||
&& (md->spawn && !md->spawn->x && !md->spawn->y)
|
||||
&& !md->target_id && !(mode&MD_BOSS))
|
||||
unit_warp(&md->bl,-1,-1,-1,0);
|
||||
// People don't want this, it seems custom, noone can prove it....
|
||||
// else if( rand()%1000<MOB_LAZYWARPPERC
|
||||
// && (md->spawn && !md->spawn->x && !md->spawn->y)
|
||||
// && !md->target_id && !(mode&MD_BOSS))
|
||||
// unit_warp(&md->bl,-1,-1,-1,0);
|
||||
}else{
|
||||
// Since PC is not even in the same map, suitable processing is carried out even if it takes.
|
||||
|
||||
|
33
src/map/pc.c
33
src/map/pc.c
@ -3821,26 +3821,23 @@ int pc_follow_timer(int tid,unsigned int tick,int id,int data)
|
||||
if (pc_isdead(sd))
|
||||
return 0;
|
||||
|
||||
if ((tsd = map_id2sd(sd->followtarget)) != NULL)
|
||||
{
|
||||
if (pc_isdead(tsd))
|
||||
return 0;
|
||||
if ((tsd = map_id2sd(sd->followtarget)) == NULL || pc_isdead(tsd))
|
||||
return 0;
|
||||
|
||||
// either player or target is currently detached from map blocks (could be teleporting),
|
||||
// but still connected to this map, so we'll just increment the timer and check back later
|
||||
if (sd->bl.prev != NULL && tsd->bl.prev != NULL &&
|
||||
sd->ud.skilltimer == -1 && sd->ud.attacktimer == -1 && sd->ud.walktimer == -1)
|
||||
{
|
||||
if((sd->bl.m == tsd->bl.m) && unit_can_reach(&sd->bl,tsd->bl.x,tsd->bl.y)) {
|
||||
if (!check_distance_bl(&sd->bl, &tsd->bl, 5) && unit_can_move(&sd->bl))
|
||||
unit_walktoxy(&sd->bl,tsd->bl.x,tsd->bl.y, 0);
|
||||
} else
|
||||
pc_setpos(sd, tsd->mapindex, tsd->bl.x, tsd->bl.y, 3);
|
||||
}
|
||||
sd->followtimer = add_timer(
|
||||
tick + sd->aspd + rand() % 1000, // increase time a bit to loosen up map's load
|
||||
pc_follow_timer, sd->bl.id, 0);
|
||||
// either player or target is currently detached from map blocks (could be teleporting),
|
||||
// but still connected to this map, so we'll just increment the timer and check back later
|
||||
if (sd->bl.prev != NULL && tsd->bl.prev != NULL &&
|
||||
sd->ud.skilltimer == -1 && sd->ud.attacktimer == -1 && sd->ud.walktimer == -1)
|
||||
{
|
||||
if((sd->bl.m == tsd->bl.m) && unit_can_reach_bl(&sd->bl,&tsd->bl, AREA_SIZE, 0, NULL, NULL)) {
|
||||
if (!check_distance_bl(&sd->bl, &tsd->bl, 5))
|
||||
unit_walktobl(&sd->bl, &tsd->bl, 5, 0);
|
||||
} else
|
||||
pc_setpos(sd, tsd->mapindex, tsd->bl.x, tsd->bl.y, 3);
|
||||
}
|
||||
sd->followtimer = add_timer(
|
||||
tick + sd->aspd + rand() % 1000, // increase time a bit to loosen up map's load
|
||||
pc_follow_timer, sd->bl.id, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -81,33 +81,33 @@ static int pet_calc_pos(struct pet_data *pd,int tx,int ty,int dir)
|
||||
dy = -diry[dir]*2;
|
||||
x = tx + dx;
|
||||
y = ty + dy;
|
||||
if(!unit_can_reach(&pd->bl,x,y)) {
|
||||
if(!unit_can_reach_pos(&pd->bl,x,y,0)) {
|
||||
if(dx > 0) x--;
|
||||
else if(dx < 0) x++;
|
||||
if(dy > 0) y--;
|
||||
else if(dy < 0) y++;
|
||||
if(!unit_can_reach(&pd->bl,x,y)) {
|
||||
if(!unit_can_reach_pos(&pd->bl,x,y,0)) {
|
||||
for(i=0;i<12;i++) {
|
||||
k = rand()%8;
|
||||
dx = -dirx[k]*2;
|
||||
dy = -diry[k]*2;
|
||||
x = tx + dx;
|
||||
y = ty + dy;
|
||||
if(unit_can_reach(&pd->bl,x,y))
|
||||
if(unit_can_reach_pos(&pd->bl,x,y,0))
|
||||
break;
|
||||
else {
|
||||
if(dx > 0) x--;
|
||||
else if(dx < 0) x++;
|
||||
if(dy > 0) y--;
|
||||
else if(dy < 0) y++;
|
||||
if(unit_can_reach(&pd->bl,x,y))
|
||||
if(unit_can_reach_pos(&pd->bl,x,y,0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i>=12) {
|
||||
x = tx;
|
||||
y = ty;
|
||||
if(!unit_can_reach(&pd->bl,x,y))
|
||||
if(!unit_can_reach_pos(&pd->bl,x,y,0))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -892,7 +892,7 @@ static int pet_randomwalk(struct pet_data *pd,unsigned int tick)
|
||||
|
||||
speed = status_get_speed(&pd->bl);
|
||||
|
||||
if(DIFF_TICK(pd->next_walktime,tick) < 0){
|
||||
if(DIFF_TICK(pd->next_walktime,tick) < 0 && unit_can_move(&pd->bl)) {
|
||||
int i,x,y,c,d=12-pd->move_fail_count;
|
||||
if(d<5) d=5;
|
||||
for(i=0;i<retrycount;i++){
|
||||
@ -931,7 +931,6 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
|
||||
{
|
||||
struct map_session_data *sd;
|
||||
struct block_list *target = NULL;
|
||||
int i=0,dx,dy;
|
||||
|
||||
sd = pd->msd;
|
||||
|
||||
@ -960,14 +959,13 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
|
||||
//Master too far, chase.
|
||||
if(pd->target_id)
|
||||
pet_unlocktarget(pd);
|
||||
if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
|
||||
if(pd->ud.walktimer != -1 && pd->ud.walktarget == sd->bl.id)
|
||||
return 0; //Already walking to him
|
||||
|
||||
pd->speed = (sd->speed>>1);
|
||||
if(pd->speed <= 0)
|
||||
pd->speed = 1;
|
||||
pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
|
||||
if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0))
|
||||
if (!unit_walktobl(&pd->bl, &sd->bl, 3, 0));
|
||||
pet_randomwalk(pd,tick);
|
||||
return 0;
|
||||
}
|
||||
@ -987,11 +985,12 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
|
||||
}
|
||||
|
||||
// ペットによるルート
|
||||
if(!pd->target_id && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0)
|
||||
if(!target && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) {
|
||||
//Use half the pet's range of sight.
|
||||
int itc=0;
|
||||
map_foreachinrange(pet_ai_sub_hard_lootsearch,&pd->bl,
|
||||
pd->db->range2/2, BL_ITEM,pd,&i);
|
||||
|
||||
pd->db->range2/2, BL_ITEM,pd,&itc);
|
||||
}
|
||||
if (!target) {
|
||||
//Just walk around.
|
||||
if (check_distance_bl(&sd->bl, &pd->bl, 3))
|
||||
@ -1014,51 +1013,26 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
|
||||
if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x,pd->ud.to_y, pd->db->range))
|
||||
return 0;
|
||||
|
||||
if(!unit_can_reach(&pd->bl, target->x, target->y))
|
||||
if(!unit_walktobl(&pd->bl, target, pd->db->range, 2))
|
||||
{ //Unreachable target.
|
||||
pet_unlocktarget(pd);
|
||||
return 0;
|
||||
}
|
||||
i=0;
|
||||
do {
|
||||
if(i==0) { // 最初はAEGISと同じ方法で検索
|
||||
dx=target->x - pd->bl.x;
|
||||
dy=target->y - pd->bl.y;
|
||||
if(dx<0) dx++;
|
||||
else if(dx>0) dx--;
|
||||
if(dy<0) dy++;
|
||||
else if(dy>0) dy--;
|
||||
}
|
||||
else { // だめならAthena式(ランダム)
|
||||
dx=target->x - pd->bl.x + rand()%3 - 1;
|
||||
dy=target->y - pd->bl.y + rand()%3 - 1;
|
||||
}
|
||||
} while(!unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0) && ++i<5);
|
||||
|
||||
if(i>=5) {
|
||||
if(dx<0) dx=2;
|
||||
else if(dx>0) dx=-2;
|
||||
if(dy<0) dy=2;
|
||||
else if(dy>0) dy=-2;
|
||||
unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0);
|
||||
}
|
||||
return 0;
|
||||
} //End Chase
|
||||
pet_stop_walking(pd,1);
|
||||
if (pd->ud.attacktimer != -1 && pd->ud.attacktarget == pd->target_id)
|
||||
return 0; //Already attacking.
|
||||
//Continuous attack.
|
||||
unit_attack(&pd->bl, pd->target_id, 1);
|
||||
} else { //Item Targeted, attempt loot
|
||||
if (!check_distance_bl(&pd->bl, target, 1))
|
||||
{ //Out of range
|
||||
if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x, pd->ud.to_y, 0))
|
||||
return 0; // 既に移動中
|
||||
|
||||
if(!unit_can_reach(&pd->bl, target->x, target->y))
|
||||
{ //Unreachable target.
|
||||
pet_unlocktarget(pd);
|
||||
if(pd->ud.walktimer != -1 && pd->ud.walktarget == pd->target_id)
|
||||
return 0;
|
||||
}
|
||||
unit_walktoxy(&pd->bl, target->x, target->y, 1);
|
||||
|
||||
if(!unit_walktobl(&pd->bl, target, 0, 1)) //Unreachable target.
|
||||
pet_unlocktarget(pd);
|
||||
return 0;
|
||||
} else{ // アイテムまでたどり着いた
|
||||
struct flooritem_data *fitem = (struct flooritem_data *)target;
|
||||
pet_stop_walking(pd,1);
|
||||
@ -1109,8 +1083,8 @@ int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
|
||||
if(pd->loot == NULL || pd->loot->item == NULL || (pd->loot->count >= pd->loot->max) ||
|
||||
(sd_id && pd->msd && pd->msd->bl.id != sd_id))
|
||||
return 0;
|
||||
if(bl->m == pd->bl.m && check_distance_bl(&pd->bl, bl, pd->db->range2) &&
|
||||
unit_can_reach(&pd->bl,bl->x,bl->y) && rand()%1000<1000/(++(*itc)))
|
||||
if(bl->m == pd->bl.m && unit_can_reach_bl(&pd->bl,bl, pd->db->range2, 1, NULL, NULL)
|
||||
&& rand()%1000<1000/(++(*itc)))
|
||||
pd->target_id=bl->id;
|
||||
return 0;
|
||||
}
|
||||
|
@ -41,6 +41,10 @@
|
||||
#define INF2_PARTY_ONLY 1024
|
||||
#define INF2_GUILD_ONLY 2048
|
||||
|
||||
//Walk intervals at which chase-skills are attempted to be triggered.
|
||||
//Note that every 2 is an actual cell walked.
|
||||
#define WALK_SKILL_INTERVAL 6
|
||||
|
||||
// スキルデ?タベ?ス
|
||||
struct skill_db {
|
||||
char *name;
|
||||
|
227
src/map/unit.c
227
src/map/unit.c
@ -57,12 +57,12 @@ int unit_walktoxy_sub(struct block_list *bl)
|
||||
|
||||
memcpy(&ud->walkpath,&wpd,sizeof(wpd));
|
||||
|
||||
ud->state.change_walk_target=0;
|
||||
|
||||
if (bl->type == BL_PC)
|
||||
clif_walkok((TBL_PC*)bl);
|
||||
clif_move(bl);
|
||||
|
||||
ud->state.change_walk_target=0;
|
||||
|
||||
if(ud->walkpath.path_pos>=ud->walkpath.path_len)
|
||||
i = -1;
|
||||
else if(ud->walkpath.path[ud->walkpath.path_pos]&1)
|
||||
@ -143,9 +143,6 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
|
||||
x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,
|
||||
dx,dy,sd?BL_ALL:BL_PC,bl);
|
||||
|
||||
if(md && md->min_chase > md->db->range2)
|
||||
md->min_chase--;
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
map_moveblock(bl, x, y, tick);
|
||||
@ -178,11 +175,19 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
|
||||
if (
|
||||
(sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR &&
|
||||
sd->sc.data[SC_MIRACLE].timer==-1 &&
|
||||
rand()%100000 < battle_config.sg_miracle_skill_ratio
|
||||
!ud->walkpath.path_pos%WALK_SKILL_INTERVAL &&
|
||||
rand()%10000 < battle_config.sg_miracle_skill_ratio
|
||||
) { //SG_MIRACLE [Komurka]
|
||||
clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]");
|
||||
sc_start(&sd->bl,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration);
|
||||
}
|
||||
} else if (md) {
|
||||
if (ud->attacktarget) {
|
||||
if(md->min_chase > md->db->range2) md->min_chase--;
|
||||
if(!ud->walkpath.path_pos%WALK_SKILL_INTERVAL &&
|
||||
mobskill_use(md, tick, -1))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,8 +205,23 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
|
||||
ud->walktimer = add_timer(tick+i,unit_walktoxy_timer,id,ud->walkpath.path_pos);
|
||||
} else if(sd && sd->sc.count && sd->sc.data[SC_RUN].timer!=-1) //Keep trying to run.
|
||||
pc_run(sd, sd->sc.data[SC_RUN].val1, sd->sc.data[SC_RUN].val2);
|
||||
else
|
||||
{ //Stopped walking. Update to_x and to_y to current location [Skotlex]
|
||||
else if (ud->walktarget) {
|
||||
//Update target trajectory.
|
||||
struct block_list *tbl = map_id2bl(ud->walktarget);
|
||||
if (!tbl) { //Cancel chase.
|
||||
ud->to_x = bl->x;
|
||||
ud->to_y = bl->y;
|
||||
return 0;
|
||||
}
|
||||
if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange))
|
||||
{ //Reached destination.
|
||||
if (ud->attacktarget == tbl->id)
|
||||
unit_attack(bl, tbl->id, ud->state.attack_continue);
|
||||
} else { //Update chase-path
|
||||
unit_walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy);
|
||||
return 0;
|
||||
}
|
||||
} else { //Stopped walking. Update to_x and to_y to current location [Skotlex]
|
||||
ud->to_x = bl->x;
|
||||
ud->to_y = bl->y;
|
||||
// if (bl->type == BL_NPC) //Original eA code had this one only for BL_NPCs
|
||||
@ -221,10 +241,11 @@ int unit_walktoxy( struct block_list *bl, int x, int y, int easy) {
|
||||
if( ud == NULL) return 0;
|
||||
|
||||
// 移動出来ないユニットは弾く
|
||||
if(!unit_can_move(bl) || !(status_get_mode(bl)&MD_CANMOVE) )
|
||||
if(!(status_get_mode(bl)&MD_CANMOVE) || !unit_can_move(bl))
|
||||
return 0;
|
||||
|
||||
ud->state.walk_easy = easy;
|
||||
ud->walktarget = 0;
|
||||
ud->to_x = x;
|
||||
ud->to_y = y;
|
||||
|
||||
@ -242,6 +263,87 @@ int unit_walktoxy( struct block_list *bl, int x, int y, int easy) {
|
||||
}
|
||||
}
|
||||
|
||||
static int unit_walktobl_sub(int tid,unsigned int tick,int id,int data)
|
||||
{
|
||||
struct block_list *bl = map_id2bl(id);
|
||||
struct unit_data *ud = bl?unit_bl2ud(bl):NULL;
|
||||
|
||||
if (ud && ud->walktimer == -1 && ud->walktarget == data)
|
||||
{
|
||||
if (DIFF_TICK(ud->canmove_tick, tick) > 0) //Keep waiting?
|
||||
add_timer(ud->canmove_tick+1, unit_walktobl_sub, id, data);
|
||||
else if (unit_can_move(bl))
|
||||
unit_walktoxy_sub(bl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Chases a tbl. If the flag&1, use hard-path seek,
|
||||
// if flag&2, start attacking upon arrival within range.
|
||||
int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int flag) {
|
||||
struct unit_data *ud = NULL;
|
||||
struct status_change *sc = NULL;
|
||||
int i;
|
||||
nullpo_retr(0, bl);
|
||||
nullpo_retr(0, tbl);
|
||||
|
||||
ud = unit_bl2ud(bl);
|
||||
if( ud == NULL) return 0;
|
||||
|
||||
if (!(status_get_mode(bl)&MD_CANMOVE))
|
||||
return 0;
|
||||
|
||||
i = distance_bl(bl, tbl)+1;
|
||||
if (!unit_can_reach_bl(bl, tbl, i, flag&1, &ud->to_x, &ud->to_y)) {
|
||||
ud->to_x = bl->x;
|
||||
ud->to_y = bl->y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ud->state.walk_easy = flag&1;
|
||||
ud->walktarget = tbl->id;
|
||||
ud->chaserange = range;
|
||||
|
||||
if (range) {
|
||||
//Adjust target cell
|
||||
if (i < range) {
|
||||
//We are already within required distance!
|
||||
if (flag&2) //Attack
|
||||
unit_attack(bl, tbl->id, 1);
|
||||
return 1;
|
||||
}
|
||||
//Trim the last part of the path to account for range.
|
||||
for (i = 1; i <= range && ud->walkpath.path_len>0; i++) {
|
||||
int dir;
|
||||
ud->walkpath.path_len--;
|
||||
dir = ud->walkpath.path[ud->walkpath.path_len];
|
||||
ud->to_x -= dirx[dir];
|
||||
ud->to_y -= diry[dir];
|
||||
}
|
||||
}
|
||||
sc = status_get_sc(bl);
|
||||
if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position
|
||||
map_random_dir(bl, &ud->to_x, &ud->to_y);
|
||||
|
||||
if (flag&2) { //Chase to attack.
|
||||
ud->attacktarget = tbl->id;
|
||||
ud->state.attack_continue = 1;
|
||||
}
|
||||
|
||||
if(ud->walktimer != -1) {
|
||||
ud->state.change_walk_target = 1;
|
||||
return 1;
|
||||
}
|
||||
if (DIFF_TICK(ud->canmove_tick, gettick()) > 0)
|
||||
{ //Can't move, wait a bit before invoking the movement.
|
||||
add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->walktarget);
|
||||
return 1;
|
||||
} else if (!unit_can_move(bl))
|
||||
return 0;
|
||||
|
||||
return unit_walktoxy_sub(bl);
|
||||
}
|
||||
|
||||
//Instant warp function.
|
||||
int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath)
|
||||
{
|
||||
@ -543,6 +645,13 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int
|
||||
return 0;
|
||||
}
|
||||
ud->canmove_tick = tick + delay;
|
||||
if (ud->walktimer != -1)
|
||||
{ //Stop walking, if chasing, readjust timers.
|
||||
delete_timer(ud->walktimer, unit_walktoxy_timer);
|
||||
clif_fixpos(bl);
|
||||
if(ud->walktarget)
|
||||
add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->walktarget);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -552,8 +661,7 @@ static int unit_walkdelay_sub(int tid, unsigned int tick, int id, int data)
|
||||
if (!bl || status_isdead(bl))
|
||||
return 0;
|
||||
|
||||
if (unit_set_walkdelay(bl, tick, data, 0))
|
||||
unit_stop_walking(bl,3);
|
||||
unit_set_walkdelay(bl, tick, data, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -954,7 +1062,11 @@ int unit_stop_attack(struct block_list *bl)
|
||||
//Means current target is unattackable. For now only unlocks mobs.
|
||||
int unit_unattackable(struct block_list *bl) {
|
||||
struct unit_data *ud = unit_bl2ud(bl);
|
||||
if (ud) ud->attacktarget = 0;
|
||||
if (ud) {
|
||||
ud->attacktarget = 0;
|
||||
ud->walktarget = 0;
|
||||
}
|
||||
|
||||
if(bl->type == BL_MOB)
|
||||
mob_unlocktarget((struct mob_data*)bl, gettick()) ;
|
||||
else if(bl->type == BL_PET)
|
||||
@ -995,6 +1107,11 @@ int unit_attack(struct block_list *src,int target_id,int type)
|
||||
|
||||
ud->attacktarget = target_id;
|
||||
ud->state.attack_continue = type;
|
||||
if (type) { //If you re to attack continously, set to auto-case character
|
||||
ud->walktarget = target_id;
|
||||
ud->chaserange = status_get_range(src);
|
||||
}
|
||||
|
||||
//Just change target/type. [Skotlex]
|
||||
if(ud->attacktimer != -1)
|
||||
return 0;
|
||||
@ -1012,7 +1129,7 @@ int unit_attack(struct block_list *src,int target_id,int type)
|
||||
*
|
||||
*------------------------------------------
|
||||
*/
|
||||
int unit_can_reach(struct block_list *bl,int x,int y)
|
||||
int unit_can_reach_pos(struct block_list *bl,int x,int y, int easy)
|
||||
{
|
||||
struct walkpath_data wpd;
|
||||
|
||||
@ -1025,9 +1142,63 @@ int unit_can_reach(struct block_list *bl,int x,int y)
|
||||
wpd.path_len=0;
|
||||
wpd.path_pos=0;
|
||||
wpd.path_half=0;
|
||||
return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,0,CELL_CHKNOREACH)!=-1)?1:0;
|
||||
return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH)!=-1);
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
*
|
||||
*------------------------------------------
|
||||
*/
|
||||
int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y)
|
||||
{
|
||||
struct walkpath_data wpd;
|
||||
int i;
|
||||
short dx,dy;
|
||||
nullpo_retr(0, bl);
|
||||
nullpo_retr(0, tbl);
|
||||
|
||||
if( bl->m != tbl->m)
|
||||
return 0;
|
||||
|
||||
if( bl->x==tbl->x && bl->y==tbl->y )
|
||||
return 1;
|
||||
|
||||
if(range>0 && !check_distance_bl(bl, tbl, range))
|
||||
return 0;
|
||||
|
||||
wpd.path_len=0;
|
||||
wpd.path_pos=0;
|
||||
wpd.path_half=0;
|
||||
|
||||
#ifndef CELL_NOSTACK
|
||||
//Skip direct path seeking when in nostacking mode.
|
||||
if(path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x,tbl->y,easy,CELL_CHKNOREACH)!=-1) {
|
||||
if (x) *x = tbl->x;
|
||||
if (y) *y = tbl->y;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// It judges whether it can adjoin or not.
|
||||
dx=tbl->x - bl->x;
|
||||
dy=tbl->y - bl->y;
|
||||
dx=(dx>0)?1:((dx<0)?-1:0);
|
||||
dy=(dy>0)?1:((dy<0)?-1:0);
|
||||
|
||||
if (map_getcell(tbl->m,tbl->x+dx,tbl->y+dy,CELL_CHKNOREACH))
|
||||
{ //Look for a suitable cell to place in.
|
||||
for(i=0;i<9 && map_getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOREACH);i++);
|
||||
if (i==9) return 0; //No valid cells.
|
||||
dx = dirx[i];
|
||||
dy = diry[i];
|
||||
}
|
||||
|
||||
if (x) *x = tbl->x-dx;
|
||||
if (y) *y = tbl->y-dy;
|
||||
return (path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH)!=-1);
|
||||
}
|
||||
|
||||
|
||||
/*==========================================
|
||||
* PCの攻撃 (timer関数)
|
||||
*------------------------------------------
|
||||
@ -1078,23 +1249,29 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
|
||||
return 1;
|
||||
}
|
||||
|
||||
range = status_get_range( src );
|
||||
range = status_get_range(src);
|
||||
|
||||
if(ud->walktimer != -1) range++; //Extra range when walking.
|
||||
if(!sd || sd->status.weapon != 11) range++; //Dunno why everyone but bows gets this extra range...
|
||||
if(unit_is_walking(target)) range++; //Extra range when chasing
|
||||
|
||||
if(!check_distance_bl(src,target,range) ) {
|
||||
if(!unit_can_reach(src,target->x,target->y))
|
||||
return 0;
|
||||
if(sd) clif_movetoattack(sd,target);
|
||||
return 1;
|
||||
//Chase if required.
|
||||
if(ud->state.attack_continue && ud->walktarget == target->id) {
|
||||
if(sd)
|
||||
clif_movetoattack(sd,target);
|
||||
else
|
||||
unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if(!battle_check_range(src,target,range)) { //Within range, but no direct line of attack
|
||||
if(unit_can_reach(src,target->x,target->y))
|
||||
unit_walktoxy(src,target->x,target->y, ud->state.walk_easy);
|
||||
if(ud->state.attack_continue)
|
||||
if(!battle_check_range(src,target,range)) {
|
||||
//Within range, but no direct line of attack
|
||||
if(ud->state.attack_continue && ud->walktarget == target->id) {
|
||||
if(ud->chaserange > 2) ud->chaserange-=2;
|
||||
unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy);
|
||||
ud->attacktimer = add_timer(tick + status_get_adelay(src),unit_attack_timer,src->id,0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1141,7 +1318,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
|
||||
|
||||
// You can't move if you can't attack neither.
|
||||
// Only for non-players, since it makes it near impossible to run away when you are on auto-attack.
|
||||
if (src->type != BL_PC)
|
||||
if (src->type != BL_PC)
|
||||
unit_set_walkdelay(src, tick, status_get_amotion(src), 1);
|
||||
}
|
||||
|
||||
@ -1604,6 +1781,8 @@ int do_init_unit(void) {
|
||||
add_timer_func_list(unit_attack_timer, "unit_attack_timer");
|
||||
add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer");
|
||||
add_timer_func_list(unit_walkdelay_sub, "unit_walkdelay_sub");
|
||||
add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
// 歩行開始
|
||||
// 戻り値は、0 ( 成功 ), 1 ( 失敗 )
|
||||
int unit_walktoxy( struct block_list *bl, int x, int y, int easy);
|
||||
int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy);
|
||||
|
||||
// 歩行停止
|
||||
// typeは以下の組み合わせ :
|
||||
@ -31,7 +32,8 @@ int unit_setdir(struct block_list *bl,unsigned char dir);
|
||||
int unit_getdir(struct block_list *bl);
|
||||
|
||||
// そこまで歩行でたどり着けるかの判定
|
||||
int unit_can_reach(struct block_list *bl,int x,int y);
|
||||
int unit_can_reach_pos(struct block_list *bl,int x,int y,int easy);
|
||||
int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y);
|
||||
|
||||
// 攻撃関連
|
||||
int unit_stop_attack(struct block_list *bl);
|
||||
|
Loading…
x
Reference in New Issue
Block a user