Procházet zdrojové kódy

* Patches to allow everything to work right. + 1 more sample script.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@6779 54d463be-8e91-2dee-dedb-b68131a5f0ec
Lance před 19 roky
rodič
revize
2681e4127b

+ 1 - 0
Changelog-Trunk.txt

@@ -4,6 +4,7 @@ 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/26
+	* Patches to allow everything to work right. + 1 more sample script. [Lance]
 	* Mob control engine tested 99% working so far. [Lance]
 	* Change scripting engine's NPC scope vars to dot (.) style.
 	* Improved and (should be fully) fixed the mob control engine. [Lance]

+ 2 - 0
db/const.txt

@@ -710,6 +710,8 @@ AI_ACTION_TYPE_ATTACK	1
 AI_ACTION_TYPE_DETECT	2
 AI_ACTION_TYPE_DEAD	3
 AI_ACTION_TYPE_ASSIST	4
+AI_ACTION_TYPE_KILL	5
+AI_ACTION_TYPE_UNLOCK	6
 
 ALL_CLIENT	0
 ALL_SAMEMAP	1

+ 2 - 0
db/mob_avail.txt

@@ -28,6 +28,8 @@
 1902,14,1,6,6,1101,2105,0,0,0,32,3
 // Poki#3
 1903,4012,1,21,0,1720,0,102,184,57,16,0
+// Sentry
+1904,1286,0
 
 // eAthena Custom Equipped Mobs
 1970,1002,10013

+ 1 - 0
db/mob_db2.txt

@@ -19,6 +19,7 @@
 1901,VALARIS_WORSHIPPER,Valaris's Worshipper,Valaris's Worshipper,50,8578,0,2706,1480,1,487,590,15,25,1,75,55,1,93,45,10,12,0,6,27,1685,100,868,480,120,0,0,0,0,0,0,0,0,923,500,984,63,1464,2,607,50,610,100,503,300,2405,50,0,0,0,0,4129,1
 1902,MC_CAMERI,MC Cameri,MC Cameri,99,668000,0,107250,37895,2,3220,4040,35,45,1,152,96,85,120,95,10,10,2,6,67,1973,100,1068,768,576,13000,5000,608,1000,750,400,923,3800,1466,200,2256,200,2607,800,714,500,617,3000,984,4300,985,5600,0,0,0,0,4147,1
 1903,POKI,Poki#3,Poki#3,99,1349000,0,4093000,1526000,9,4892,9113,22,35,1,180,39,67,193,130,10,12,1,7,64,1973,120,500,672,480,92100,7000,603,5500,617,3000,1723,1000,1228,100,1236,500,617,2500,1234,75,1237,125,1722,250,1724,100,1720,50,0,0,0,0
+1904,SENTRY,Sentry,Sentry,99,668000,0,107250,37895,2,3220,4040,35,45,1,152,96,85,120,95,10,10,2,6,67,1973,100,1068,768,576,13000,5000,608,1000,750,400,923,3800,1466,200,2256,200,2607,800,714,500,617,3000,984,4300,985,5600,0,0,0,0,4147,1
 
 // Mobs used for eAthena's Custom Equipped Mobs
 1970,PORING_,Pet Poring,Pet Poring,1,50,0,2,1,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,131,400,1872,672,480,0,0,0,0,0,0,0,0,909,7000,1202,100,938,400,512,1000,713,1500,741,5,619,20,0,0,0,0,4001,20

+ 119 - 0
npc/custom/Lance/Sentry.cpp

@@ -0,0 +1,119 @@
+//(=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)
+//(        (c)2006 eAthena Development Team presents        )
+//(       ______  __    __                                  )
+//(      /\  _  \/\ \__/\ \                     v 1.00.00   )
+//(    __\ \ \_\ \ \ ,_\ \ \___      __    ___      __      )
+//(  /'__`\ \  __ \ \ \/\ \  _ `\  /'__`\/' _ `\  /'__`\    )
+//( /\  __/\ \ \/\ \ \ \_\ \ \ \ \/\  __//\ \/\ \/\ \_\.\_  )
+//( \ \____\\ \_\ \_\ \__\\ \_\ \_\ \____\ \_\ \_\ \__/.\_\ )
+//(  \/____/ \/_/\/_/\/__/ \/_/\/_/\/____/\/_/\/_/\/__/\/_/ )
+//(   _   _   _   _   _   _   _     _   _   _   _   _   _   )
+//(  / \ / \ / \ / \ / \ / \ / \   / \ / \ / \ / \ / \ / \  )
+//( ( e | A | t | h | e | n | a ) ( S | c | r | i | p | t ) )
+//(  \_/ \_/ \_/ \_/ \_/ \_/ \_/   \_/ \_/ \_/ \_/ \_/ \_/  )
+//(                                                         )
+//(=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)
+// Programmed by [Lance] ver. 1.0
+// ---------------------------------------------------------
+// [ Sentry System ]
+// - Guards main towns against aggresive monsters and bad
+//   players.
+// [ Customization ]
+// - See OnInit:
+// =========================================================
+
+-	script	sentry_system	-1,{
+	function spawn_guardian {
+		set .mob_id[getarg(0)], spawnmob("Guardian Sentry",1904,.mob_map$[getarg(0)],.mob_x[getarg(0)],.mob_y[getarg(0)]);
+		mobattach .mob_id[getarg(0)]; // Attach events to this script.
+		mobrandomwalk .mob_id[getarg(0)], 0; // Prevents random walking.
+		mobattack .mob_id[getarg(0)]; // Enable all viewing.
+		return;
+	}
+
+	function search_entry {
+		set .@tmp, getarraysize(getarg(0));
+		for(set .@i, 0; .@i < .@tmp; set .@i, .@i + 1){
+			if(getelementofarray(getarg(0),.@i) == getarg(1))
+				break;
+		}
+		if(.@i == .@tmp)
+			return -1;
+		else
+			return .@i;
+	}
+
+	// Script Entry Point - When an event from the script engine is received.
+	if(getarraysize(.ai_action) == 4){ // Checks if the data is formatted correctly.
+		set .@tmp, search_entry(.mob_id, .ai_action[AI_ACTION_SRC]);
+		switch(.ai_action[AI_ACTION_TYPE]){
+			case AI_ACTION_TYPE_DETECT: // We see something...
+				if(.ai_busy[.@tmp] == 0){ // Not busy
+					switch(.ai_action[AI_ACTION_TAR_TYPE]){ // Check what have we here.
+							case AI_ACTION_TAR_TYPE_PC: // It's a player
+								if(getd("$pkarma_"+.ai_action[AI_ACTION_TAR]) > .karma){ // pkarma is higher?
+									mobtalk .ai_action[AI_ACTION_SRC], "Who goes there!";
+									mobemote .ai_action[AI_ACTION_SRC], e_gasp; // !
+									mobattack .ai_action[AI_ACTION_SRC],.ai_action[AI_ACTION_TAR];
+									// We're currently busy.
+									set .ai_busy[.@tmp], .ai_action[AI_ACTION_TAR];
+								}
+								break;
+							case AI_ACTION_TAR_TYPE_MOB: // It's a monster
+								if(.ai_action[AI_ACTION_TAR] != .ai_action[AI_ACTION_SRC]){
+									getmobdata .ai_action[AI_ACTION_TAR], .@temp;
+									if(.@temp[9]&0x804){ // In Aggressive mode?
+										mobtalk .ai_action[AI_ACTION_SRC], "Protect the villagers we must!";
+										mobemote .ai_action[AI_ACTION_SRC], e_gasp; // !
+										mobattack .ai_action[AI_ACTION_SRC],.ai_action[AI_ACTION_TAR];
+										// We're currently busy.
+										set .ai_busy[.@tmp], .ai_action[AI_ACTION_TAR];
+									}
+								}
+								break;
+					}
+				}
+				break;
+			case AI_ACTION_TYPE_KILL: // We eliminated the criminal
+				if(.ai_action[AI_ACTION_TAR_TYPE] == AI_ACTION_TAR_TYPE_PC)
+					setd "$pkarma_"+.ai_action[AI_ACTION_TAR], 0;
+			case AI_ACTION_TYPE_UNLOCK: // Target lost :(
+				if(.@tmp != -1){
+					set .ai_busy[.@tmp], 0; // Remove him, we're free.
+				}
+				// Walk back to where we came from.
+				mobwalk .ai_action[AI_ACTION_SRC],.mob_x[.@tmp],.mob_y[.@tmp];
+				break;
+			case AI_ACTION_TYPE_DEAD: // We got killed :(
+				if(.ai_action[AI_ACTION_TAR_TYPE] == AI_ACTION_TAR_TYPE_PC){ // Attacker is a player?
+					setd "$pkarma_"+.ai_action[AI_ACTION_TAR], getd("$pkarma_"+.ai_action[AI_ACTION_TAR]) + 5;
+				}
+				sleep 10000; // 10 seconds until reinforcements arrive
+				spawn_guardian .@tmp;
+				break;
+			case AI_ACTION_TYPE_ATTACK: // Someone attacked us
+				if(.ai_action[AI_ACTION_TAR_TYPE] == AI_ACTION_TAR_TYPE_PC){ // Attacker is a player?
+					setd "$pkarma_"+.ai_action[AI_ACTION_TAR], getd("$pkarma_"+.ai_action[AI_ACTION_TAR]) + 1;
+				}
+				// The system's AI will auto attack any attackers. So we leave it here.
+				break;
+		}
+	}
+	deletearray .ai_action, getarraysize(.ai_action); // Cleans up and frees up memory
+	end;
+
+OnInit:
+	// Customization ---------------------------------------------------------------------
+	setarray .mob_map$, "prt_fild08.gat", "prt_fild05.gat", "prt_fild06.gat", "prt_gld.gat";
+	setarray .mob_x,176,369,29,165;
+	setarray .mob_y,372,201,187,37;
+	set .karma, 5;
+	// -----------------------------------------------------------------------------------
+	set .@tmp, getarraysize(.mob_map$);
+	for(set .@i, 0; .@i < .@tmp; set .@i, .@i + 1){
+		spawn_guardian .@i;
+	}
+	debugmes "[Sentry System] Spawned " + .@i + " guardians.";
+	end;
+
+}

+ 20 - 8
npc/sample/monster_controller.cpp

@@ -69,14 +69,26 @@ prontera.gat,180,200,4	script	Monster Controller	123,{
 				break;
 		}
 
-		if(.ai_action[AI_ACTION_TYPE] == AI_ACTION_TYPE_ATTACK)
-			set .@action_type$, "Attacked by";
-		else if(.ai_action[AI_ACTION_TYPE] == AI_ACTION_TYPE_DETECT)
-			set .@action_type$, "Detected";
-		else if (.ai_action[AI_ACTION_TYPE] == AI_ACTION_TYPE_ASSIST)
-			set .@action_type$, "Killed by";
-		else
-			set .@action_type$, "Assisting";
+		switch(.ai_action[AI_ACTION_TYPE]){
+			case AI_ACTION_TYPE_ATTACK:
+				set .@action_type$, "Attacked by";
+				break;
+			case AI_ACTION_TYPE_DETECT:
+				set .@action_type$, "Detected";
+				break;
+			case AI_ACTION_TYPE_DEAD:
+				set .@action_type$, "Killed by";
+				break;
+			case AI_ACTION_TYPE_ASSIST:
+				set .@action_type$, "Assisting";
+				break;
+			case AI_ACTION_TYPE_UNLOCK:
+				set .@action_type$, "Unlocked target";
+				break;
+			case AI_ACTION_TYPE_KILL:
+				set .@action_type$, "Killed";
+				break;
+		}
 
 		announce "Details - " + .@action_type$ + " [" + .@action_from$ + "] " + .@action_name$ + "!", bc_all;
 		deletearray .ai_action, 4;

+ 2 - 1
npc/scripts_custom.conf

@@ -20,7 +20,6 @@
 //npc: npc/location/to/script.txt
 //                     Your scripts go here!!
 // --------------------------------------------------------------
-//npc: npc/sample/monster_controller.cpp
 // ----------------------- Basic  Scripts -----------------------
 // -- Adoption NPC [Fredzilla]
 npc: npc/custom/adoption.txt
@@ -91,6 +90,8 @@ npc: npc/custom/adoption.txt
 //npc: npc/custom/Lance/FR_WeatherController.c
 //npc: npc/custom/Lance/FR_MailSystem.c
 //npc: npc/sample/npc_dynamic_shop.txt
+//npc: npc/sample/monster_controller.cpp
+//npc: npc/custom/Lance/Sentry.cpp
 // --------------------------------------------------------------
 
 // --------------------------------------------------------------

+ 21 - 1
src/map/mob.c

@@ -808,7 +808,7 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
 		setd_sub(NULL, NULL, ".ai_action", 2, (void *)bl->id, &md->nd->u.scr.script->script_vars);
 		setd_sub(NULL, NULL, ".ai_action", 3, (void *)md->bl.id, &md->nd->u.scr.script->script_vars);
 		run_script(md->nd->u.scr.script, 0, 0, md->nd->bl.id);
-		return 0; // We have script handling the work.
+		return 1; // We have script handling the work.
 	}
 
 	if(battle_check_target(&md->bl,bl,BCT_ENEMY)<=0)
@@ -997,6 +997,15 @@ int mob_unlocktarget(struct mob_data *md,int tick)
 {
 	nullpo_retr(0, md);
 
+	if(md->nd){
+		struct block_list *tbl = map_id2bl(md->target_id);
+		setd_sub(NULL, NULL, ".ai_action", 0, (void *)(int)6, &md->nd->u.scr.script->script_vars);
+		setd_sub(NULL, NULL, ".ai_action", 1, (void *)(int)(tbl?tbl->type:0), &md->nd->u.scr.script->script_vars);
+		setd_sub(NULL, NULL, ".ai_action", 2, (void *)(tbl?tbl->id:0), &md->nd->u.scr.script->script_vars);
+		setd_sub(NULL, NULL, ".ai_action", 3, (void *)md->bl.id, &md->nd->u.scr.script->script_vars);
+		run_script(md->nd->u.scr.script, 0, 0, md->nd->bl.id);
+	}
+
 	md->target_id=0;
 	md->state.skillstate=MSS_IDLE;
 	md->next_walktime=tick+rand()%3000+3000;
@@ -2160,6 +2169,17 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
 			guild_agit_break(md);
 	}
 
+	if(src->type == BL_MOB){
+		struct mob_data *smd = (struct mob_data *)src;
+		if(smd->nd){
+			setd_sub(NULL, NULL, ".ai_action", 0, (void *)(int)5, &smd->nd->u.scr.script->script_vars);
+			setd_sub(NULL, NULL, ".ai_action", 1, (void *)(int)md->bl.type, &smd->nd->u.scr.script->script_vars);
+			setd_sub(NULL, NULL, ".ai_action", 2, (void *)md->bl.id, &smd->nd->u.scr.script->script_vars);
+			setd_sub(NULL, NULL, ".ai_action", 3, (void *)smd->bl.id, &smd->nd->u.scr.script->script_vars);
+			run_script(smd->nd->u.scr.script, 0, 0, smd->nd->bl.id);
+		}
+	}
+
 	if(md->nd){
 		setd_sub(NULL, NULL, ".ai_action", 0, (void *)(int)3, &md->nd->u.scr.script->script_vars);
 		setd_sub(NULL, NULL, ".ai_action", 1, (void *)(int)src->type, &md->nd->u.scr.script->script_vars);

+ 40 - 29
src/map/pc.c

@@ -4527,37 +4527,48 @@ int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
 	}
 	clif_clearchar_area(&sd->bl,1);
 
-	if (src && src->type == BL_PC) {
-		struct map_session_data *ssd = (struct map_session_data *)src;
-		if (ssd) {
-			if (sd->state.event_death)
-				pc_setglobalreg(sd,"killerrid",(ssd->status.account_id));
-			if (ssd->state.event_kill_pc) {
-				pc_setglobalreg(ssd, "killedrid", sd->bl.id);
-				npc_script_event(ssd, NPCE_KILLPC);
+	if (src) {
+		if(src->type == BL_MOB){
+			struct mob_data *smd = (struct mob_data *)src;
+			if(smd->nd){
+				setd_sub(NULL, NULL, ".ai_action", 0, (void *)(int)5, &smd->nd->u.scr.script->script_vars);
+				setd_sub(NULL, NULL, ".ai_action", 1, (void *)(int)sd->bl.type, &smd->nd->u.scr.script->script_vars);
+				setd_sub(NULL, NULL, ".ai_action", 2, (void *)sd->bl.id, &smd->nd->u.scr.script->script_vars);
+				setd_sub(NULL, NULL, ".ai_action", 3, (void *)smd->bl.id, &smd->nd->u.scr.script->script_vars);
+				run_script(smd->nd->u.scr.script, 0, 0, smd->nd->bl.id);
 			}
-			if (battle_config.pk_mode && ssd->status.manner >= 0 && battle_config.manner_system) {
-				ssd->status.manner -= 5;
-				if(ssd->status.manner < 0)
-					sc_start(src,SC_NOCHAT,100,0,0);
-
-			// PK/Karma system code (not enabled yet) [celest]
-			// originally from Kade Online, so i don't know if any of these is correct ^^;
-			// note: karma is measured REVERSE, so more karma = more 'evil' / less honourable,
-			// karma going down = more 'good' / more honourable.
-			// The Karma System way...
-				/*if (sd->status.karma > ssd->status.karma) {	// If player killed was more evil
-					sd->status.karma--;
-					ssd->status.karma--;
+		} else if(src->type == BL_PC){
+			struct map_session_data *ssd = (struct map_session_data *)src;
+			if (ssd) {
+				if (sd->state.event_death)
+					pc_setglobalreg(sd,"killerrid",(ssd->status.account_id));
+				if (ssd->state.event_kill_pc) {
+					pc_setglobalreg(ssd, "killedrid", sd->bl.id);
+					npc_script_event(ssd, NPCE_KILLPC);
+				}
+				if (battle_config.pk_mode && ssd->status.manner >= 0 && battle_config.manner_system) {
+					ssd->status.manner -= 5;
+					if(ssd->status.manner < 0)
+						sc_start(src,SC_NOCHAT,100,0,0);
+
+				// PK/Karma system code (not enabled yet) [celest]
+				// originally from Kade Online, so i don't know if any of these is correct ^^;
+				// note: karma is measured REVERSE, so more karma = more 'evil' / less honourable,
+				// karma going down = more 'good' / more honourable.
+				// The Karma System way...
+					/*if (sd->status.karma > ssd->status.karma) {	// If player killed was more evil
+						sd->status.karma--;
+						ssd->status.karma--;
+					}
+					else if (sd->status.karma < ssd->status.karma)	// If player killed was more good
+						ssd->status.karma++;*/
+
+				// or the PK System way...
+					/* if (sd->status.karma > 0)	// player killed is dishonourable?
+						ssd->status.karma--; // honour points earned
+					sd->status.karma++;	// honour points lost */
+					// To-do: Receive exp on certain occasions
 				}
-				else if (sd->status.karma < ssd->status.karma)	// If player killed was more good
-					ssd->status.karma++;*/
-
-			// or the PK System way...
-				/* if (sd->status.karma > 0)	// player killed is dishonourable?
-					ssd->status.karma--; // honour points earned
-				sd->status.karma++;	// honour points lost */
-				// To-do: Receive exp on certain occasions
 			}
 		}
 	} else {

+ 26 - 25
src/map/script.c

@@ -10514,37 +10514,38 @@ int buildin_getmobdata(struct script_state *st) {
 	int num, id;
 	char *name;
 	struct mob_data *md = NULL;
+	struct map_session_data *sd = st->rid?map_id2sd(st->rid):NULL;
 	id = conv_num(st, & (st->stack->stack_data[st->start+2]));
 	if(!(md = (struct mob_data *)map_id2bl(id)) || st->stack->stack_data[st->start+3].type!=C_NAME ){
 		ShowWarning("buildin_getmobdata: Error in argument!\n");
 	} else {
 		num=st->stack->stack_data[st->start+3].u.num;
 		name=(char *)(str_buf+str_data[num&0x00ffffff].str);
-		setd_sub(st,map_id2sd(st->rid),name,0,(void *)(int)md->class_,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,1,(void *)(int)md->level,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,2,(void *)(int)md->hp,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,3,(void *)(int)md->max_hp,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,4,(void *)(int)md->master_id,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,5,(void *)(int)md->bl.m,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,6,(void *)(int)md->bl.x,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,7,(void *)(int)md->bl.y,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,8,(void *)(int)md->speed,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,9,(void *)(int)md->mode,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,10,(void *)(int)md->special_state.ai,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,11,(void *)(int)md->db->option,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,12,(void *)(int)md->vd->sex,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,13,(void *)(int)md->vd->class_,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,14,(void *)(int)md->vd->hair_style,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,15,(void *)(int)md->vd->hair_color,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,16,(void *)(int)md->vd->head_bottom,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,17,(void *)(int)md->vd->head_mid,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,18,(void *)(int)md->vd->head_top,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,19,(void *)(int)md->vd->cloth_color,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,20,(void *)(int)md->vd->shield,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,21,(void *)(int)md->vd->weapon,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,22,(void *)(int)md->vd->shield,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,23,(void *)(int)md->ud.dir,NULL);
-		setd_sub(st,map_id2sd(st->rid),name,24,(void *)(int)md->state.killer,NULL);
+		setd_sub(st,sd,name,0,(void *)(int)md->class_,NULL);
+		setd_sub(st,sd,name,1,(void *)(int)md->level,NULL);
+		setd_sub(st,sd,name,2,(void *)(int)md->hp,NULL);
+		setd_sub(st,sd,name,3,(void *)(int)md->max_hp,NULL);
+		setd_sub(st,sd,name,4,(void *)(int)md->master_id,NULL);
+		setd_sub(st,sd,name,5,(void *)(int)md->bl.m,NULL);
+		setd_sub(st,sd,name,6,(void *)(int)md->bl.x,NULL);
+		setd_sub(st,sd,name,7,(void *)(int)md->bl.y,NULL);
+		setd_sub(st,sd,name,8,(void *)(int)md->speed,NULL);
+		setd_sub(st,sd,name,9,(void *)(int)(md->mode?md->mode:md->db->mode),NULL);
+		setd_sub(st,sd,name,10,(void *)(int)md->special_state.ai,NULL);
+		setd_sub(st,sd,name,11,(void *)(int)md->db->option,NULL);
+		setd_sub(st,sd,name,12,(void *)(int)md->vd->sex,NULL);
+		setd_sub(st,sd,name,13,(void *)(int)md->vd->class_,NULL);
+		setd_sub(st,sd,name,14,(void *)(int)md->vd->hair_style,NULL);
+		setd_sub(st,sd,name,15,(void *)(int)md->vd->hair_color,NULL);
+		setd_sub(st,sd,name,16,(void *)(int)md->vd->head_bottom,NULL);
+		setd_sub(st,sd,name,17,(void *)(int)md->vd->head_mid,NULL);
+		setd_sub(st,sd,name,18,(void *)(int)md->vd->head_top,NULL);
+		setd_sub(st,sd,name,19,(void *)(int)md->vd->cloth_color,NULL);
+		setd_sub(st,sd,name,20,(void *)(int)md->vd->shield,NULL);
+		setd_sub(st,sd,name,21,(void *)(int)md->vd->weapon,NULL);
+		setd_sub(st,sd,name,22,(void *)(int)md->vd->shield,NULL);
+		setd_sub(st,sd,name,23,(void *)(int)md->ud.dir,NULL);
+		setd_sub(st,sd,name,24,(void *)(int)md->state.killer,NULL);
 	}
 	return 0;
 }

+ 2 - 2
src/map/unit.c

@@ -1084,8 +1084,8 @@ int unit_attack(struct block_list *src,int target_id,int type)
 		return 0;
 	}
 
-	if(battle_check_target(src,target,BCT_ENEMY)<=0 ||
-		!status_check_skilluse(src, target, 0, 0)
+	if(!(src->type == BL_MOB && !((TBL_MOB *)src)->state.killer) && (battle_check_target(src,target,BCT_ENEMY)<=0 ||
+		!status_check_skilluse(src, target, 0, 0))
 	) {
 		unit_unattackable(src);
 		return 1;