summaryrefslogtreecommitdiff
path: root/src/map/skill.c
diff options
context:
space:
mode:
authorultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-09-10 20:50:55 +0000
committerultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-09-10 20:50:55 +0000
commit8921a3023de5519f0e0af164d71023914c8656f3 (patch)
tree20ac266e3da2e1482954b9895e3c5389ab2927e8 /src/map/skill.c
parentc62e4ce22fe01f8f355f8f47695da2c977102c1c (diff)
downloadhercules-8921a3023de5519f0e0af164d71023914c8656f3.tar.gz
hercules-8921a3023de5519f0e0af164d71023914c8656f3.tar.bz2
hercules-8921a3023de5519f0e0af164d71023914c8656f3.tar.xz
hercules-8921a3023de5519f0e0af164d71023914c8656f3.zip
* Added a safeguard to skill_get_unit_layout() against incorrectly defined layout ids (will give weird results but won't crash at least)
* Fixed Firewall/Icewall being oriented backwards (no real difference though...) * Removed some junk Landprotector/Graffiti code; Graffiti doesn't get placed randomly anymore * Icewall can now be cast on yourself... but for some reason, the cell on yourself immediately expires! * Merged together functions clif_set0192() and clif_changemapcell() - also removed its "send to whole map" mode which is just plain wrong (although aegis actually does use it to 'inform' caster about changes) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11175 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map/skill.c')
-rw-r--r--src/map/skill.c202
1 files changed, 98 insertions, 104 deletions
diff --git a/src/map/skill.c b/src/map/skill.c
index 27701cf40..f27d29298 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -6,6 +6,7 @@
#include "../common/nullpo.h"
#include "../common/malloc.h"
#include "../common/showmsg.h"
+#include "../common/strlib.h"
#include "../common/ers.h"
#include "skill.h"
@@ -14,7 +15,7 @@
#include "pc.h"
#include "status.h"
#include "pet.h"
-#include "mercenary.h" //[orn]
+#include "mercenary.h"
#include "mob.h"
#include "npc.h"
#include "battle.h"
@@ -666,6 +667,10 @@ struct skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
struct skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
struct skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
+struct skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT];
+int firewall_unit_pos;
+int icewall_unit_pos;
+
// macros to check for out of bounds errors [celest]
// i: Skill ID, l: Skill Level, var: Value to return after checking
// for values that don't require level just put a one (putting 0 will trigger return 0; instead
@@ -986,30 +991,28 @@ int skillnotok_hom (int skillid, struct homun_data *hd)
return skillnotok(skillid, hd->master);
}
-struct skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT];
-int firewall_unit_pos;
-int icewall_unit_pos;
-
-struct skill_unit_layout *skill_get_unit_layout (int skillid, int skilllv, struct block_list *src, int x, int y)
+struct skill_unit_layout* skill_get_unit_layout (int skillid, int skilllv, struct block_list* src, int x, int y)
{
int pos = skill_get_unit_layout_type(skillid,skilllv);
int dir;
- if (pos != -1)
+ if (pos < -1 || pos >= MAX_SKILL_UNIT_LAYOUT) {
+ ShowError("skill_get_unit_layout: unsupported layout type %d for skill %d (level %d)\n", pos, skillid, skilllv);
+ pos = cap_value(pos, 0, MAX_SQUARE_LAYOUT); // cap to nearest square layout
+ }
+
+ if (pos != -1) // simple single-definition layout
return &skill_unit_layout[pos];
- if (src->x == x && src->y == y)
- dir = 2;
- else
- dir = map_calc_dir(src,x,y);
+ dir = (src->x == x && src->y == y) ? 6 : map_calc_dir(src,x,y); // 6 - default aegis direction
if (skillid == MG_FIREWALL)
return &skill_unit_layout [firewall_unit_pos + dir];
else if (skillid == WZ_ICEWALL)
return &skill_unit_layout [icewall_unit_pos + dir];
- ShowError("Unknown unit layout for skill %d, %d\n",skillid,skilllv);
- return &skill_unit_layout[0];
+ ShowError("skill_get_unit_layout: unknown unit layout for skill %d (level %d)\n", skillid, skilllv);
+ return &skill_unit_layout[0]; // default 1x1 layout
}
/*==========================================
@@ -2341,8 +2344,7 @@ static int skill_check_unit_range (struct block_list *bl, int x, int y, int skil
}
range += layout_type;
- return map_foreachinarea(skill_check_unit_range_sub,bl->m,
- x-range,y-range,x+range,y+range,BL_SKILL,skillid);
+ return map_foreachinarea(skill_check_unit_range_sub,bl->m,x-range,y-range,x+range,y+range,BL_SKILL,skillid);
}
static int skill_check_unit_range2_sub (struct block_list *bl, va_list ap)
@@ -5959,21 +5961,22 @@ int skill_castend_pos (int tid, unsigned int tick, int id, int data)
ud->skilltimer=-1;
do {
- if(status_isdead(src)) break;
+ if(status_isdead(src))
+ break;
- if (!(battle_config.skill_reiteration && src->type&battle_config.skill_reiteration) &&
+ if( !(src->type&battle_config.skill_reiteration) &&
skill_get_unit_flag(ud->skillid)&UF_NOREITERATION &&
skill_check_unit_range(src,ud->skillx,ud->skilly,ud->skillid,ud->skilllv)
- )
+ )
break;
- if (battle_config.skill_nofootset && src->type&battle_config.skill_nofootset &&
+ if( src->type&battle_config.skill_nofootset &&
skill_get_unit_flag(ud->skillid)&UF_NOFOOTSET &&
skill_check_unit_range2(src,ud->skillx,ud->skilly,ud->skillid,ud->skilllv)
- )
+ )
break;
- if(battle_config.land_skill_limit && src->type&battle_config.land_skill_limit &&
+ if( src->type&battle_config.land_skill_limit &&
(maxcount = skill_get_maxcount(ud->skillid, ud->skilllv)) > 0
) {
int i;
@@ -5981,7 +5984,7 @@ int skill_castend_pos (int tid, unsigned int tick, int id, int data)
if(ud->skillunit[i]->skill_id == ud->skillid)
maxcount--;
}
- if(!maxcount)
+ if( maxcount == 0 )
break;
}
@@ -6647,7 +6650,6 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid,
{
struct skill_unit_group *group;
int i,limit,val1=0,val2=0,val3=0;
- int count=0;
int target,interval,range,unit_flag;
struct skill_unit_layout *layout;
struct map_session_data *sd;
@@ -6737,13 +6739,6 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid,
break;
case SA_LANDPROTECTOR:
- {
- int aoe_diameter; // -- aoe_diameter (moonsoul) added for sage Area Of Effect skills
- val1=skilllv*15+10;
- aoe_diameter=skilllv+skilllv%2+5;
- count=aoe_diameter*aoe_diameter; // -- this will not function if changed to ^2 (moonsoul)
- }
- //No break because we also have to check if we use gemstones. [Skotlex]
case SA_VOLCANO:
case SA_DELUGE:
case SA_VIOLENTGALE:
@@ -6845,9 +6840,6 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid,
val1 = 55 + skilllv*5; //Elemental Resistance
val2 = skilllv*10; //Status ailment resistance
break;
- case RG_GRAFFITI: /* Graffiti */
- count=1; // Leave this at 1 [Valaris]
- break;
case WE_CALLPARTNER:
if (sd) val1 = sd->status.partner_id;
break;
@@ -6894,8 +6886,7 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid,
}
}
- nullpo_retr(NULL, group=skill_initunitgroup(src,(count > 0 ? count : layout->count),
- skillid,skilllv,skill_get_unit_id(skillid,flag&1)+subunt, limit, interval));
+ nullpo_retr(NULL, group=skill_initunitgroup(src,layout->count,skillid,skilllv,skill_get_unit_id(skillid,flag&1)+subunt, limit, interval));
group->val1=val1;
group->val2=val2;
group->val3=val3;
@@ -6903,47 +6894,39 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid,
group->bl_flag= skill_get_unit_bl_target(skillid);
group->state.into_abyss = (sc && sc->data[SC_INTOABYSS].timer != -1); //Store into abyss state, to know it shouldn't give traps back. [Skotlex]
group->state.magic_power = (flag&2 || (sc && sc->data[SC_MAGICPOWER].timer != -1)); //Store the magic power flag. [Skotlex]
- //Store if this skill needs to consume ammo.
- group->state.ammo_consume = (sd && sd->state.arrow_atk && skillid != GS_GROUNDDRIFT);
+ group->state.ammo_consume = (sd && sd->state.arrow_atk && skillid != GS_GROUNDDRIFT); //Store if this skill needs to consume ammo.
group->state.song_dance = (unit_flag&(UF_DANCE|UF_SONG)?1:0)|(unit_flag&UF_ENSEMBLE?2:0); //Signals if this is a song/dance/duet
//if tick is greater than current, do not invoke onplace function just yet. [Skotlex]
if (DIFF_TICK(group->tick, gettick()) > 100)
active_flag = 0;
- if(skillid==HT_TALKIEBOX ||
- skillid==RG_GRAFFITI){
+ if(skillid==HT_TALKIEBOX || skillid==RG_GRAFFITI){
group->valstr=(char *) aMalloc(MESSAGE_SIZE*sizeof(char));
if (sd)
- memcpy(group->valstr,sd->message,MESSAGE_SIZE);
+ safestrncpy(group->valstr, sd->message, MESSAGE_SIZE);
else //Eh... we have to write something here... even though mobs shouldn't use this. [Skotlex]
- strcpy(group->valstr, "Boo!");
+ safestrncpy(group->valstr, "Boo!", MESSAGE_SIZE);
}
//Why redefine local variables when the ones of the function can be reused? [Skotlex]
val1=skilllv;
val2=0;
limit=group->limit;
- count=group->unit_count;
- for(i=0;i<count;i++){
+ for(i=0;i<layout->count;i++)
+ {
struct skill_unit *unit;
int ux,uy,alive=1;
ux = x + layout->dx[i];
uy = y + layout->dy[i];
+
switch (skillid) {
case MG_FIREWALL:
case NJ_KAENSIN:
val2=group->val2;
break;
case WZ_ICEWALL:
- if(skilllv <= 1)
- val1 = 500;
- else
- val1 = 200 + 200*skilllv;
- break;
- case RG_GRAFFITI: /* Graffiti [Valaris] */
- ux+=(i%5-2);
- uy+=(i/5-2);
+ val1 = (skilllv <= 1) ? 500 : 200 + 200*skilllv;
break;
case GS_DESPERADO:
val1 = abs(layout->dx[i]);
@@ -6968,25 +6951,19 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid,
if(alive && map_getcell(src->m,ux,uy,CELL_CHKWALL))
alive = 0;
- if (alive && battle_config.skill_wall_check) {
- //Check if there's a path between cell and center of casting.
- if (!path_search_long(NULL,src->m,ux,uy,x,y))
- alive = 0;
- }
+ if(alive && battle_config.skill_wall_check && !path_search_long(NULL,src->m,ux,uy,x,y))
+ alive = 0; //no path between cell and center of casting.
if(alive && skillid == WZ_ICEWALL) {
- if(src->x == x && src->y==y) // Ice Wall not allowed on self [DracoRPG]
- alive=0;
- else {
- val2=map_getcell(src->m,ux,uy,CELL_GETTYPE);
- if(val2==5 || val2==1)
+ int celltype = map_getcell(src->m,ux,uy,CELL_GETTYPE);
+ if(celltype==5 || celltype==1)
alive=0;
else
- clif_changemapcell(src->m,ux,uy,5,0);
- }
+ clif_changemapcell(0,src->m,ux,uy,5);
}
if(alive){
+ //FIXME: why not calculate val1/val2 in here? [ultramage]
nullpo_retr(NULL, unit=skill_initunit(group,i,ux,uy,val1,val2));
unit->limit=limit;
unit->range=range;
@@ -7681,8 +7658,7 @@ static int skill_unit_onleft (int skill_id, struct block_list *bl, unsigned int
case BD_ROKISWEIL:
case BD_INTOABYSS:
case BD_SIEGFRIED:
- if(sc && sc->data[SC_DANCING].timer != -1 &&
- (sc->data[SC_DANCING].val1&0xFFFF) == skill_id)
+ if(sc && sc->data[SC_DANCING].timer != -1 && (sc->data[SC_DANCING].val1&0xFFFF) == skill_id)
{ //Check if you just stepped out of your ensemble skill to cancel dancing. [Skotlex]
//We don't check for SC_LONGING because someone could always have knocked you back and out of the song/dance.
//FIXME: This code is not perfect, it doesn't checks for the real ensemble's owner,
@@ -7735,12 +7711,12 @@ static int skill_unit_onleft (int skill_id, struct block_list *bl, unsigned int
}
}
break;
- case UNT_GOSPEL:
- if (sc && sc->data[type].timer != -1 && sc->data[type].val4 == BCT_ALL) //End item-no-use Gospel Effect. [Skotlex]
- status_change_end(bl, type, -1);
- break;
-
+ case UNT_GOSPEL:
+ if (sc && sc->data[type].timer != -1 && sc->data[type].val4 == BCT_ALL) //End item-no-use Gospel Effect. [Skotlex]
+ status_change_end(bl, type, -1);
+ break;
}
+
return skill_id;
}
@@ -7811,7 +7787,7 @@ int skill_unit_onlimit (struct skill_unit *src, unsigned int tick, int flag)
break;
case UNT_ICEWALL:
- clif_changemapcell(src->bl.m,src->bl.x,src->bl.y,src->val2,1);
+ clif_changemapcell(0,src->bl.m,src->bl.x,src->bl.y,src->val2);
break;
case UNT_CALLFAMILY:
if (!flag)
@@ -9904,11 +9880,13 @@ int skill_delunit (struct skill_unit *unit, int flag)
return 0;
nullpo_retr(0, group=unit->group);
+ // invoke onlimit event
skill_unit_onlimit( unit,gettick(), flag);
if (group->state.song_dance&0x1) //Restore dissonance effect.
skill_dance_overlap(unit, 0);
+ // invoke onout event
if (!unit->range) {
map_foreachincell(skill_unit_effect,unit->bl.m,
unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,gettick(),4);
@@ -9946,10 +9924,11 @@ int skill_delunit (struct skill_unit *unit, int flag)
*
*------------------------------------------*/
static int skill_unit_group_newid = MAX_SKILL_DB;
+
struct skill_unit_group *skill_initunitgroup (struct block_list *src, int count, int skillid, int skilllv, int unit_id, int limit, int interval)
{
- struct unit_data *ud = unit_bl2ud(src);
- struct skill_unit_group *group=NULL;
+ struct unit_data* ud = unit_bl2ud( src );
+ struct skill_unit_group* group;
int i;
if(skilllv <= 0) return 0;
@@ -9957,9 +9936,11 @@ struct skill_unit_group *skill_initunitgroup (struct block_list *src, int count,
nullpo_retr(NULL, src);
nullpo_retr(NULL, ud);
- for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i]; i++);
-
- if(i == MAX_SKILLUNITGROUP) {
+ // find a free spot to store the new unit group
+ ARR_FIND( 0, MAX_SKILLUNITGROUP, i, ud->skillunit[i] == NULL );
+ if(i == MAX_SKILLUNITGROUP)
+ {
+ // array is full, make room by discarding oldest group
int j=0;
unsigned maxdiff=0,x,tick=gettick();
for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++)
@@ -9971,30 +9952,35 @@ struct skill_unit_group *skill_initunitgroup (struct block_list *src, int count,
//Since elements must have shifted, we use the last slot.
i = MAX_SKILLUNITGROUP-1;
}
- if (!ud->skillunit[i])
- ud->skillunit[i] = ers_alloc(skill_unit_ers, struct skill_unit_group);
- group=ud->skillunit[i];
- group->src_id=src->id;
- group->party_id=status_get_party_id(src);
- group->guild_id=status_get_guild_id(src);
- group->group_id=skill_unit_group_newid++;
+ group = ers_alloc(skill_unit_ers, struct skill_unit_group);
+ group->src_id = src->id;
+ group->party_id = status_get_party_id(src);
+ group->guild_id = status_get_guild_id(src);
+ group->group_id = skill_unit_group_newid++;
+ group->unit = (struct skill_unit *)aCalloc(count,sizeof(struct skill_unit));
+ group->unit_count = count;
+ group->alive_count = 0;
+ group->val1 = 0;
+ group->val2 = 0;
+ group->val3 = 0;
+ group->skill_id = skillid;
+ group->skill_lv = skilllv;
+ group->unit_id = unit_id;
+ group->map = src->m;
+ group->limit = limit;
+ group->interval = interval;
+ group->tick = gettick();
+ group->valstr = NULL;
+
+ ud->skillunit[i] = group;
+
if(skill_unit_group_newid<=0)
skill_unit_group_newid = MAX_SKILL_DB;
- group->unit=(struct skill_unit *)aCalloc(count,sizeof(struct skill_unit));
- group->unit_count=count;
- group->alive_count=0;
- group->val1=group->val2=group->val3=0;
- group->skill_id=skillid;
- group->skill_lv=skilllv;
- group->unit_id=unit_id;
- group->map=src->m;
- group->limit=limit;
- group->interval=interval;
- group->tick=gettick();
+
if (skillid == PR_SANCTUARY) //Sanctuary starts healing +1500ms after casted. [Skotlex]
group->tick += 1500;
- group->valstr=NULL;
+
return group;
}
@@ -10060,16 +10046,18 @@ int skill_delunitgroup (struct block_list *src, struct skill_unit_group *group,
group->group_id=0;
group->unit_count=0;
- //Locate and clear this unit from the array.
- for (i=0; i<MAX_SKILLUNITGROUP && ud->skillunit[i]!=group; i++);
- for (j=i; j<MAX_SKILLUNITGROUP && ud->skillunit[j]; j++);
- j--;
- if (i<MAX_SKILLUNITGROUP) {
+ // locate this group, swap with the last entry and delete it
+ ARR_FIND( 0, MAX_SKILLUNITGROUP, i, ud->skillunit[i] == group );
+ ARR_FIND( i, MAX_SKILLUNITGROUP, j, ud->skillunit[j] == NULL ); j--;
+ if( i < MAX_SKILLUNITGROUP )
+ {
ud->skillunit[i] = ud->skillunit[j];
ud->skillunit[j] = NULL;
ers_free(skill_unit_ers, group);
- } else
+ }
+ else
ShowError("skill_delunitgroup: Group not found! (src_id: %d skill_id: %d)\n", group->src_id, group->skill_id);
+
return 1;
}
@@ -10392,13 +10380,12 @@ int skill_unit_move (struct block_list *bl, unsigned int tick, int flag)
skill_unit_index=0;
}
- map_foreachincell(skill_unit_move_sub,
- bl->m,bl->x,bl->y,BL_SKILL,bl,tick,flag);
+ map_foreachincell(skill_unit_move_sub,bl->m,bl->x,bl->y,BL_SKILL,bl,tick,flag);
if (flag&2 && flag&1)
{ //Onplace, check any skill units you have left.
int i;
- for (i=0; i < (sizeof(skill_unit_temp)/sizeof(int)) && skill_unit_temp[i]; i++)
+ for (i=0; i < ARRAYLENGTH(skill_unit_temp) && skill_unit_temp[i]; i++)
skill_unit_onleft(skill_unit_temp[i], bl, tick);
}
@@ -11077,6 +11064,8 @@ void skill_init_unit_layout (void)
int i,j,size,pos = 0;
memset(skill_unit_layout,0,sizeof(skill_unit_layout));
+
+ // standard square layouts go first
for (i=0; i<=MAX_SQUARE_LAYOUT; i++) {
size = i*2+1;
skill_unit_layout[i].count = size*size;
@@ -11085,6 +11074,8 @@ void skill_init_unit_layout (void)
skill_unit_layout[i].dy[j] = (j/size-i);
}
}
+
+ // afterwards add special ones
pos = i;
for (i=0;i<MAX_SKILL_DB;i++) {
if (!skill_db[i].unit_id[0] || skill_db[i].unit_layout_type[0] != -1)
@@ -11092,6 +11083,7 @@ void skill_init_unit_layout (void)
switch (i) {
case MG_FIREWALL:
case WZ_ICEWALL:
+ // these will be handled later
break;
case PR_SANCTUARY:
case NPC_EVILLAND:
@@ -11234,6 +11226,8 @@ void skill_init_unit_layout (void)
skill_db[i].unit_layout_type[j] = pos;
pos++;
}
+
+ // firewall and icewall have 8 layouts (direction-dependent)
firewall_unit_pos = pos;
for (i=0;i<8;i++) {
if (i&1) {