Bläddra i källkod

- Removed the on-die specific code from unit_remove_map and placed it on the corresponding *_dead functions. unit_remove_map should never assume the char died, it is just a "remove from map" function.
- Updated status_damage to handle the general death code (clearing status changes, clearing skill related data, sending death packet, etc). The return value from the *_dead functions will tell it what to do or not with the object (death aborted, clear it from map/memory, etc)
- Cleaned up pc_dead to take advantage of the fact that status changes are not ended until after the function.


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@6852 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex 19 år sedan
förälder
incheckning
1d027c8db8
8 ändrade filer med 111 tillägg och 94 borttagningar
  1. 9 0
      Changelog-Trunk.txt
  2. 2 3
      src/map/atcommand.c
  3. 1 7
      src/map/mercenary.c
  4. 20 17
      src/map/mob.c
  5. 17 29
      src/map/pc.c
  6. 3 3
      src/map/script.c
  7. 56 10
      src/map/status.c
  8. 3 25
      src/map/unit.c

+ 9 - 0
Changelog-Trunk.txt

@@ -4,6 +4,15 @@ 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/05/30
+	* Removed the on-die specific code from unit_remove_map and placed it on
+	  the corresponding *_dead functions. unit_remove_map should never assume the
+	  char died, it is just a "remove from map" function. [Skotlex]
+	* Updated status_damage to handle the general death code (clearing status
+	  changes, clearing skill related data, sending death packet, etc). The
+	  return value from the *_dead functions will tell it what to do or not with
+	  the object (death aborted, clear it from map/memory, etc) [Skotlex]
+	* Cleaned up pc_dead to take advantage of the fact that status changes are
+	  not ended until after the function. [Skotlex]
 	* Disabled ontouch npcs triggering on hidden/chase-walk characters. 
 	  [Skotlex]
 	* Updated/adapted current Homun code to use the status_data update.

+ 2 - 3
src/map/atcommand.c

@@ -3690,9 +3690,8 @@ static int atkillmonster_sub(struct block_list *bl, va_list ap) {
 	
 	if (flag)
 		status_kill(bl);
-	else
-		unit_remove_map(&md->bl,1);
-	
+	else //FIXME: Eh.. what exactly is the difference here?
+		status_kill(bl);	
 	return 1;
 }
 void atcommand_killmonster_sub(

+ 1 - 7
src/map/mercenary.c

@@ -102,14 +102,8 @@ void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp)
 int merc_dead(struct homun_data *hd, struct block_list *src)
 {
 	//dead lol
-	clif_clearchar((struct block_list*)hd,1);
-	hd->bl.m = 0;
-	hd->bl.x = 0;
-	hd->bl.y = 0;	//send it somewhere where it doesn't bother us
 	merc_save(hd);
-	clif_clearchar_area(&hd->bl,0);
-	map_delblock(&hd->bl);	
-	return 1;
+	return 3; //Remove it from map.
 }
 
 void merc_skillup(struct map_session_data *sd,short skillnum)

+ 20 - 17
src/map/mob.c

@@ -883,10 +883,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
 	bl=map_id2bl(md->master_id);
 
 	if (!bl || status_isdead(bl)) {	//主が死亡しているか見つからない
-		if(md->special_state.ai)
-			unit_remove_map(&md->bl, 1);
-		else
-			status_kill(&md->bl);
+		status_kill(&md->bl);
 		return 0;
 	}
 
@@ -921,10 +918,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
 		}	
 	} 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]
-		if(md->special_state.ai)
-			unit_remove_map(&md->bl, 1);
-		else
-			status_kill(&md->bl);
+		status_kill(&md->bl);
 		return 0;
 	}
 	
@@ -1695,19 +1689,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 	}
 
 	md->state.skillstate = MSS_DEAD;	
-	md->status.hp = 1; //Otherwise skill will be blocked due to being dead! [Skotlex]
 	mobskill_use(md,tick,-1);	//On Dead skill.
-	md->status.hp = 0;
 
 	if (md->sc.data[SC_KAIZEL].timer != -1)
 	{	//Revive in a bit.
-		mob_unlocktarget(md,tick);
-		mob_stop_walking(md, 0);
-		clif_clearchar_area(&md->bl,1);
 		add_timer(gettick()+3000, mob_respawn, md->bl.id, 10*md->sc.data[SC_KAIZEL].val1); //% of life to rebirth with
-		status_change_end(&md->bl, SC_KAIZEL, -1);
 		map_delblock(&md->bl);
-		return 0;
+		return 1; //Return 1 to only clear the object.
 	}
 
 	map_freeblock_lock();
@@ -2134,9 +2122,24 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			npc_script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance]
 	}
 	if(md->level) md->level=0;
+
+	if(md->deletetimer!=-1) {
+		delete_timer(md->deletetimer,mob_timer_delete);
+		md->deletetimer=-1;
+	}
+	if(pcdb_checkid(md->vd->class_)) //Player mobs are not removed automatically by the client.
+		clif_clearchar_delay(tick+3000,&md->bl,0);
+
+	mob_deleteslave(md);
+	md->last_deadtime=tick;
+	
 	map_freeblock_unlock();
-	unit_remove_map(&md->bl,1);
-	return 1;
+
+	if(!md->spawn) //Tell status_damage to remove it from memory.
+		return 5;
+	
+	mob_setdelayspawn(md); //Set respawning.
+	return 3; //Remove from map.
 }
 
 void mob_revive(struct mob_data *md, unsigned int hp)

+ 17 - 29
src/map/pc.c

@@ -4432,9 +4432,8 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h
 
 int pc_dead(struct map_session_data *sd,struct block_list *src)
 {
-	int i=0,j=0,resurrect_flag=0,baby_flag=0;
+	int i=0,j=0;
 	unsigned int tick = gettick();
-	struct status_data *status = &sd->battle_status;
 		
 	if(sd->vender_id)
 		vending_closevending(sd);
@@ -4458,20 +4457,8 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		if(sd->duel_invite > 0)
 			duel_reject(sd->duel_invite, sd);
 	}
-
-	//SC data that will be needed later on.
-	resurrect_flag = (sd->sc.data[SC_KAIZEL].timer != -1)?sd->sc.data[SC_KAIZEL].val1:0;
-	baby_flag = (sd->sc.data[SC_BABY].timer != -1)?1:0;
 	
-	pc_stop_attack(sd);
-	pc_stop_walking(sd,0);
-	unit_skillcastcancel(&sd->bl,0);
-	clif_clearchar_area(&sd->bl,1);
 	pc_setdead(sd);
-	skill_unit_move(&sd->bl,tick,4);
-	if (battle_config.clear_unit_ondeath)
-		skill_clear_unitgroup(&sd->bl); //orn
-	status_change_clear(&sd->bl,0);
 	sd->canregen_tick = tick;
 	
 	pc_setglobalreg(sd,"PC_DIE_COUNTER",++sd->die_counter);
@@ -4599,7 +4586,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 	if(battle_config.death_penalty_type && sd->state.snovice_flag != 4
 		&& (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE	// only novices will receive no penalty
 		&& !map[sd->bl.m].flag.nopenalty && !map_flag_gvg(sd->bl.m)
-		&& !baby_flag)
+		&& sd->sc.data[SC_BABY].timer == -1)
 	{
 		unsigned int base_penalty =0;
 		if (battle_config.death_penalty_base > 0) {
@@ -4715,27 +4702,28 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		return 1;
 	}
 
-	if (sd->state.snovice_flag == 4 || resurrect_flag)
+	if (sd->sc.count && sd->sc.data[SC_KAIZEL].timer != -1)
 	{
 		clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,1,1);
-		pc_setstand(sd);
-		status->hp = 1;
-		if (sd->state.snovice_flag == 4 ||
-			sd->special_state.restart_full_recover) {
+		if(sd->special_state.restart_full_recover)
 			status_percent_heal(&sd->bl, 100, 100);
-		} else { //10% life per each level in Kaizel
-			status_percent_heal(&sd->bl, 10*resurrect_flag, 0);
-		}
-		clif_updatestatus(sd, SP_HP);
-		clif_updatestatus(sd, SP_SP);
+		else
+			status_percent_heal(&sd->bl, 10*sd->sc.data[SC_KAIZEL].val1, 0);
+		if(battle_config.pc_invincible_time)
+			pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
+		sc_start(&sd->bl,SkillStatusChangeTable[PR_KYRIE],100,10,skill_get_time2(SL_KAIZEL,sd->sc.data[SC_KAIZEL].val1));
+		status_change_end(&sd->bl,SC_KAIZEL,-1);
+		return 0;
+	}
+	if (sd->state.snovice_flag == 4)
+	{
+		clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,1,1);
+		status_percent_heal(&sd->bl, 100, 100);
 		clif_resurrection(&sd->bl, 1);
 		sd->state.snovice_flag = 0;
 		if(battle_config.pc_invincible_time)
 			pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
-		if (resurrect_flag)
-			sc_start(&sd->bl,SkillStatusChangeTable[PR_KYRIE],100,10,skill_get_time2(SL_KAIZEL, resurrect_flag));
-		else
-			sc_start(&sd->bl,SkillStatusChangeTable[MO_STEELBODY],100,1,skill_get_time(MO_STEELBODY,1));
+		sc_start(&sd->bl,SkillStatusChangeTable[MO_STEELBODY],100,1,skill_get_time(MO_STEELBODY,1));
 		return 0;
 	}
 

+ 3 - 3
src/map/script.c

@@ -5732,11 +5732,11 @@ int buildin_killmonster_sub(struct block_list *bl,va_list ap)
 
 	if(!allflag){
 		if(strcmp(event,md->npc_event)==0)
-			unit_remove_map(bl,1);
+			status_kill(bl);
 		return 0;
 	}else{
 		if(!md->spawn)
-			unit_remove_map(bl,1);
+			status_kill(bl);
 		return 0;
 	}
 	return 0;
@@ -5760,7 +5760,7 @@ int buildin_killmonster(struct script_state *st)
 
 int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
 {
-	unit_remove_map(bl,1);
+	status_kill(bl);
 	return 0;
 }
 int buildin_killmonsterall(struct script_state *st)

+ 56 - 10
src/map/status.c

@@ -584,23 +584,69 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 	{
 		case BL_MOB:
 			mob_damage((TBL_MOB*)target, src, hp);
-			if (!status->hp)
-				mob_dead((TBL_MOB*)target, src, flag&4?3:0);
 			break;
 		case BL_PC:
 			pc_damage((TBL_PC*)target,src,hp,sp);
-			if (!status->hp)
-				pc_dead((TBL_PC*)target,src);
 			break;
 		case BL_HOMUNCULUS:
 			merc_damage((TBL_HOMUNCULUS*)target,src,hp,sp);
-			if (!status->hp)
-				merc_dead((TBL_HOMUNCULUS*)target,src);
 	}
-	
-	if (walkdelay && status->hp)
-		unit_set_walkdelay(target, gettick(), walkdelay, 0);
-	
+
+	if (status->hp)
+  	{	//Still lives!
+		if (walkdelay)
+			unit_set_walkdelay(target, gettick(), walkdelay, 0);
+		return hp+sp;
+	}
+
+	status->hp = 1; //To let the dead function cast skills and all that.
+	//NOTE: These dead functions should return: [Skotlex]
+	//0: Death cancelled, auto-revived.
+	//Non-zero: Standard death. Clear status, cancel move/attack, etc
+	//&2: Also remove object from map.
+	//&4: Also delete object from memory.
+	switch (target->type)
+	{
+		case BL_MOB:
+			flag = mob_dead((TBL_MOB*)target, src, flag&4?3:0);
+			break;
+		case BL_PC:
+			flag = pc_dead((TBL_PC*)target,src);
+			break;
+		case BL_HOMUNCULUS:
+			flag = merc_dead((TBL_HOMUNCULUS*)target,src);
+			break;
+		default:	//Unhandled case, do nothing to object.
+			flag = 0;
+			break;
+	}
+
+	if(!flag) //Death cancelled.
+		return hp+sp;
+  
+	//Normal death
+	if (battle_config.clear_unit_ondeath &&
+		battle_config.clear_unit_ondeath&target->type)
+		skill_clear_unitgroup(target);
+	status_change_clear(target,0);
+
+	if(flag&2) //remove the unit from the map.
+		unit_remove_map(target,1);
+	else { //These are handled by unit_remove_map.
+		unit_stop_attack(target);
+		unit_stop_walking(target,0);
+		unit_skillcastcancel(target,0);
+		clif_clearchar_area(target,1);
+		skill_unit_move(target,gettick(),4);
+		skill_cleartimerskill(target);
+	}
+
+	if(flag&4) { //Delete from memory.
+		map_delblock(target);
+		unit_free(target);
+	}
+
+		
 	return hp+sp;
 }
 

+ 3 - 25
src/map/unit.c

@@ -1433,6 +1433,7 @@ int unit_changeviewsize(struct block_list *bl,short size)
  * Returns 1 on success. 0 if it couldn't be removed or the bl was free'd
  * if clrtype is 1 (death), appropiate cleanup is performed. 
  * Otherwise it is assumed bl is being warped.
+ * On-Kill specific stuff is not performed here, look at status_damage for that.
  *------------------------------------------
  */
 int unit_remove_map(struct block_list *bl, int clrtype) {
@@ -1455,9 +1456,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) {
 	ud->attackabletime = ud->canmove_tick = ud->canact_tick = gettick();
 	clif_clearchar_area(bl,clrtype);
 	
-	if (clrtype == 1) //Death. Remove all status changes.
-		status_change_clear(bl,0);
-	else if(sc && sc->count ) { //map-change/warp dispells.
+	if(sc && sc->count ) { //map-change/warp dispells.
 		if(sc->data[SC_BLADESTOP].timer!=-1)
 			status_change_end(bl,SC_BLADESTOP,-1);
 		if(sc->data[SC_BASILICA].timer!=-1)
@@ -1488,9 +1487,6 @@ int unit_remove_map(struct block_list *bl, int clrtype) {
 			status_change_end(bl, SC_GOSPEL, -1);
 	}
 
-	if (clrtype == 1 && battle_config.clear_unit_ondeath && //Clrtype 1 = died.
-		battle_config.clear_unit_ondeath&bl->type)
-		skill_clear_unitgroup(bl);			// スキルユニットグループの削除
 	if (bl->type&BL_CHAR) {
 		skill_unit_move(bl,gettick(),4);
 		skill_cleartimerskill(bl);			// タイマースキルクリア
@@ -1537,25 +1533,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) {
 		struct mob_data *md = (struct mob_data*)bl;
 		md->target_id=0;
 		md->attacked_id=0;
-		md->state.skillstate= clrtype==1?MSS_DEAD:MSS_IDLE;
-		if (md->master_id) md->master_dist = 0;
-		if (clrtype == 1) { //Death.
-			md->last_deadtime=gettick();
-			if(md->deletetimer!=-1)
-				delete_timer(md->deletetimer,mob_timer_delete);
-			md->deletetimer=-1;
-			if(pcdb_checkid(md->vd->class_)) //Player mobs are not removed automatically by the client.
-				clif_clearchar_delay(gettick()+3000,bl,0);
-			mob_deleteslave(md);
-
-			if(!md->spawn) {
-				map_delblock(bl);
-				unit_free(bl); //Mob does not respawn.
-				map_freeblock_unlock();
-				return 0;
-			}
-			mob_setdelayspawn(md); //Set respawning.
-		}
+		md->state.skillstate= MSS_IDLE;
 	} else if (bl->type == BL_PET) {
 		struct pet_data *pd = (struct pet_data*)bl;
 		struct map_session_data *sd = pd->msd;