summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshennetsind <ind@henn.et>2015-03-14 23:18:53 -0300
committershennetsind <ind@henn.et>2015-03-14 23:18:53 -0300
commit8aee60e91807930e4d43965a20c8991b416d7f29 (patch)
tree9fcebc1a9017b7485859128bb29579456d607d18
parent2b71c036298756d294d10141ce6196a48d783930 (diff)
downloadhercules-8aee60e91807930e4d43965a20c8991b416d7f29.tar.gz
hercules-8aee60e91807930e4d43965a20c8991b416d7f29.tar.bz2
hercules-8aee60e91807930e4d43965a20c8991b416d7f29.tar.xz
hercules-8aee60e91807930e4d43965a20c8991b416d7f29.zip
Multiple SC fixes
First and foremost an ancient status_change_timer issue which'd cause a timer deletion error when an status within status_change_timer kills the unit. This commit also fixes some pointer/map-free-block logic which showed up while debugging status_change_timer. Special Thanks to Haruna. Signed-off-by: shennetsind <ind@henn.et>
-rw-r--r--src/map/status.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/src/map/status.c b/src/map/status.c
index b278324b0..c2b634665 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -9634,7 +9634,8 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t
}
break;
case SC_CASH_BOSS_ALARM:
- clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message
+ if( sd )
+ clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message
break;
case SC_MER_HP:
status_percent_heal(bl, 100, 0); // Recover Full HP
@@ -9778,7 +9779,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
nullpo_ret(bl);
sc = status->get_sc(bl);
- st = status->get_status_data(bl);
if(type < 0 || type >= SC_MAX || !sc || !(sce = sc->data[type]))
return 0;
@@ -9788,6 +9788,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
if (sce->timer != tid && tid != INVALID_TIMER)
return 0;
+ st = status->get_status_data(bl);
+
if( sd && sce->timer == INVALID_TIMER && !sd->state.loggingout )
chrif->del_scdata_single(sd->status.account_id,sd->status.char_id,type);
@@ -9969,7 +9971,9 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
}
sce->val2 = 0;
- skill->del_unitgroup(group,ALC_MARK);
+
+ if( group )
+ skill->del_unitgroup(group,ALC_MARK);
}
if ((sce->val1&0xFFFF) == CG_MOONLIT)
@@ -10072,7 +10076,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
if (sce->val3) { //Clear the group.
struct skill_unit_group* group = skill->id2group(sce->val3);
sce->val3 = 0;
- skill->del_unitgroup(group,ALC_MARK);
+ if( group )
+ skill->del_unitgroup(group,ALC_MARK);
}
break;
case SC_HERMODE:
@@ -10118,10 +10123,12 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
break;
// Note: vending/buying is closed by unit_remove_map, no
// need to do it here.
- map->quit(sd);
- // Because map->quit calls status_change_end with tid -1
- // from here it's not neccesary to continue
- return 1;
+ if( sd ) {
+ map->quit(sd);
+ // Because map->quit calls status_change_end with tid -1
+ // from here it's not neccesary to continue
+ return 1;
+ }
break;
case SC_STOP:
if( sce->val2 ) {
@@ -10227,7 +10234,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
struct block_list *src = map->id2bl(sce->val2);
if(src) {
struct status_change *ssc = status->get_sc(src);
- ssc->bs_counter--;
+ if( ssc )
+ ssc->bs_counter--;
}
}
break;
@@ -10568,6 +10576,8 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
ShowError("status_change_timer: Mismatch for type %d: %d != %d (bl id %d)\n",type,tid,sce->timer, bl->id);
return 0;
}
+
+ sce->timer = INVALID_TIMER;
sd = BL_CAST(BL_PC, bl);
@@ -10598,7 +10608,6 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
}
sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data);
return 0;
- break;
case SC_SKA:
if(--(sce->val2)>0) {
@@ -10927,6 +10936,8 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
}
if( !flag ) { // Random Skill Cast
+ map->freeblock_lock();
+
if (sd && !pc_issit(sd)) { //can't cast if sit
int mushroom_skill_id = 0;
unit->stop_attack(bl);
@@ -10950,7 +10961,10 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
}
clif->emotion(bl,E_HEH);
- sc_timer_next(4000+tick,status->change_timer,bl->id,data);
+ if( sc->data[type] )
+ sc_timer_next(4000+tick,status->change_timer,bl->id,data);
+
+ map->freeblock_unlock();
}
return 0;
}
@@ -10998,8 +11012,15 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
int heal = st->max_hp * 3 / 100;
if (sc->count && sc->data[SC_AKAITSUKI] && heal)
heal = ~heal + 1;
+
+ map->freeblock_lock();
+
status->heal(bl, heal, 0, 2);
- sc_timer_next(5000 + tick, status->change_timer, bl->id, data);
+ if( sc->data[type] ) {
+ sc_timer_next(5000 + tick, status->change_timer, bl->id, data);
+ }
+ map->freeblock_unlock();
+
return 0;
}
break;
@@ -11117,8 +11138,8 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
if ( sc->data[type] ) {
sc_timer_next(1000 + tick, status->change_timer, bl->id, data);
}
- map->freeblock_unlock();
status->heal(src, damage*(5 + 5 * sce->val1)/100, 0, 0); // 5 + 5% per level
+ map->freeblock_unlock();
return 0;
}
break;
@@ -11225,6 +11246,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
sc_timer_next(1000 + tick, status->change_timer, bl->id, data);
}
map->freeblock_unlock();
+ return 0;
}
break;
@@ -11305,12 +11327,13 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) {
case SC_WATER_DROP:
case SC_WIND_CURTAIN:
case SC_STONE_SHIELD:
- if(status->charge(bl, 0, sce->val2) && (sce->val4==-1 || (sce->val4-=sce->val3)>=0))
+ if(status->charge(bl, 0, sce->val2) && (sce->val4==-1 || (sce->val4-=sce->val3)>=0)) {
sc_timer_next(sce->val3 + tick, status->change_timer, bl->id, data);
- else
+ return 0;
+ } else
if (bl->type == BL_ELEM)
elemental->change_mode(BL_CAST(BL_ELEM,bl),MAX_ELESKILLTREE);
- return 0;
+ break;
case SC_STOMACHACHE:
if( --(sce->val4) > 0 ) {
@@ -11696,6 +11719,8 @@ int status_change_clear_buffs (struct block_list* bl, int type) {
if (!sc || !sc->count)
return 0;
+ map->freeblock_lock();
+
if (type&6) //Debuffs
for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++)
status_change_end(bl, (sc_type)i, INVALID_TIMER);
@@ -11742,6 +11767,9 @@ int status_change_clear_buffs (struct block_list* bl, int type) {
}
status_change_end(bl, (sc_type)i, INVALID_TIMER);
}
+
+ map->freeblock_unlock();
+
return 0;
}