- Some cleanup of how mobcount works.

- status_calc_misc will now be invoked in status_calc_bl even on the first call, since status could have gone up due to skill bonuses.
- Moved max HP/SP calculations to before invoking status_calc_misc
- Simplified distance and check_distance to use "aegis" methods (greater of dx/dy = distance), there's a new define in map.h called CIRCULAR_AREA, when set, the previous method is used, and map for each in range calls will also check for distances, making most ground skills and battle system use real circles instead of squares.


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@8609 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
skotlex 2006-09-04 14:10:14 +00:00
parent 4c82f276ae
commit def8753415
6 changed files with 95 additions and 63 deletions

View File

@ -3,6 +3,16 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. 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. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2006/09/04
* status_calc_misc will now be invoked in status_calc_bl even on the first
call, since status could have gone up due to skill bonuses. [Skotlex]
* Moved max HP/SP calculations to before invoking status_calc_misc
[Skotlex]
* Simplified distance and check_distance to use "aegis" methods (greater of
dx/dy = distance), there's a new define in map.h called CIRCULAR_AREA, when
set, the previous method is used, and "for each in range" calls will also
check for distances, making most ground skills and battle system use real
circles instead of squares. [Skotlex]
2006/09/03 2006/09/03
* Fixed SC_BERSERK's no regen penalty lasting pretty much forever. * Fixed SC_BERSERK's no regen penalty lasting pretty much forever.
[Skotlex] [Skotlex]

View File

@ -220,14 +220,20 @@ int map_getusers(void) {
return map_users; return map_users;
} }
//Distance functions, taken from http://www.flipcode.com/articles/article_fastdistance.shtml //Distance functions, taken from http://www.flipcode.com/articles/article_fastdistance.shtml
int check_distance(int dx, int dy, int distance) { int check_distance(int dx, int dy, int distance) {
#ifdef CIRCULAR_AREA
//In this case, we just do a square comparison. Add 1 tile grace for diagonal range checks. //In this case, we just do a square comparison. Add 1 tile grace for diagonal range checks.
return (dx*dx + dy*dy <= distance*distance + (dx&&dy?1:0)); return (dx*dx + dy*dy <= distance*distance + (dx&&dy?1:0));
#else
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
return ((dx<dy?dy:dx) <= distance);
#endif
} }
unsigned int distance(int dx, int dy) { unsigned int distance(int dx, int dy) {
#ifdef CIRCULAR_AREA
unsigned int min, max; unsigned int min, max;
if ( dx < 0 ) dx = -dx; if ( dx < 0 ) dx = -dx;
@ -247,6 +253,11 @@ unsigned int distance(int dx, int dy) {
// coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min ) // coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min )
return ((( max << 8 ) + ( max << 3 ) - ( max << 4 ) - ( max << 1 ) + return ((( max << 8 ) + ( max << 3 ) - ( max << 4 ) - ( max << 1 ) +
( min << 7 ) - ( min << 5 ) + ( min << 3 ) - ( min << 1 )) >> 8 ); ( min << 7 ) - ( min << 5 ) + ( min << 3 ) - ( min << 1 )) >> 8 );
#else
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
return (dx<dy?dy:dx);
#endif
} }
// //
@ -657,9 +668,9 @@ int map_foreachinrange(int (*func)(struct block_list*,va_list),struct block_list
for(i=0;i<c && bl;i++,bl=bl->next){ for(i=0;i<c && bl;i++,bl=bl->next){
if(bl && bl->type&type if(bl && bl->type&type
&& bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1
//For speed purposes, it does not checks actual range by default. #ifdef CIRCULAR_AREA
//Feel free to uncomment if you want a more "exact" approach. && check_distance_bl(center, bl, range)
// && check_distance_bl(center, bl, range) #endif
&& bl_list_count<BL_LIST_MAX) && bl_list_count<BL_LIST_MAX)
bl_list[bl_list_count++]=bl; bl_list[bl_list_count++]=bl;
} }
@ -673,7 +684,9 @@ int map_foreachinrange(int (*func)(struct block_list*,va_list),struct block_list
for(i=0;i<c && bl;i++,bl=bl->next){ for(i=0;i<c && bl;i++,bl=bl->next){
if(bl if(bl
&& bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1
// && check_distance_bl(center, bl, range) #ifdef CIRCULAR_AREA
&& check_distance_bl(center, bl, range)
#endif
&& bl_list_count<BL_LIST_MAX) && bl_list_count<BL_LIST_MAX)
bl_list[bl_list_count++]=bl; bl_list[bl_list_count++]=bl;
} }
@ -731,6 +744,9 @@ int map_foreachinshootrange(int (*func)(struct block_list*,va_list),struct block
for(i=0;i<c && bl;i++,bl=bl->next){ for(i=0;i<c && bl;i++,bl=bl->next){
if(bl && bl->type&type if(bl && bl->type&type
&& bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1
#ifdef CIRCULAR_AREA
&& check_distance_bl(center, bl, range)
#endif
&& path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y) && path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y)
&& bl_list_count<BL_LIST_MAX) && bl_list_count<BL_LIST_MAX)
bl_list[bl_list_count++]=bl; bl_list[bl_list_count++]=bl;
@ -745,6 +761,9 @@ int map_foreachinshootrange(int (*func)(struct block_list*,va_list),struct block
for(i=0;i<c && bl;i++,bl=bl->next){ for(i=0;i<c && bl;i++,bl=bl->next){
if(bl if(bl
&& bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1
#ifdef CIRCULAR_AREA
&& check_distance_bl(center, bl, range)
#endif
&& path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y) && path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y)
&& bl_list_count<BL_LIST_MAX) && bl_list_count<BL_LIST_MAX)
bl_list[bl_list_count++]=bl; bl_list[bl_list_count++]=bl;

View File

@ -14,6 +14,13 @@
//Only chars affected are those defined in BL_CHAR (mobs and players currently) //Only chars affected are those defined in BL_CHAR (mobs and players currently)
//#define CELL_NOSTACK //#define CELL_NOSTACK
//Uncomment to enable circular area checks.
//By default, all range checks in Aegis are of Square shapes, so a weapon range
// of 10 allows you to attack from anywhere within a 21x21 area.
//Enabling this changes such checks to circular checks, which is more realistic,
// but is not the official behaviour.
//#define CIRCULAR_AREA
#define MAX_PC_CLASS 4050 #define MAX_PC_CLASS 4050
#define PC_CLASS_BASE 0 #define PC_CLASS_BASE 0
#define PC_CLASS_BASE2 (PC_CLASS_BASE + 4001) #define PC_CLASS_BASE2 (PC_CLASS_BASE + 4001)

View File

@ -786,7 +786,7 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
return 0; //For some reason Homun targets are never overriden. return 0; //For some reason Homun targets are never overriden.
dist = distance_bl(&md->bl, bl); dist = distance_bl(&md->bl, bl);
if(dist < md->db->range2 && if(
((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) && ((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) &&
battle_check_range(&md->bl,bl,md->db->range2) battle_check_range(&md->bl,bl,md->db->range2)
) { //Pick closest target? ) { //Pick closest target?
@ -825,9 +825,8 @@ static int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap)
case BL_PC: case BL_PC:
case BL_HOM: //[orn] case BL_HOM: //[orn]
case BL_MOB: case BL_MOB:
if(check_distance_bl(&md->bl, bl, md->status.rhw.range) && if(battle_check_range (&md->bl, bl, md->status.rhw.range))
battle_check_range (&md->bl, bl, md->status.rhw.range) {
) {
(*target) = bl; (*target) = bl;
md->target_id=bl->id; md->target_id=bl->id;
md->min_chase= md->db->range3; md->min_chase= md->db->range3;
@ -852,8 +851,8 @@ static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
md=va_arg(ap,struct mob_data *); md=va_arg(ap,struct mob_data *);
target= va_arg(ap,struct block_list**); target= va_arg(ap,struct block_list**);
if((dist=distance_bl(&md->bl, bl)) < md->db->range2 && dist=distance_bl(&md->bl, bl);
mob_can_reach(md,bl,dist+1, MSS_LOOT) && if(mob_can_reach(md,bl,dist+1, MSS_LOOT) &&
((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) //New target closer than previous one. ((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) //New target closer than previous one.
) { ) {
(*target) = bl; (*target) = bl;

View File

@ -9100,17 +9100,15 @@ int buildin_stoptimer(struct script_state *st) // Added by RoVeRT
int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT
{ {
char *event=va_arg(ap,char *); char *event=va_arg(ap,char *);
int *c=va_arg(ap,int *);
if(strcmp(event,((struct mob_data *)bl)->npc_event)==0) if(strcmp(event,((struct mob_data *)bl)->npc_event)==0)
(*c)++; return 1;
return 0; return 0;
} }
int buildin_mobcount(struct script_state *st) // Added by RoVeRT int buildin_mobcount(struct script_state *st) // Added by RoVeRT
{ {
char *mapname,*event; char *mapname,*event;
int m,c=0; int m;
mapname=conv_str(st,& (st->stack->stack_data[st->start+2])); mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
event=conv_str(st,& (st->stack->stack_data[st->start+3])); event=conv_str(st,& (st->stack->stack_data[st->start+3]));
check_event(st, event); check_event(st, event);
@ -9119,9 +9117,8 @@ int buildin_mobcount(struct script_state *st) // Added by RoVeRT
push_val(st->stack,C_INT,-1); push_val(st->stack,C_INT,-1);
return 0; return 0;
} }
map_foreachinmap(buildin_mobcount_sub, m, BL_MOB, event,&c );
push_val(st->stack,C_INT, (c)); push_val(st->stack,C_INT,map_foreachinmap(buildin_mobcount_sub, m, BL_MOB, event));
return 0; return 0;
} }

View File

@ -1941,6 +1941,49 @@ int status_calc_pc(struct map_session_data* sd,int first)
if((skill=pc_checkskill(sd,BS_HILTBINDING))>0) if((skill=pc_checkskill(sd,BS_HILTBINDING))>0)
status->batk += 4; status->batk += 4;
// ----- HP MAX CALCULATION -----
// Basic MaxHP value
//We hold the standard Max HP here to make it faster to recalculate on vit changes.
sd->status.max_hp = status_base_pc_maxhp(sd,status);
status->max_hp += sd->status.max_hp;
// Absolute modifiers from passive skills
if((skill=pc_checkskill(sd,CR_TRUST))>0)
status->max_hp += skill*200;
// ----- SP MAX CALCULATION -----
// Basic MaxSP value
sd->status.max_sp = status_base_pc_maxsp(sd,status);
status->max_sp += sd->status.max_sp;
// Absolute modifiers from passive skills
if((skill=pc_checkskill(sd,SL_KAINA))>0)
status->max_sp += 30*skill;
if(status->sp>status->max_sp)
status->sp=status->max_sp;
// ----- RESPAWN HP/SP -----
//
//Calc respawn hp and store it on base_status
if (sd->special_state.restart_full_recover)
{
status->hp = status->max_hp;
status->sp = status->max_sp;
} else {
if((sd->class_&MAPID_BASEMASK) == MAPID_NOVICE && !(sd->class_&JOBL_2)
&& battle_config.restart_hp_rate < 50)
status->hp=status->max_hp>>1;
else
status->hp=status->max_hp * battle_config.restart_hp_rate/100;
if(!status->hp)
status->hp = 1;
status->sp = status->max_sp * battle_config.restart_sp_rate /100;
}
// ----- MISC CALCULATION ----- // ----- MISC CALCULATION -----
status_calc_misc(&sd->bl, status, sd->status.base_level); status_calc_misc(&sd->bl, status, sd->status.base_level);
@ -2047,49 +2090,6 @@ int status_calc_pc(struct map_session_data* sd,int first)
i = 800-status->agi*4; i = 800-status->agi*4;
status->dmotion = cap_value(i, 400, 800); status->dmotion = cap_value(i, 400, 800);
// ----- HP MAX CALCULATION -----
// Basic MaxHP value
//We hold the standard Max HP here to make it faster to recalculate on vit changes.
sd->status.max_hp = status_base_pc_maxhp(sd,status);
status->max_hp += sd->status.max_hp;
// Absolute modifiers from passive skills
if((skill=pc_checkskill(sd,CR_TRUST))>0)
status->max_hp += skill*200;
// ----- SP MAX CALCULATION -----
// Basic MaxSP value
sd->status.max_sp = status_base_pc_maxsp(sd,status);
status->max_sp += sd->status.max_sp;
// Absolute modifiers from passive skills
if((skill=pc_checkskill(sd,SL_KAINA))>0)
status->max_sp += 30*skill;
if(status->sp>status->max_sp)
status->sp=status->max_sp;
// ----- RESPAWN HP/SP -----
//
//Calc respawn hp and store it on base_status
if (sd->special_state.restart_full_recover)
{
status->hp = status->max_hp;
status->sp = status->max_sp;
} else {
if((sd->class_&MAPID_BASEMASK) == MAPID_NOVICE && !(sd->class_&JOBL_2)
&& battle_config.restart_hp_rate < 50)
status->hp=status->max_hp>>1;
else
status->hp=status->max_hp * battle_config.restart_hp_rate/100;
if(!status->hp)
status->hp = 1;
status->sp = status->max_sp * battle_config.restart_sp_rate /100;
}
// ----- MISC CALCULATIONS ----- // ----- MISC CALCULATIONS -----
// Weight // Weight
@ -2720,9 +2720,9 @@ void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag)
unit_walktoxy(&sd->bl, sd->ud.to_x, sd->ud.to_y, sd->ud.state.walk_easy); unit_walktoxy(&sd->bl, sd->ud.to_x, sd->ud.to_y, sd->ud.state.walk_easy);
} }
//Avoid calculating twice (SCB_ALL -> status_calc_pc -> was calculated in //Needs be done even when it was already done in status_calc_misc, because
//status_calc_misc() [Skotlex] //int/vit max hp/sp could have changed due to skills.
if(flag&(SCB_INT|SCB_MAXSP|SCB_VIT|SCB_MAXHP) && flag != SCB_ALL) if(flag&(SCB_INT|SCB_MAXSP|SCB_VIT|SCB_MAXHP))
status_calc_regen(&sd->bl, status, &sd->regen); status_calc_regen(&sd->bl, status, &sd->regen);
if(flag&SCB_REGEN) if(flag&SCB_REGEN)