Browse Source

- Added sd variables menuskill_id/menuskill_lv to store menu-based selections. These are used now to check the validity of skill use instead of sd->skillid/sd->skilllv
- Affected skills/packets: AC_MAKINGARROW/ AL_WARP/ AL_TELEPORT/ AM_PHARMACY (all refine functions)/ MC_IDENTIFY/ BS_REPAIRWEAPON/ SA_TAMINGMONSTER/ SA_AUTOSPELL/ WS_WEAPONREFINE/ SG_FEEL
- Removed feel_lv and repair_target variables as now they are handled by the previous two new variables.


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

skotlex 19 years ago
parent
commit
bc1aad166c
7 changed files with 180 additions and 106 deletions
  1. 14 0
      Changelog-Trunk.txt
  2. 132 71
      src/map/clif.c
  3. 3 3
      src/map/clif.h
  4. 2 3
      src/map/map.h
  5. 0 1
      src/map/pc.c
  6. 1 2
      src/map/script.c
  7. 28 26
      src/map/skill.c

+ 14 - 0
Changelog-Trunk.txt

@@ -5,6 +5,20 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.  EV
 GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS
 
 2006/02/20
+	* Menu-based skills now use their own variables separetly from the normal
+	  skill variables. This should enable them to work even when you keep doing
+	  other stuff between the menu invocation and selection. Also gives a better
+	  control over packet-based exploits. Affected skill/script-commands are:
+	  [Skotlex]
+	- Arrow Crafting
+	- Warp Portal / Teleport
+	- Item producing
+	- Identify
+	- Repair weapon
+	- Pet egg selection
+	- Hindsight
+	- Weapon refine.
+	- Feel of the Stars, Moon and Stars.
 	* Corrected the implementation of Gangster's Paradise to work as it should.
 	  [Skotlex]
 	* Fixed Close-confine not properly ending on a knockback (that includes

+ 132 - 71
src/map/clif.c

@@ -156,7 +156,13 @@ enum {
 
 //To make the assignation of the level based on limits clearer/easier. [Skotlex]
 #define clif_setlevel(lv) (lv<battle_config.max_lv?lv:battle_config.max_lv-(lv<battle_config.aura_lv?1:0));
-	
+
+//Quick check to know if the player shouldn't be "busy" with something else to deny action requests. [Skotlex]
+#define clif_cant_act(sd) (sd->npc_id || sd->npc_shopid || sd->vender_id || sd->chatID || (sd->sc.opt1 && sd->sc.opt1 != OPT1_STONEWAIT) || sd->trade_partner || sd->state.storage_flag)
+
+// Checks if SD is in a trade/shop (where messing with the inventory can cause problems/exploits)
+#define clif_trading(sd) (sd->npc_id || sd->npc_shopid || sd->vender_id || sd->trade_partner)
+
 static char map_ip_str[16];
 static in_addr_t map_ip;
 static in_addr_t bind_ip = INADDR_ANY;
@@ -3443,7 +3449,10 @@ int clif_arrow_create_list(struct map_session_data *sd)
 	}
 	WFIFOW(fd,2) = c*2+4;
 	WFIFOSET(fd, WFIFOW(fd,2));
-	if (c > 0) sd->state.produce_flag = 1;
+	if (c > 0) {
+		sd->menuskill_id = AC_MAKINGARROW;
+		sd->menuskill_lv = c;
+	}
 
 	return 0;
 }
@@ -5328,7 +5337,7 @@ int clif_skill_delunit(struct skill_unit *unit)
  * ワープ場所選択
  *------------------------------------------
  */
-int clif_skill_warppoint(struct map_session_data *sd,int skill_num,
+int clif_skill_warppoint(struct map_session_data *sd,int skill_num, int skill_lv,
 	const char *map1,const char *map2,const char *map3,const char *map4)
 {
 	int fd;
@@ -5344,6 +5353,8 @@ int clif_skill_warppoint(struct map_session_data *sd,int skill_num,
 	strncpy((char*)WFIFOP(fd,36),map3,MAP_NAME_LENGTH);
 	strncpy((char*)WFIFOP(fd,52),map4,MAP_NAME_LENGTH);
 	WFIFOSET(fd,packet_len_table[0x11c]);
+	sd->menuskill_id = skill_num;
+	sd->menuskill_lv = skill_lv;
 	return 0;
 }
 /*==========================================
@@ -5425,11 +5436,13 @@ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst)
  * アイテム合成可能リスト
  *------------------------------------------
  */
-int clif_skill_produce_mix_list(struct map_session_data *sd,int trigger)
+int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger)
 {
 	int i,c,view,fd;
 	nullpo_retr(0, sd);
 
+	if(sd->menuskill_id == AM_PHARMACY)
+		return 0; //Avoid resending the menu twice or more times...
 	fd=sd->fd;
 	WFIFOHEAD(fd, MAX_SKILL_PRODUCE_DB * 8 + 8);
 	WFIFOW(fd, 0)=0x18d;
@@ -5447,7 +5460,11 @@ int clif_skill_produce_mix_list(struct map_session_data *sd,int trigger)
 	}
 	WFIFOW(fd, 2)=c*8+8;
 	WFIFOSET(fd,WFIFOW(fd,2));
-	if(c > 0) sd->state.produce_flag = 1;
+	if(c > 0) {
+		sd->menuskill_id = AM_PHARMACY;
+		sd->menuskill_lv = trigger;
+		return 1;
+	}
 	return 0;
 }
 
@@ -5898,6 +5915,8 @@ int clif_item_identify_list(struct map_session_data *sd)
 	if(c > 0) {
 		WFIFOW(fd,2)=c*2+4;
 		WFIFOSET(fd,WFIFOW(fd,2));
+		sd->menuskill_id = MC_IDENTIFY;
+		sd->menuskill_lv = c;
 	}
 	return 0;
 }
@@ -5951,8 +5970,8 @@ int clif_item_repair_list(struct map_session_data *sd,struct map_session_data *d
 	if(c > 0) {
 		WFIFOW(fd,2)=c*13+4;
 		WFIFOSET(fd,WFIFOW(fd,2));
-		sd->state.produce_flag = 1;
-		sd->repair_target=dstsd->bl.id;
+		sd->menuskill_id = BS_REPAIRWEAPON;
+		sd->menuskill_lv = dstsd->bl.id;
 	}else
 		clif_skill_fail(sd,sd->skillid,0,0);
 
@@ -6016,7 +6035,8 @@ int clif_item_refine_list(struct map_session_data *sd)
 	}
 	WFIFOW(fd,2)=c*13+4;
 	WFIFOSET(fd,WFIFOW(fd,2));
-	sd->state.produce_flag = 1;
+	sd->menuskill_id = WS_WEAPONREFINE;
+	sd->menuskill_lv = skilllv;
 
 	return 0;
 }
@@ -6856,6 +6876,8 @@ int clif_sendegg(struct map_session_data *sd)
 	WFIFOW(fd,2)=4+n*2;
 	WFIFOSET(fd,WFIFOW(fd,2));
 
+	sd->menuskill_id = SA_TAMINGMONSTER;
+	sd->menuskill_lv = n;
 	return 0;
 }
 
@@ -7028,6 +7050,9 @@ int clif_autospell(struct map_session_data *sd,int skilllv)
 		WFIFOL(fd,26)= 0x00000000;
 
 	WFIFOSET(fd,packet_len_table[0x1cd]);
+	sd->menuskill_id = SA_AUTOSPELL;
+	sd->menuskill_lv = skilllv;
+	
 	return 0;
 }
 
@@ -8845,15 +8870,12 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) {
 	if (pc_issit(sd)) //No walking when you are sit!
 		return;
 	
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->state.storage_flag)
+	if (clif_cant_act(sd))
 		return;
 
 	if (sd->skilltimer != -1 && pc_checkskill(sd, SA_FREECAST) <= 0) // フリーキャスト
 		return;
 
-	if (sd->chatID)
-		return;
-
 	if (!pc_can_move(sd))
 		return;
 
@@ -9247,9 +9269,10 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd) {
 		clif_clearchar_area(&sd->bl, 1);
 		return;
 	}
-	if (sd->npc_id || sd->sc.opt1 || sd->sc.option&OPTION_HIDE || sd->state.storage_flag)
+
+	if (clif_cant_act(sd) || sd->sc.option&OPTION_HIDE)
 		return;
-			
+	
 	if (sd->sc.count &&
 		(sd->sc.data[SC_TRICKDEAD].timer != -1 ||
 	 	sd->sc.data[SC_AUTOCOUNTER].timer != -1 ||
@@ -9274,8 +9297,6 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd) {
 	case 0x07: // continuous attack
 		if(sd->view_class==JOB_WEDDING || sd->view_class==JOB_XMAS)
 			return;
-		if (sd->vender_id != 0)
-			return;
 		if (!battle_config.sdelay_attack_enable && pc_checkskill(sd, SA_FREECAST) <= 0) {
 			if (DIFF_TICK(tick, sd->canact_tick) < 0) {
 				clif_skill_fail(sd, 1, 4, 0);
@@ -9548,8 +9569,10 @@ void clif_parse_TakeItem(int fd, struct map_session_data *sd) {
 	if (fitem == NULL || fitem->bl.type != BL_ITEM || fitem->bl.m != sd->bl.m)
 		return;
 	
-	if(sd->npc_id || sd->vender_id || sd->sc.opt1 || sd->trade_partner ||
-		pc_iscloaking(sd) || pc_ischasewalk(sd)) //Disable cloaking/chasewalking characters from looting [Skotlex]
+	if (clif_cant_act(sd))
+		return;
+	
+	if(pc_iscloaking(sd) || pc_ischasewalk(sd)) //Disable cloaking/chasewalking characters from looting [Skotlex]
 		return;
 	if(sd->sc.count && (
 		sd->sc.data[SC_TRICKDEAD].timer != -1 || //死んだふり
@@ -9575,8 +9598,10 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd) {
 		clif_clearchar_area(&sd->bl, 1);
 		return;
 	}
-	if (sd->npc_id || sd->vender_id || sd->sc.opt1 || sd->trade_partner)
+
+	if (clif_cant_act(sd))
 		return;
+
 	if (sd->sc.count && (
 		sd->sc.data[SC_AUTOCOUNTER].timer != -1 || //オートカウンター
 		sd->sc.data[SC_BLADESTOP].timer != -1//白刃取り
@@ -9600,13 +9625,16 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) {
 		clif_clearchar_area(&sd->bl, 1);
 		return;
 	}
-	if (sd->vender_id || sd->trade_partner)
-		return;
+
 
 	if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT)
 		return;
 	
-	if (sd->npc_id && sd->npc_id != sd->npc_item_flag) //This flag enables you to use items while in an NPC. [Skotlex]
+	if (clif_trading(sd))
+		return;
+	
+	//This flag enables you to use items while in an NPC. [Skotlex]
+	if (sd->npc_id && sd->npc_id != sd->npc_item_flag)
 		return;
 	
 	if (sd->sc.count && (
@@ -9648,12 +9676,12 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
 	if (index < 0 || index >= MAX_INVENTORY)
 		return; //Out of bounds check.
 	
-	if(sd->npc_id!=0 && sd->npc_id != sd->npc_item_flag)
-		return;
-	
-	if(sd->vender_id != 0 || sd->trade_partner != 0)
+	if(sd->npc_id) {
+		if (sd->npc_id != sd->npc_item_flag)
+			return;
+	} else if (clif_cant_act(sd))
 		return;
-	
+		
 	if(sd->sc.data[SC_BLADESTOP].timer!=-1 || sd->sc.data[SC_BERSERK].timer!=-1 )
 		return;
 
@@ -9685,8 +9713,10 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd)
 		clif_clearchar_area(&sd->bl,1);
 		return;
 	}
-	if(sd->npc_id!=0 || sd->vender_id != 0 || sd->sc.opt1 > 0 || sd->trade_partner != 0)
+
+	if (clif_cant_act(sd))
 		return;
+
 	index = RFIFOW(fd,2)-2;
 
 	pc_unequipitem(sd,index,1);
@@ -9704,7 +9734,11 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
 		clif_clearchar_area(&sd->bl,1);
 		return;
 	}
-	if(sd->npc_id!=0 || sd->vender_id != 0 || sd->trade_partner != 0 || RFIFOL(fd,2) < 0) //Clicked on a negative ID? Player disguised as NPC! [Skotlex]
+
+	if (clif_cant_act(sd))
+		return;
+	//Clicked on a negative ID? Player disguised as NPC! [Skotlex]
+	if (RFIFOL(fd,2) < 0)
 		return;
 	npc_click(sd,RFIFOL(fd,2));
 }
@@ -9909,7 +9943,7 @@ void clif_parse_PutItemToCart(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
 
-	if(sd->npc_id!=0 || sd->vender_id != 0 || sd->trade_partner != 0)
+	if (clif_trading(sd))
 		return;
 	pc_putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4));
 }
@@ -9921,7 +9955,8 @@ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
 
-	if(sd->npc_id!=0 || sd->vender_id != 0 || sd->trade_partner != 0) return;
+	if (clif_trading(sd))
+		return;
 	pc_getitemfromcart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4));
 }
 
@@ -9973,7 +10008,9 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
 	unsigned int tick = gettick();
 	RFIFOHEAD(fd);
 
-	if (sd->chatID || sd->npc_id != 0 || sd->vender_id != 0 || sd->state.storage_flag || pc_issit(sd))
+	if (clif_cant_act(sd))
+		return;
+	if (pc_issit(sd))
 		return;
 
 	skilllv = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
@@ -10114,7 +10151,9 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, int skilll
 void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd) {
 	RFIFOHEAD(fd);
 
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->chatID || sd->state.storage_flag || pc_issit(sd))
+	if (clif_cant_act(sd))
+		return;
+	if (pc_issit(sd))
 		return;
 
 	clif_parse_UseSkillToPosSub(fd, sd,
@@ -10129,8 +10168,11 @@ void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd) {
 void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd) {
 	RFIFOHEAD(fd);
 
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->chatID || sd->state.storage_flag) return;
-
+	if (clif_cant_act(sd))
+		return;
+	if (pc_issit(sd))
+		return;
+	
 	clif_parse_UseSkillToPosSub(fd, sd,
 		RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]), //Skill lv
 		RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[1]), //Skill num
@@ -10147,7 +10189,7 @@ void clif_parse_UseSkillMap(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
 
-	if(sd->chatID || sd->npc_id || sd->vender_id)
+	if (clif_cant_act(sd))
 		return;
 
 	if (sd->view_class==JOB_WEDDING || sd->view_class == JOB_XMAS)
@@ -10175,15 +10217,17 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
 
-	if (!sd->state.produce_flag)
+	if (sd->menuskill_id !=	AM_PHARMACY)
 		return;
-	sd->state.produce_flag = 0;
-	if (sd->npc_id) {
+
+	if (clif_trading(sd)) {
 		//Make it fail to avoid shop exploits where you sell something different than you see.
 		clif_skill_fail(sd,sd->skillid,0,0);
+		sd->menuskill_lv = sd->menuskill_id = 0;
 		return;
 	}
 	skill_produce_mix(sd,0,RFIFOW(fd,2),RFIFOW(fd,4),RFIFOW(fd,6),RFIFOW(fd,8), 1);
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 /*==========================================
  * 武器修理
@@ -10193,15 +10237,16 @@ void clif_parse_RepairItem(int fd, struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
 
-	if (!sd->state.produce_flag)
+	if (sd->menuskill_id != BS_REPAIRWEAPON)
 		return;
-	sd->state.produce_flag = 0;
-	if (sd->npc_id) {
+	if (clif_trading(sd)) {
 		//Make it fail to avoid shop exploits where you sell something different than you see.
 		clif_skill_fail(sd,sd->skillid,0,0);
+		sd->menuskill_lv = sd->menuskill_id = 0;
 		return;
 	}
 	skill_repairweapon(sd,RFIFOW(fd,2));
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 
 /*==========================================
@@ -10212,16 +10257,17 @@ void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) {
 	int idx;
 	RFIFOHEAD(fd);
 
-	if (!sd->state.produce_flag) //Packet exploit?
+	if (sd->menuskill_id != WS_WEAPONREFINE) //Packet exploit?
 		return;
-	sd->state.produce_flag = 0;
-	if (sd->npc_id) {
+	if (clif_trading(sd)) {
 		//Make it fail to avoid shop exploits where you sell something different than you see.
 		clif_skill_fail(sd,sd->skillid,0,0);
+		sd->menuskill_lv = sd->menuskill_id = 0;
 		return;
 	}
 	idx = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
 	skill_weaponrefine(sd, idx-2);
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 
 /*==========================================
@@ -10300,7 +10346,10 @@ void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd)
 void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
+	if (sd->menuskill_id != MC_IDENTIFY)
+		return;
 	skill_identify(sd,RFIFOW(fd,2)-2);
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 /*==========================================
  * 矢作成
@@ -10309,14 +10358,16 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
 void clif_parse_SelectArrow(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
-	if (!sd->state.produce_flag)
+	if (sd->menuskill_id != AC_MAKINGARROW)
 		return;
-	sd->state.produce_flag = 0;
-	if (sd->npc_id) { //Make it fail to avoid shop exploits where you sell something different than you see.
+	if (clif_trading(sd)) {
+	//Make it fail to avoid shop exploits where you sell something different than you see.
 		clif_skill_fail(sd,sd->skillid,0,0);
+		sd->menuskill_lv = sd->menuskill_id = 0;
 		return;
 	}
 	skill_arrow_create(sd,RFIFOW(fd,2));
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 /*==========================================
  * オートスペル受信
@@ -10325,7 +10376,10 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd)
 void clif_parse_AutoSpell(int fd,struct map_session_data *sd)
 {
 	RFIFOHEAD(fd);
+	if (sd->menuskill_id != SA_AUTOSPELL)
+		return;
 	skill_autospell(sd,RFIFOW(fd,2));
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 /*==========================================
  * カード使用
@@ -10406,7 +10460,7 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd) {
 	int item_index, item_amount;
 	RFIFOHEAD(fd);
 
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->trade_partner != 0 || !sd->state.storage_flag)
+	if (clif_trading(sd))
 		return;
 	
 	item_index = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-2;
@@ -10428,7 +10482,7 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd) {
 	int item_index, item_amount;
 	RFIFOHEAD(fd);
 
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->trade_partner != 0 || !sd->state.storage_flag)
+	if (clif_trading(sd))
 		return;
 	
 	item_index = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-1;
@@ -10447,7 +10501,7 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd) {
 void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd) {
 	RFIFOHEAD(fd);
 
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->trade_partner != 0 || !sd->state.storage_flag)
+	if (clif_trading(sd))
 		return;
 
 	if (sd->state.storage_flag == 1)
@@ -10463,7 +10517,7 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd) {
 void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) {
 	RFIFOHEAD(fd);
 
-	if (sd->npc_id != 0 || sd->vender_id != 0 || sd->trade_partner != 0 || !sd->state.storage_flag)
+	if (clif_trading(sd))
 		return;
 	if (sd->state.storage_flag == 1)
 		storage_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4));
@@ -10600,7 +10654,7 @@ void clif_parse_VendingListReq(int fd, struct map_session_data *sd) {
  */
 void clif_parse_PurchaseReq(int fd, struct map_session_data *sd) {
 	RFIFOHEAD(fd);
-	if (sd->trade_partner != 0)
+	if (clif_trading(sd))
 		return;
 	vending_purchasereq(sd, RFIFOW(fd,2), RFIFOL(fd,4), RFIFOP(fd,8));
 }
@@ -10611,7 +10665,7 @@ void clif_parse_PurchaseReq(int fd, struct map_session_data *sd) {
  */
 void clif_parse_OpenVending(int fd,struct map_session_data *sd) {
 	RFIFOHEAD(fd);
-	if (sd->trade_partner != 0)
+	if (clif_trading(sd))
 		return;
 	vending_openvending(sd, RFIFOW(fd,2), (char*)RFIFOP(fd,4), RFIFOB(fd,84), RFIFOP(fd,85));
 }
@@ -10835,7 +10889,10 @@ void clif_parse_CatchPet(int fd, struct map_session_data *sd) {
 
 void clif_parse_SelectEgg(int fd, struct map_session_data *sd) {
 	RFIFOHEAD(fd);
+	if (sd->menuskill_id != SA_TAMINGMONSTER)
+		return;
 	pet_select_egg(sd,RFIFOW(fd,2)-2);
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 
 void clif_parse_SendEmotion(int fd, struct map_session_data *sd) {
@@ -11597,32 +11654,36 @@ void clif_parse_RankingPk(int fd,struct map_session_data *sd)
  */
 void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd)
 {
-	if (sd->feel_level!=-1)
-	{
-		char feel_var[3][NAME_LENGTH] = {"PC_FEEL_SUN","PC_FEEL_MOON","PC_FEEL_STAR"};
-		sd->feel_map[sd->feel_level].index = map[sd->bl.m].index;
-		sd->feel_map[sd->feel_level].m = sd->bl.m;
-		pc_setglobalreg(sd,feel_var[sd->feel_level],map[sd->bl.m].index);
-
-		WFIFOHEAD(fd,packet_len_table[0x20e]);
-		WFIFOW(fd,0)=0x20e;
-		memcpy(WFIFOP(fd,2),map[sd->bl.m].name, MAP_NAME_LENGTH);
-		WFIFOL(fd,26)=sd->bl.id;
-		WFIFOW(fd,30)=sd->feel_level;
-		WFIFOSET(fd, packet_len_table[0x20e]);
-		sd->feel_level = -1;
-		if (pc_checkskill(sd,SG_KNOWLEDGE)) status_calc_pc(sd,0);
-	}
+	char feel_var[3][NAME_LENGTH] = {"PC_FEEL_SUN","PC_FEEL_MOON","PC_FEEL_STAR"};
+	int i;
+	if (sd->menuskill_id != SG_FEEL)
+		return;
+	i = sd->menuskill_lv-1;
+	if (i<0 || i > 2) return; //Bug?
+	sd->feel_map[i].index = map[sd->bl.m].index;
+	sd->feel_map[i].m = sd->bl.m;
+	pc_setglobalreg(sd,feel_var[i],map[sd->bl.m].index);
+	
+	WFIFOHEAD(fd,packet_len_table[0x20e]);
+	WFIFOW(fd,0)=0x20e;
+	memcpy(WFIFOP(fd,2),map[sd->bl.m].name, MAP_NAME_LENGTH);
+	WFIFOL(fd,26)=sd->bl.id;
+	WFIFOW(fd,30)=i;
+	WFIFOSET(fd, packet_len_table[0x20e]);
+	if (pc_checkskill(sd,SG_KNOWLEDGE)) status_calc_pc(sd,0);
+	sd->menuskill_lv = sd->menuskill_id = 0;
 }
 
 /*==========================================
  * Question about Star Glaldiator save map [Komurka]
  *------------------------------------------
  */
-void clif_parse_ReqFeel(int fd, struct map_session_data *sd) {
+void clif_parse_ReqFeel(int fd, struct map_session_data *sd, int skilllv) {
 	WFIFOHEAD(fd,packet_len_table[0x253]);
 	WFIFOW(fd,0)=0x253;
 	WFIFOSET(fd, packet_len_table[0x253]);
+	sd->menuskill_id=SG_FEEL;
+	sd->menuskill_lv=skilllv;
 }
 
 /*==========================================

+ 3 - 3
src/map/clif.h

@@ -177,11 +177,11 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,
 int clif_skill_poseffect(struct block_list *src,int skill_id,
 	int val,int x,int y,int tick);
 int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst);
-int clif_skill_warppoint(struct map_session_data *sd,int skill_num,
+int clif_skill_warppoint(struct map_session_data *sd,int skill_num, int skill_lv,
 	const char *map1,const char *map2,const char *map3,const char *map4);
 int clif_skill_memo(struct map_session_data *sd,int flag);
 int clif_skill_teleportmessage(struct map_session_data *sd,int flag);
-int clif_skill_produce_mix_list(struct map_session_data *sd,int trigger);
+int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger);
 
 int clif_produceeffect(struct map_session_data *sd,int flag,int nameid);
 
@@ -334,7 +334,7 @@ int do_init_clif(void);
 
 
 int clif_party_xy_remove(struct map_session_data *sd); //Fix for minimap [Kevin]
-void clif_parse_ReqFeel(int fd, struct map_session_data *sd); 
+void clif_parse_ReqFeel(int fd, struct map_session_data *sd, int skilllv); 
 void clif_feel_info(struct map_session_data *sd, int feel_level);
 void clif_hate_mob(struct map_session_data *sd, int skilllv,int mob_id);
 void clif_mission_mob(struct map_session_data *sd, unsigned short mob_id, unsigned short progress);

+ 2 - 3
src/map/map.h

@@ -423,7 +423,6 @@ struct map_session_data {
 		unsigned skill_flag : 1;
 		unsigned gangsterparadise : 1;
 		unsigned rest : 1;
-		unsigned produce_flag : 1;
 		unsigned storage_flag : 2; //0: closed, 1: Normal Storage open, 2: guild storage open [Skotlex]
 		unsigned snovice_flag : 4;
 		// originally by Qamera, adapted by celest
@@ -515,6 +514,7 @@ struct map_session_data {
 	int skilltarget;
 	short skillx,skilly;
 	short skillid,skilllv;
+
 	short skillitem,skillitemlv;
 	short skillid_old,skilllv_old;
 	short skillid_dance,skilllv_dance;
@@ -525,7 +525,7 @@ struct map_session_data {
 	//unsigned int skillstatictimer[MAX_SKILL];
 	unsigned short timerskill_count; // [celest]
 	int cloneskill_id;
-	int repair_target;
+	int menuskill_id, menuskill_lv;
 
 	int invincible_timer;
 	unsigned int canact_tick;
@@ -709,7 +709,6 @@ struct map_session_data {
 		int  m; //-1 - none, other: map index corresponding to map name.
 		unsigned short index; //map index
 	}feel_map[3];// 0 - Sun; 1 - Moon; 2 - Stars
-	int feel_level;
 	short hate_mob[3];
 
 	unsigned int pvp_timer;

+ 0 - 1
src/map/pc.c

@@ -840,7 +840,6 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t
 	
 	//Prevent S. Novices from getting the no-death bonus just yet. [Skotlex]
 	sd->die_counter=-1;
-	sd->feel_level=-1;
 	//Until the reg values arrive, set them to not require trigger...
 	sd->state.event_death = 1;
 	sd->state.event_kill = 1;

+ 1 - 2
src/map/script.c

@@ -5299,9 +5299,8 @@ int buildin_produce(struct script_state *st)
 	int trigger;
 	struct map_session_data *sd=script_rid2sd(st);
 
-	if(	sd->state.produce_flag == 1) return 0;
 	trigger=conv_num(st,& (st->stack->stack_data[st->start+2]));
-	clif_skill_produce_mix_list(sd,trigger);
+	clif_skill_produce_mix_list(sd, trigger);
 	return 0;
 }
 /*==========================================

+ 28 - 26
src/map/skill.c

@@ -4276,12 +4276,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				// possibility to skip menu [LuzZza]
 				if(!battle_config.skip_teleport_lv1_menu &&
 					sd->skillid == AL_TELEPORT) //If skillid is not teleport, this was auto-casted! [Skotlex]
-					clif_skill_warppoint(sd,skillid,"Random","","","");
+					clif_skill_warppoint(sd,skillid,skilllv,"Random","","","");
 				else
 					pc_randomwarp(sd,3);
 			} else {
 				if (sd->skillid == AL_TELEPORT)
-					clif_skill_warppoint(sd,skillid,"Random",
+					clif_skill_warppoint(sd,skillid,skilllv,"Random",
 						mapindex_id2name(sd->status.save_point.map),"","");
 				else //Autocasted Teleport level 2??
 					pc_setpos(sd,sd->status.save_point.map,
@@ -5534,9 +5534,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	case SG_FEEL:
 		if (sd) {
 			if(!sd->feel_map[skilllv-1].index) {
-				sd->feel_level=skilllv-1;
 				clif_skill_nodamage(src,bl,skillid,skilllv,1);
-				clif_parse_ReqFeel(sd->fd,sd);
+				clif_parse_ReqFeel(sd->fd,sd, skilllv);
 			}
 			else
 				clif_feel_info(sd, skilllv-1);
@@ -5729,11 +5728,10 @@ int skill_castend_id( int tid, unsigned int tick, int id,int data )
 
 	if(sd->sc.count && sd->sc.data[SC_MAGICPOWER].timer != -1 && sd->skillid != HW_MAGICPOWER)
 		status_change_end(&sd->bl,SC_MAGICPOWER,-1);		
-		
-	if (sd->skillid != AL_TELEPORT && sd->skillid != WS_WEAPONREFINE) {
-		sd->skillid = sd->skilllv = -1; //Clean this up for future references to battle_getcurrentskill. [Skotlex]
-		sd->skilltarget = 0;
-	}
+
+	//Clean this up for future references to battle_getcurrentskill. [Skotlex]
+	sd->skillid = sd->skilllv = -1;
+	sd->skilltarget = 0;
 	return 0;
 #undef skill_failed
 }
@@ -5998,7 +5996,7 @@ int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skil
 
 	case AL_WARP:				/* �??プポ?タル */
 		if(sd) {
-			clif_skill_warppoint(sd,skillid,mapindex_id2name(sd->status.save_point.map),
+			clif_skill_warppoint(sd,skillid,skilllv,mapindex_id2name(sd->status.save_point.map),
 				(sd->skilllv>1)?mapindex_id2name(sd->status.memo_point[0].map):"",
 				(sd->skilllv>2)?mapindex_id2name(sd->status.memo_point[1].map):"",
 				(sd->skilllv>3)?mapindex_id2name(sd->status.memo_point[2].map):"");
@@ -6145,8 +6143,7 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 	nullpo_retr(0, sd);
 
 //Simplify skill_failed code.
-#undef skill_failed
-#define skill_failed(sd) { sd->skillid = sd->skilllv = sd->skillitem = sd->skillitemlv = -1; }
+#define skill_failed(sd) { sd->skillid = sd->skilllv = sd->skillitem = sd->skillitemlv = -1; sd->menuskill_id = sd->menuskill_lv = 0; }
 
 	if( sd->bl.prev == NULL || pc_isdead(sd) )
 		return 0;
@@ -6171,7 +6168,7 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 	 ))
 		return 0;
 
-	if( skill_num != sd->skillid) /* 不?ウパケットらしい */
+	if( skill_num != sd->menuskill_id) /* 不?ウパケットらしい */
 		return 0;
 
 	if (strlen(map) > MAP_NAME_LENGTH-1)
@@ -6197,7 +6194,7 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 	case AL_TELEPORT:		/* テレポ?ト */
 		if(strcmp(map,"Random")==0)
 			pc_randomwarp(sd,3);
-		else
+		else if (sd->menuskill_lv > 1) //Need lv2 to be able to warp here.
 			pc_setpos(sd,sd->status.save_point.map,
 				sd->status.save_point.x,sd->status.save_point.y,3);
 		break;
@@ -6206,7 +6203,7 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 		{
 			const struct point *p[4];
 			struct skill_unit_group *group;
-			int i;
+			int i, lv;
 			int maxcount=0;
 			unsigned short mapindex;
 			mapindex  = mapindex_name2id((char*)map);
@@ -6232,9 +6229,9 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 					return 0;
 				}
 			}
-
-			if(sd->skilllv <= 0) return 0;
-			for(i=0;i<sd->skilllv;i++){
+			lv = sd->menuskill_lv;
+			if(lv <= 0) return 0;
+			for(i=0;i<lv;i++){
 				if(mapindex == p[i]->map){
 					x=p[i]->x;
 					y=p[i]->y;
@@ -6245,19 +6242,24 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 				skill_failed(sd);
 				return 0;
 			}
-			
+			//FIXME: What is gonna be done in the case other skills are being used
+			//in the middle of this block of code? Something more robust needs be
+			//figured out. And what about when you use another ground skill? skillx
+			//and skilly are messed up already... [Skotlex]
+			sd->skillid = sd->menuskill_id;
+			sd->skilllv = sd->menuskill_lv;
 			if(!skill_check_condition(sd,3))
 			{
 				skill_failed(sd);
 				return 0;
 			}
 			
-			if(skill_check_unit_range2(&sd->bl,sd->bl.m,sd->skillx,sd->skilly,skill_num,sd->skilllv) > 0) {
+			if(skill_check_unit_range2(&sd->bl,sd->bl.m,sd->skillx,sd->skilly,skill_num,lv) > 0) {
 				clif_skill_fail(sd,0,0,0);
 				skill_failed(sd);
 				return 0;
 			}
-			if((group=skill_unitsetting(&sd->bl,skill_num,sd->skilllv,sd->skillx,sd->skilly,0))==NULL) {
+			if((group=skill_unitsetting(&sd->bl,skill_num,lv,sd->skillx,sd->skilly,0))==NULL) {
 				skill_failed(sd);
 				return 0;
 			}
@@ -6270,8 +6272,9 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
 		break;
 	}
 
-	sd->skillid = sd->skilllv = -1;
+	sd->menuskill_id = sd->menuskill_lv = 0;
 	return 0;
+#undef skill_failed
 }
 
 /*==========================================
@@ -7542,7 +7545,7 @@ int skill_check_condition(struct map_session_data *sd,int type)
 		return 1;
 	}
 
-	if (sd->state.produce_flag &&
+	if (sd->menuskill_id == AM_PHARMACY &&
 		(sd->skillid == AM_PHARMACY || sd->skillid == AC_MAKINGARROW || sd->skillid == BS_REPAIRWEAPON ||
 		sd->skillid == AM_TWILIGHT1 || sd->skillid == AM_TWILIGHT2  || sd->skillid == AM_TWILIGHT3 
 	)) {
@@ -8974,8 +8977,7 @@ void skill_repairweapon(struct map_session_data *sd, int idx)
 	struct map_session_data *target_sd;
 
 	nullpo_retv(sd);
-	target_sd = map_id2sd(sd->repair_target);
-	sd->repair_target = 0;
+	target_sd = map_id2sd(sd->menuskill_lv);
 	if (!target_sd) //Failed....
 		return;
 	if(idx==0xFFFF) // No item selected ('Cancel' clicked)
@@ -9106,7 +9108,7 @@ int skill_autospell(struct map_session_data *sd,int skillid)
 
 	nullpo_retr(0, sd);
 
-	skilllv = pc_checkskill(sd,SA_AUTOSPELL);
+	skilllv = sd->menuskill_lv;
 	if(skilllv <= 0) return 0;
 
 	if(skillid==MG_NAPALMBEAT)	maxlv=3;