summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-04-11 18:45:43 +0000
committerskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-04-11 18:45:43 +0000
commit354a5439cd4f7b4e1454cb37637ce07af279466c (patch)
treede0749dacacf28d5e6b962eb4db40698428a19a1
parentf30f40066e831e4cc0c4326f96d9358554c51791 (diff)
downloadhercules-354a5439cd4f7b4e1454cb37637ce07af279466c.tar.gz
hercules-354a5439cd4f7b4e1454cb37637ce07af279466c.tar.bz2
hercules-354a5439cd4f7b4e1454cb37637ce07af279466c.tar.xz
hercules-354a5439cd4f7b4e1454cb37637ce07af279466c.zip
- Implemented use of ers for skill_unit_groups to reduce memory usage. NEEDS TESTING
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5991 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r--Changelog-Trunk.txt3
-rw-r--r--src/map/battle.c4
-rw-r--r--src/map/map.c1
-rw-r--r--src/map/map.h2
-rw-r--r--src/map/pc.c2
-rw-r--r--src/map/skill.c173
-rw-r--r--src/map/skill.h4
-rw-r--r--src/map/status.c4
8 files changed, 104 insertions, 89 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 13296f684..cb26ba463 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -4,6 +4,9 @@ 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/11
+ * Implemented use of ers for skill_unit_groups to reduce memory usage.
+ * Note that it's NOT TESTED yet. Use with caution, at least some obvious
+ bugs are expected to be found... [Skotlex]
* Modified battle_check_range to do a path-check on distances less than 2
(rather than 3) to avoid being able to hit through walls. [Skotlex]
* Modified unit_walktoxy_sub to always move at least one cell when a large
diff --git a/src/map/battle.c b/src/map/battle.c
index fdbcffa07..cb84d3044 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -223,7 +223,7 @@ int battle_damage(struct block_list *src,struct block_list *target,int damage, i
sc->data[SC_GRAVITATION].val3 == BCT_SELF) {
struct skill_unit_group *sg = (struct skill_unit_group *)sc->data[SC_GRAVITATION].val4;
if (sg) {
- skill_delunitgroup(sg);
+ skill_delunitgroup(target,sg);
sc->data[SC_GRAVITATION].val4 = 0;
status_change_end(target, SC_GRAVITATION, -1);
}
@@ -404,7 +404,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
struct skill_unit_group *group = (struct skill_unit_group *)sc->data[SC_SAFETYWALL].val3;
if (group) {
if (--group->val2<=0)
- skill_delunitgroup(group);
+ skill_delunitgroup(NULL,group);
return 0;
} else {
status_change_end(bl,SC_SAFETYWALL,-1);
diff --git a/src/map/map.c b/src/map/map.c
index aac3bea46..bfe0f777f 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -3659,6 +3659,7 @@ void do_final(void) {
do_final_pet();
do_final_mob();
do_final_msg();
+ do_final_skill();
do_final_unit();
if(use_irc)
do_final_irc();
diff --git a/src/map/map.h b/src/map/map.h
index 50f8693b7..9e13c3985 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -349,7 +349,7 @@ struct unit_data {
struct block_list *bl;
struct walkpath_data walkpath;
struct skill_timerskill skilltimerskill[MAX_SKILLTIMERSKILL];
- struct skill_unit_group skillunit[MAX_SKILLUNITGROUP];
+ struct skill_unit_group *skillunit[MAX_SKILLUNITGROUP];
struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
short attacktarget_lv;
short to_x,to_y;
diff --git a/src/map/pc.c b/src/map/pc.c
index 8502b5ce8..f752f3a5e 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -4679,7 +4679,7 @@ int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
{ //Remove Gospel [Skotlex]
struct skill_unit_group *sg = (struct skill_unit_group *)sd->sc.data[SC_GOSPEL].val3;
if (sg)
- skill_delunitgroup(sg);
+ skill_delunitgroup(&sd->bl, sg);
}
clif_clearchar_area(&sd->bl,1);
diff --git a/src/map/skill.c b/src/map/skill.c
index f0964ec01..e60bea290 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -12,6 +12,7 @@
#include "../common/malloc.h"
#include "../common/showmsg.h"
#include "../common/grfio.h"
+#include "../common/ers.h"
#include "skill.h"
#include "map.h"
@@ -35,7 +36,6 @@
//Guild Skills are shifted to these to make them stick into the skill array.
#define GD_SKILLRANGEMIN 900
#define GD_SKILLRANGEMAX GD_SKILLRANGEMIN+MAX_GUILDSKILL
-#define swap(x,y) { int t; t = x; x = y; y = t; }
int skill_names_id[MAX_SKILL_DB];
const struct skill_name_db skill_names[] = {
@@ -610,6 +610,8 @@ const struct skill_name_db skill_names[] = {
static const int dirx[8]={0,-1,-1,-1,0,1,1,1};
static const int diry[8]={1,1,0,-1,-1,-1,0,1};
+
+static struct eri *skill_unit_ers = NULL; //For handling skill_unit's [Skotlex]
/* ƒXƒLƒ‹ƒf?ƒ^ƒx?ƒX */
struct skill_db skill_db[MAX_SKILL_DB];
@@ -5803,8 +5805,8 @@ int skill_castend_pos( int tid, unsigned int tick, int id,int data )
(maxcount = skill_get_maxcount(ud->skillid)) > 0
) {
int i;
- for(i=0;i<MAX_SKILLUNITGROUP && maxcount;i++) {
- if(ud->skillunit[i].alive_count > 0 && ud->skillunit[i].skill_id == ud->skillid)
+ for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i] && maxcount;i++) {
+ if(ud->skillunit[i]->skill_id == ud->skillid)
maxcount--;
}
if(!maxcount)
@@ -6229,8 +6231,8 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
p[3] = &sd->status.memo_point[2];
if((maxcount = skill_get_maxcount(skill_num)) > 0) {
- for(i=0;i<MAX_SKILLUNITGROUP && maxcount;i++) {
- if(sd->ud.skillunit[i].alive_count > 0 && sd->ud.skillunit[i].skill_id == skill_num)
+ for(i=0;i<MAX_SKILLUNITGROUP && sd->ud.skillunit[i] && maxcount;i++) {
+ if(sd->ud.skillunit[i]->skill_id == skill_num)
maxcount--;
}
if(!maxcount) {
@@ -6598,7 +6600,7 @@ int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int
struct skill_unit_group *sg;
struct block_list *ss;
struct status_change *sc;
- int type;
+ int type,skillid;
nullpo_retr(0, src);
nullpo_retr(0, bl);
@@ -6622,7 +6624,7 @@ int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int
return 0; //Hidden characters are inmune to AoE skills except Heaven's Drive. [Skotlex]
type = SkillStatusChangeTable[sg->skill_id];
-
+ skillid = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still.
switch (sg->unit_id) {
case UNT_SAFETYWALL:
//TODO: Find a more reliable way to handle the link to sg, this could cause dangling pointers. [Skotlex]
@@ -6637,7 +6639,7 @@ int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int
&& sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y) {
if (pc_setpos(sd,sg->val3,sg->val2>>16,sg->val2&0xffff,3) == 0) {
if (--sg->val1<=0 || sg->src_id == bl->id)
- skill_delunitgroup(sg);
+ skill_delunitgroup(NULL, sg);
}
}
} else if(battle_config.mob_warpportal && bl->type != BL_PET)
@@ -6686,12 +6688,12 @@ int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int
if (sc && sc->data[type].timer==-1)
sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
break;
-
+/* Basilica does not knocks back...
case UNT_BASILICA:
if (!(status_get_mode(bl)&MD_BOSS) && battle_check_target(&src->bl,bl,BCT_ENEMY)>0)
skill_blown(&src->bl,bl,1);
break;
-
+*/
case UNT_FOGWALL:
if (sc && sc->data[type].timer==-1)
{
@@ -6713,7 +6715,7 @@ int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int
break;
}
- return sg->skill_id;
+ return skillid;
}
/*==========================================
@@ -6728,7 +6730,7 @@ int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsign
int splash_count=0;
struct status_change *tsc, *sc;
struct skill_unit_group_tickset *ts;
- int type;
+ int type, skillid;
int diff=0;
nullpo_retr(0, src);
@@ -6743,6 +6745,7 @@ int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsign
sc = status_get_sc(ss); //For magic power.
tsc = status_get_sc(bl);
type = SkillStatusChangeTable[sg->skill_id];
+ skillid = sg->skill_id;
if (sg->interval == -1) {
switch (sg->unit_id) {
@@ -6765,7 +6768,7 @@ int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsign
ts->tick = tick+sg->interval;
// GX‚Í?d‚È‚Á‚Ä‚¢‚½‚ç3HIT‚µ‚È‚¢
- if ((sg->skill_id==CR_GRANDCROSS || sg->skill_id==NPC_GRANDDARKNESS) && !battle_config.gx_allhit)
+ if ((skillid==CR_GRANDCROSS || skillid==NPC_GRANDDARKNESS) && !battle_config.gx_allhit)
ts->tick += sg->interval*(map_count_oncell(bl->m,bl->x,bl->y,0)-1);
}
//Temporarily set magic power to have it take effect. [Skotlex]
@@ -6817,7 +6820,7 @@ int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsign
sg->val1--; // ?V‹K‚É“ü‚Á‚½ƒ†ƒjƒbƒg‚¾‚¯ƒJƒEƒ“ƒg
}
if (sg->val1 <= 0)
- skill_delunitgroup(sg);
+ skill_delunitgroup(NULL,sg);
break;
}
@@ -6835,8 +6838,8 @@ int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsign
break;
case UNT_FIREPILLAR_WAITING:
- skill_delunit(src);
skill_unitsetting(ss,sg->skill_id,sg->skill_lv,src->bl.x,src->bl.y,1);
+ skill_delunit(src);
break;
case UNT_FIREPILLAR_ACTIVE:
@@ -7066,13 +7069,13 @@ int skill_unit_onplace_timer(struct skill_unit *src,struct block_list *bl,unsign
int target = md->target_id;
if (ss->type == BL_PC)
md->target_id = ss->id;
- mobskill_use(md, tick, MSC_SKILLUSED|(sg->skill_id << 16));
+ mobskill_use(md, tick, MSC_SKILLUSED|(skillid << 16));
md->target_id = target;
} else
- mobskill_use(md, tick, MSC_SKILLUSED|(sg->skill_id << 16));
+ mobskill_use(md, tick, MSC_SKILLUSED|(skillid << 16));
}
- return sg->skill_id;
+ return skillid;
}
/*==========================================
* ƒXƒLƒ‹ƒ†ƒjƒbƒg‚©‚ç—£?‚·‚é(‚à‚µ‚­‚Í‚µ‚Ä‚¢‚é)?ê?‡
@@ -7321,7 +7324,7 @@ int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,
nullpo_retr(0, sg=src->group);
if (skill_get_inf2(sg->skill_id)&INF2_TRAP && damage > 0)
- skill_delunitgroup(sg);
+ skill_delunitgroup(NULL,sg);
else
switch(sg->unit_id){
case UNT_ICEWALL:
@@ -8926,14 +8929,14 @@ int skill_clear_element_field(struct block_list *bl)
nullpo_retr(0, bl);
if (!ud) return 0;
- for (i=0;i<MAX_SKILLUNITGROUP;i++) {
- switch (ud->skillunit[i].skill_id) {
+ for (i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++) {
+ switch (ud->skillunit[i]->skill_id) {
case SA_DELUGE:
case SA_VOLCANO:
case SA_VIOLENTGALE:
case SA_LANDPROTECTOR:
case NJ_SUITON:
- skill_delunitgroup(&ud->skillunit[i]);
+ skill_delunitgroup(bl, ud->skillunit[i]);
}
}
return 1;
@@ -8950,14 +8953,14 @@ struct skill_unit_group *skill_locate_element_field(struct block_list *bl)
nullpo_retr(0, bl);
if (!ud) return NULL;
- for (i=0;i<MAX_SKILLUNITGROUP;i++) {
- switch (ud->skillunit[i].skill_id) {
+ for (i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++) {
+ switch (ud->skillunit[i]->skill_id) {
case SA_DELUGE:
case SA_VOLCANO:
case SA_VIOLENTGALE:
case SA_LANDPROTECTOR:
case NJ_SUITON:
- return &ud->skillunit[i];
+ return ud->skillunit[i];
}
}
return NULL;
@@ -9058,7 +9061,7 @@ int skill_ganbatein(struct block_list *bl, va_list ap )
if (unit->group->skill_id == SA_LANDPROTECTOR)
skill_delunit(unit);
- else skill_delunitgroup(unit->group);
+ else skill_delunitgroup(NULL, unit->group);
return 1;
}
@@ -9246,7 +9249,7 @@ void skill_stop_dancing(struct block_list *src)
}
if (group)
- skill_delunitgroup(group);
+ skill_delunitgroup(NULL, group);
if (dsd)
{
@@ -9348,7 +9351,7 @@ int skill_delunit(struct skill_unit *unit)
unit->alive=0;
map_delobjectnofree(unit->bl.id);
if(--group->alive_count==0)
- skill_delunitgroup(group);
+ skill_delunitgroup(NULL, group);
return 0;
}
@@ -9369,30 +9372,23 @@ struct skill_unit_group *skill_initunitgroup(struct block_list *src,
nullpo_retr(NULL, src);
nullpo_retr(NULL, ud);
- if(ud->skillunit){
- for(i=0;i<MAX_SKILLUNITGROUP;i++) /* ‹ó‚¢‚Ä‚¢‚é‚à‚Ì??õ */
- if(ud->skillunit[i].group_id==0){
- group=&ud->skillunit[i];
- break;
- }
-
- if(group==NULL){ /* ‹ó‚¢‚Ä‚È‚¢‚̂Ō¢‚à‚Ì??õ */
- int j=0;
- unsigned maxdiff=0,x,tick=gettick();
- for(i=0;i<MAX_SKILLUNITGROUP;i++)
- if((x=DIFF_TICK(tick,ud->skillunit[i].tick))>maxdiff){
- maxdiff=x;
- j=i;
- }
- skill_delunitgroup(&ud->skillunit[j]);
- group=&ud->skillunit[j];
- }
- }
-
- if(group==NULL){
- ShowFatalError("skill_initunitgroup: error unit group !\n");
- exit(1);
- }
+ for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i]; i++);
+
+ if(i == MAX_SKILLUNITGROUP) {
+ int j=0;
+ unsigned maxdiff=0,x,tick=gettick();
+ for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++)
+ if((x=DIFF_TICK(tick,ud->skillunit[i]->tick))>maxdiff){
+ maxdiff=x;
+ j=i;
+ }
+ skill_delunitgroup(src, ud->skillunit[j]);
+ //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);
@@ -9439,34 +9435,36 @@ struct skill_unit_group *skill_initunitgroup(struct block_list *src,
* ƒXƒLƒ‹ƒ†ƒjƒbƒgƒOƒ‹?ƒv?í?œ
*------------------------------------------
*/
-int skill_delunitgroup(struct skill_unit_group *group)
+int skill_delunitgroup(struct block_list *src, struct skill_unit_group *group)
{
- struct block_list *src;
- int i;
+ struct unit_data *ud;
+ int i,j;
nullpo_retr(0, group);
if(group->unit_count<=0)
return 0;
- src=map_id2bl(group->src_id);
- //ƒ_ƒ“ƒXƒXƒLƒ‹‚̓_ƒ“ƒX?ó‘Ô‚ð‰ð?œ‚·‚é
- if(src) {
- if (skill_get_unit_flag(group->skill_id)&UF_DANCE)
+ if (!src) src=map_id2bl(group->src_id);
+ ud = unit_bl2ud(src);
+ if(!src || !ud) {
+ ShowError("skill_delunitgroup: Group's source not found! (src_id: %d skill_id: %d)\n", group->src_id, group->skill_id);
+ return 0;
+ }
+ if (skill_get_unit_flag(group->skill_id)&UF_DANCE)
+ {
+ struct status_change* sc = status_get_sc(src);
+ if (sc && sc->data[SC_DANCING].timer != -1)
{
- struct status_change* sc = status_get_sc(src);
- if (sc && sc->data[SC_DANCING].timer != -1)
- {
- sc->data[SC_DANCING].val2 = 0 ; //This prevents status_change_end attempting to redelete the group. [Skotlex]
- status_change_end(src,SC_DANCING,-1);
- }
+ sc->data[SC_DANCING].val2 = 0 ; //This prevents status_change_end attempting to redelete the group. [Skotlex]
+ status_change_end(src,SC_DANCING,-1);
}
+ }
- if (group->unit_id == UNT_GOSPEL) { //Clear Gospel [Skotlex]
- struct status_change *sc = status_get_sc(src);
- if(sc && sc->data[SC_GOSPEL].timer != -1) {
- sc->data[SC_GOSPEL].val3 = 0; //Remove reference to this group. [Skotlex]
- status_change_end(src,SC_GOSPEL,-1);
- }
+ if (group->unit_id == UNT_GOSPEL) { //Clear Gospel [Skotlex]
+ struct status_change *sc = status_get_sc(src);
+ if(sc && sc->data[SC_GOSPEL].timer != -1) {
+ sc->data[SC_GOSPEL].val3 = 0; //Remove reference to this group. [Skotlex]
+ status_change_end(src,SC_GOSPEL,-1);
}
}
@@ -9484,10 +9482,20 @@ int skill_delunitgroup(struct skill_unit_group *group)
map_freeblock((struct block_list*)group->unit); /* aFree()‚Ì‘Ö‚í‚è */
group->unit=NULL;
- group->src_id=0;
group->group_id=0;
group->unit_count=0;
- return 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) {
+ ud->skillunit[i] = ud->skillunit[j];
+ ud->skillunit[j] = NULL;
+ ers_free(skill_unit_ers, group);
+ } else
+ ShowError("skill_delunitgroup: Group not found! (src_id: %d skill_id: %d)\n", group->src_id, group->skill_id);
+ return 1;
}
/*==========================================
@@ -9497,16 +9505,11 @@ int skill_delunitgroup(struct skill_unit_group *group)
int skill_clear_unitgroup(struct block_list *src)
{
struct unit_data *ud = unit_bl2ud(src);
- int i;
- nullpo_retr(0, src);
nullpo_retr(0, ud);
- if(!ud) return 0;
-
- for(i=0;i<MAX_SKILLUNITGROUP;i++)
- if(ud->skillunit[i].group_id>0 && ud->skillunit[i].src_id == src->id)
- skill_delunitgroup(&ud->skillunit[i]);
+ while (ud->skillunit[0])
+ skill_delunitgroup(src, ud->skillunit[0]);
return 1;
}
@@ -9744,6 +9747,7 @@ int skill_unit_move_sub( struct block_list *bl, va_list ap )
}
if (flag&4)
skill_unit_onleft(skill_id,target,tick);
+
return 1;
}
@@ -11060,7 +11064,9 @@ void skill_reload(void)
int do_init_skill(void)
{
skill_readdb();
-
+
+ skill_unit_ers = ers_new((uint32)sizeof(struct skill_unit_group));
+
if (battle_config.skill_sp_override_grffile)
skill_read_skillspamount();
@@ -11074,3 +11080,8 @@ int do_init_skill(void)
return 0;
}
+
+int do_final_skill(void) {
+ ers_destroy(skill_unit_ers);
+ return 0;
+}
diff --git a/src/map/skill.h b/src/map/skill.h
index 42069c29c..2ba25b937 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -130,7 +130,7 @@ struct skill_unit;
struct skill_unit_group;
int do_init_skill(void);
-
+int do_final_skill(void);
//Returns the cast type of the skill: ground cast, castend damage, castend no damage
enum { CAST_GROUND, CAST_DAMAGE, CAST_NODAMAGE };
@@ -187,7 +187,7 @@ struct skill_unit *skill_initunit(struct skill_unit_group *group,int idx,int x,i
int skill_delunit(struct skill_unit *unit);
struct skill_unit_group *skill_initunitgroup(struct block_list *src,
int count,int skillid,int skilllv,int unit_id, int limit, int interval);
-int skill_delunitgroup(struct skill_unit_group *group);
+int skill_delunitgroup(struct block_list *src, struct skill_unit_group *group);
int skill_clear_unitgroup(struct block_list *src);
int skill_clear_element_field(struct block_list *bl);
diff --git a/src/map/status.c b/src/map/status.c
index d708a921c..ffba6e1e5 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -5021,7 +5021,7 @@ int status_change_end( struct block_list* bl , int type,int tid )
struct status_change *dsc;
if(sc->data[type].val2)
{
- skill_delunitgroup((struct skill_unit_group *)sc->data[type].val2);
+ skill_delunitgroup(bl, (struct skill_unit_group *)sc->data[type].val2);
sc->data[type].val2 = 0;
}
if(sc->data[type].val4 && sc->data[type].val4 != BCT_SELF && (dsd=map_id2sd(sc->data[type].val4))){
@@ -5131,7 +5131,7 @@ int status_change_end( struct block_list* bl , int type,int tid )
else if (sc->data[type].val3) { //Clear the group.
struct skill_unit_group *group = (struct skill_unit_group *)sc->data[type].val3;
sc->data[type].val3 = 0;
- skill_delunitgroup(group);
+ skill_delunitgroup(bl, group);
}
break;
case SC_HERMODE: