Browse Source

- Rewrote/cleaned up trade.c for a more clean trading implementation.
- Added @request commands, sends a request to all connected GMs of lowest_gm_level or above as a whisper message. Defaults to gm level 20 users.
- Made SC_COMBO status start delay attackabletime and walkdelay by sc's duration regardless of skill used (previously it was only for TK kicks, now it's for both those and Monk combos)


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

skotlex 19 years ago
parent
commit
e2eadf7bb2
8 changed files with 357 additions and 361 deletions
  1. 5 0
      Changelog-Trunk.txt
  2. 3 0
      conf-tmpl/atcommand_athena.conf
  3. 3 1
      conf-tmpl/msg_athena.conf
  4. 23 0
      src/map/atcommand.c
  5. 1 1
      src/map/atcommand.h
  6. 0 10
      src/map/skill.c
  7. 4 4
      src/map/status.c
  8. 318 345
      src/map/trade.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ 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.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 
 2006/05/09
 2006/05/09
+	* Rewrote/cleaned up trade.c for a more clean trading implementation.
+	  [Skotlex]
+	* Added @request commands, sends a request to all connected GMs of
+	  lowest_gm_level or above as a whisper message. Defaults to gm level 20
+	  users (UNTESTED). [Skotlex]
 	* Modified @commands to use Meruru's code which is faster and does a fair
 	* Modified @commands to use Meruru's code which is faster and does a fair
 	  attempt at tabulating the commands presented. [Skotlex]
 	  attempt at tabulating the commands presented. [Skotlex]
 	* Updated SKA to return a random value between 0 and 99 each time
 	* Updated SKA to return a random value between 0 and 99 each time

+ 3 - 0
conf-tmpl/atcommand_athena.conf

@@ -181,6 +181,9 @@ gmotd: 20
 // follow a player (including warping to them)
 // follow a player (including warping to them)
 follow: 20
 follow: 20
 
 
+// Sends a request to all connected GMs (via the gm whisper system)
+request: 20
+
 // Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit").
 // Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit").
 kick: 20
 kick: 20
 
 

+ 3 - 1
conf-tmpl/msg_athena.conf

@@ -284,7 +284,9 @@
 272: You can't trade on this map
 272: You can't trade on this map
 273: Commands available:
 273: Commands available:
 274: %d commands found.
 274: %d commands found.
-275: No commands found.
+275: Usage: @request <petition/message to online GMs>.
+276: (@request): %s
+277: @request sent.
 // Guild Castles Number
 // Guild Castles Number
 // --------------------
 // --------------------
 299: ?? Castles
 299: ?? Castles

+ 23 - 0
src/map/atcommand.c

@@ -295,6 +295,7 @@ ACMD_FUNC(clone); // [Valaris]
 ACMD_FUNC(tonpc); // LuzZza
 ACMD_FUNC(tonpc); // LuzZza
 ACMD_FUNC(commands); // [Skotlex]
 ACMD_FUNC(commands); // [Skotlex]
 ACMD_FUNC(noask); //LuzZza
 ACMD_FUNC(noask); //LuzZza
+ACMD_FUNC(request); //LuzZza
 
 
 /*==========================================
 /*==========================================
  *AtCommandInfo atcommand_info[]�\‘¢‘̂̒è‹`
  *AtCommandInfo atcommand_info[]�\‘¢‘̂̒è‹`
@@ -611,6 +612,7 @@ static AtCommandInfo atcommand_info[] = {
 	{ AtCommand_ToNPC,				"@tonpc",			40, atcommand_tonpc }, // LuzZza
 	{ AtCommand_ToNPC,				"@tonpc",			40, atcommand_tonpc }, // LuzZza
 	{ AtCommand_Commands,			"@commands",		1, atcommand_commands }, // [Skotlex]
 	{ AtCommand_Commands,			"@commands",		1, atcommand_commands }, // [Skotlex]
 	{ AtCommand_NoAsk,				"@noask",			1, atcommand_noask }, // [LuzZza]
 	{ AtCommand_NoAsk,				"@noask",			1, atcommand_noask }, // [LuzZza]
+	{ AtCommand_Request,				"@request",			20, atcommand_request }, // [LuzZza]
 
 
 // add new commands before this line
 // add new commands before this line
 	{ AtCommand_Unknown,			NULL,				 1, NULL }
 	{ AtCommand_Unknown,			NULL,				 1, NULL }
@@ -10273,6 +10275,27 @@ int atcommand_noask(
 	return 0;
 	return 0;
 }
 }
 
 
+/*=====================================
+ * Send a @request message to all GMs of lowest_gm_level.
+ * Usage: @request <petition>
+ *-------------------------------------
+ */
+int atcommand_request(
+	const int fd, struct map_session_data* sd,
+	const char* command, const char* message)
+{
+	if (!message || !*message) {
+		clif_displaymessage(sd->fd,msg_txt(275));
+		return -1;
+	}
+
+	sprintf(atcmd_output, msg_txt(276), message);
+	intif_wis_message_to_gm(sd->status.name, lowest_gm_level, atcmd_output);
+	clif_disp_onlyself(sd, atcmd_output, strlen(atcmd_output));
+	clif_displaymessage(sd->fd,msg_txt(277));
+	return 0;
+}
+
 void do_init_atcommand() {
 void do_init_atcommand() {
 	users_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int));
 	users_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int));
 	duel_count = 0;
 	duel_count = 0;

+ 1 - 1
src/map/atcommand.h

@@ -270,7 +270,7 @@ enum AtCommandType {
 	AtCommand_ToNPC, // LuzZza
 	AtCommand_ToNPC, // LuzZza
 	AtCommand_Commands, // [Skotlex]
 	AtCommand_Commands, // [Skotlex]
 	AtCommand_NoAsk, // [LuzZza]
 	AtCommand_NoAsk, // [LuzZza]
-	
+	AtCommand_Request, // [Skotlex], supposedly taken from Freya (heard the command was there, but I haven't seen the code yet)
 	// end <- Ahem, guys, don't place AtCommands after AtCommand_Unknown! [Skotlex]
 	// end <- Ahem, guys, don't place AtCommands after AtCommand_Unknown! [Skotlex]
 	AtCommand_Unknown,
 	AtCommand_Unknown,
 	AtCommand_MAX
 	AtCommand_MAX

+ 0 - 10
src/map/skill.c

@@ -1821,8 +1821,6 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
 					pc_checkskill(sd, MO_CHAINCOMBO) > 0)
 					pc_checkskill(sd, MO_CHAINCOMBO) > 0)
 					delay += 300 * battle_config.combo_delay_rate / 100;
 					delay += 300 * battle_config.combo_delay_rate / 100;
 				sc_start4(src,SC_COMBO,100,MO_TRIPLEATTACK,skilllv,0,0,delay);
 				sc_start4(src,SC_COMBO,100,MO_TRIPLEATTACK,skilllv,0,0,delay);
-				sd->ud.attackabletime = tick + delay;
-				unit_set_walkdelay(src, tick, delay, 1);
 				clif_combo_delay(src, delay);
 				clif_combo_delay(src, delay);
 				
 				
 				if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka]
 				if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka]
@@ -1836,8 +1834,6 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
 					(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0))
 					(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0))
 					delay += 300 * battle_config.combo_delay_rate /100;
 					delay += 300 * battle_config.combo_delay_rate /100;
 				sc_start4(src,SC_COMBO,100,MO_CHAINCOMBO,skilllv,0,0,delay);
 				sc_start4(src,SC_COMBO,100,MO_CHAINCOMBO,skilllv,0,0,delay);
-				sd->ud.attackabletime = tick + delay;
-				unit_set_walkdelay(src, tick, delay, 1);
 				clif_combo_delay(src,delay);
 				clif_combo_delay(src,delay);
 				break;
 				break;
 			}
 			}
@@ -1852,8 +1848,6 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
 				))
 				))
 					delay += 300 * battle_config.combo_delay_rate /100;
 					delay += 300 * battle_config.combo_delay_rate /100;
 				sc_start4(src,SC_COMBO,100,MO_COMBOFINISH,skilllv,0,0,delay);
 				sc_start4(src,SC_COMBO,100,MO_COMBOFINISH,skilllv,0,0,delay);
-				sd->ud.attackabletime = tick + delay;
-				unit_set_walkdelay(src, tick, delay, 1);
 				clif_combo_delay(src,delay);
 				clif_combo_delay(src,delay);
 				break;
 				break;
 			}
 			}
@@ -1867,8 +1861,6 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
 				))
 				))
 					delay += 300 * battle_config.combo_delay_rate /100;
 					delay += 300 * battle_config.combo_delay_rate /100;
 				sc_start4(src,SC_COMBO,100,CH_TIGERFIST,skilllv,0,0,delay);
 				sc_start4(src,SC_COMBO,100,CH_TIGERFIST,skilllv,0,0,delay);
-				sd->ud.attackabletime = tick + delay;
-				unit_set_walkdelay(src, tick, delay, 1);
 				clif_combo_delay(src,delay);
 				clif_combo_delay(src,delay);
 				break;
 				break;
 			}
 			}
@@ -1878,8 +1870,6 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
 				if(damage < status_get_hp(bl))
 				if(damage < status_get_hp(bl))
 					delay += 300 * battle_config.combo_delay_rate /100;
 					delay += 300 * battle_config.combo_delay_rate /100;
 				sc_start4(src,SC_COMBO,100,CH_CHAINCRUSH,skilllv,0,0,delay);
 				sc_start4(src,SC_COMBO,100,CH_CHAINCRUSH,skilllv,0,0,delay);
-				sd->ud.attackabletime = tick + delay;
-				unit_set_walkdelay(src, tick, delay, 1);
 				clif_combo_delay(src,delay);
 				clif_combo_delay(src,delay);
 				break;
 				break;
 			}
 			}

+ 4 - 4
src/map/status.c

@@ -4452,21 +4452,21 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 			switch (val1) { //Val1 contains the skill id
 			switch (val1) { //Val1 contains the skill id
 				case TK_STORMKICK:
 				case TK_STORMKICK:
 					clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1);
 					clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1);
-					if (ud) ud->attackabletime = gettick()+tick;
 					break;
 					break;
 				case TK_DOWNKICK:
 				case TK_DOWNKICK:
 					clif_skill_nodamage(bl,bl,TK_READYDOWN,1,1);
 					clif_skill_nodamage(bl,bl,TK_READYDOWN,1,1);
-					if (ud) ud->attackabletime = gettick()+tick;
 					break;
 					break;
 				case TK_TURNKICK:
 				case TK_TURNKICK:
 					clif_skill_nodamage(bl,bl,TK_READYTURN,1,1);
 					clif_skill_nodamage(bl,bl,TK_READYTURN,1,1);
-					if (ud) ud->attackabletime = gettick()+tick;
 					break;
 					break;
 				case TK_COUNTER:
 				case TK_COUNTER:
 					clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1);
 					clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1);
-					if (ud) ud->attackabletime = gettick()+tick;
 					break;
 					break;
 			}
 			}
+			if (ud) {
+				ud->attackabletime = gettick()+tick;
+				unit_set_walkdelay(bl, gettick(), tick, 1);
+			}
 		}
 		}
 			break;
 			break;
 		case SC_TKREST:
 		case SC_TKREST:

+ 318 - 345
src/map/trade.c

@@ -20,7 +20,7 @@
 
 
 
 
 /*==========================================
 /*==========================================
- * 取引要請を相手に送る
+ * Initiates a trade request.
  *------------------------------------------
  *------------------------------------------
  */
  */
 void trade_traderequest(struct map_session_data *sd, int target_id) {
 void trade_traderequest(struct map_session_data *sd, int target_id) {
@@ -34,73 +34,89 @@ void trade_traderequest(struct map_session_data *sd, int target_id) {
 		return; //Can't trade in notrade mapflag maps.
 		return; //Can't trade in notrade mapflag maps.
 	}
 	}
 
 
-	if ((target_sd = map_id2sd(target_id)) != NULL) {
-		if (!battle_config.invite_request_check) {
-			if (target_sd->guild_invite > 0 || target_sd->party_invite > 0) {
-				clif_tradestart(sd, 2); // 相手はPT要請中かGuild要請中
-				return;
-			}
-		}
-		level = pc_isGM(sd);
-		if ( pc_can_give_items(level) || pc_can_give_items(pc_isGM(target_sd)) ) //check if both GMs are allowed to trade
-		{
-			clif_displaymessage(sd->fd, msg_txt(246));
-			trade_tradecancel(sd); // GM is not allowed to trade
-		} else if ((target_sd->trade_partner != 0) || (sd->trade_partner != 0)) {
-			trade_tradecancel(sd); // person is in another trade
-		} else {
-			//Fixed. Only real GMs can request trade from far away! [Lupus] 
-			if (level < lowest_gm_level && (sd->bl.m != target_sd->bl.m ||
-			    (sd->bl.x - target_sd->bl.x <= -5 || sd->bl.x - target_sd->bl.x >= 5) ||
-			    (sd->bl.y - target_sd->bl.y <= -5 || sd->bl.y - target_sd->bl.y >= 5))) {
-				clif_tradestart(sd, 0); // too far
-			} else if (sd != target_sd) {
-				target_sd->trade_partner = sd->status.account_id;
-				sd->trade_partner = target_sd->status.account_id;
-				clif_traderequest(target_sd, sd->status.name);
-			}
-		}
-	} else {
+	if ((target_sd = map_id2sd(target_id)) == NULL || sd == target_sd) {
 		clif_tradestart(sd, 1); // character does not exist
 		clif_tradestart(sd, 1); // character does not exist
+		return;
+	}
+	
+	if (!battle_config.invite_request_check) {
+		if (target_sd->guild_invite > 0 || target_sd->party_invite > 0) {
+			clif_tradestart(sd, 2);
+			return;
+		}
+	}
+
+	if ((target_sd->trade_partner != 0) || (sd->trade_partner != 0)) {
+		trade_tradecancel(sd); // person is in another trade
+		return;
+	}
+
+	level = pc_isGM(sd);
+	if ( pc_can_give_items(level) || pc_can_give_items(pc_isGM(target_sd)) ) //check if both GMs are allowed to trade
+	{
+		clif_displaymessage(sd->fd, msg_txt(246));
+		trade_tradecancel(sd); // GM is not allowed to trade
+		return;
+	} 
+	
+	//Fixed. Only real GMs can request trade from far away! [Lupus] 
+	if (level < lowest_gm_level && (sd->bl.m != target_sd->bl.m ||
+		 (sd->bl.x - target_sd->bl.x <= -5 || sd->bl.x - target_sd->bl.x >= 5) ||
+		 (sd->bl.y - target_sd->bl.y <= -5 || sd->bl.y - target_sd->bl.y >= 5))) {
+		clif_tradestart(sd, 0); // too far
+		return ;
 	}
 	}
+	
+	target_sd->trade_partner = sd->status.account_id;
+	sd->trade_partner = target_sd->status.account_id;
+	clif_traderequest(target_sd, sd->status.name);
 }
 }
 
 
 /*==========================================
 /*==========================================
- * 取引要請
+ * Reply to a trade-request.
  *------------------------------------------
  *------------------------------------------
  */
  */
 void trade_tradeack(struct map_session_data *sd, int type) {
 void trade_tradeack(struct map_session_data *sd, int type) {
 	struct map_session_data *target_sd;
 	struct map_session_data *target_sd;
 	nullpo_retv(sd);
 	nullpo_retv(sd);
 
 
-	if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) {
-		clif_tradestart(target_sd, type);
-		clif_tradestart(sd, type);
-		if (type == 4) { // Cancel
-			sd->state.deal_locked = 0;
-			sd->trade_partner = 0;
-			target_sd->state.deal_locked = 0;
-			target_sd->trade_partner = 0;
-		}
-
-		if (type == 3) { //Initiate trade
-			sd->state.trading = 1;
-			target_sd->state.trading = 1;
-			memset(&sd->deal, 0, sizeof(sd->deal));
-			memset(&target_sd->deal, 0, sizeof(target_sd->deal));
-		}
+	if (sd->state.trading || !sd->trade_partner)
+		return; //Already trading or no partner set.
+	
+	if ((target_sd = map_id2sd(sd->trade_partner)) == NULL) {
+		sd->trade_partner=0;
+		return;
+	}
 		
 		
-		if (sd->npc_id != 0)
-			npc_event_dequeue(sd);
-		if (target_sd->npc_id != 0)
-			npc_event_dequeue(target_sd);
-
-		//close STORAGE window if it's open. It protects from spooffing packets [Lupus]
-		if (sd->state.storage_flag == 1)
-			storage_storageclose(sd);
-		else if (sd->state.storage_flag == 2)
-			storage_guild_storageclose(sd);
+	clif_tradestart(target_sd, type);
+	clif_tradestart(sd, type);
+	if (type == 4) { // Cancel
+		sd->state.deal_locked = 0;
+		sd->trade_partner = 0;
+		target_sd->state.deal_locked = 0;
+		target_sd->trade_partner = 0;
+	}
+
+	if (type == 3) { //Initiate trade
+		sd->state.trading = 1;
+		target_sd->state.trading = 1;
+		memset(&sd->deal, 0, sizeof(sd->deal));
+		memset(&target_sd->deal, 0, sizeof(target_sd->deal));
 	}
 	}
+		
+	if (sd->npc_id)
+		npc_event_dequeue(sd);
+	if (target_sd->npc_id)
+		npc_event_dequeue(target_sd);
+
+	/* Why? It should be allowed to bring items from storage to inventory for trading, but not the other way around
+	 * (this is blocked on clif.c) [Skotlex]
+	//close STORAGE window if it's open. It protects from spooffing packets [Lupus]
+	if (sd->state.storage_flag == 1)
+		storage_storageclose(sd);
+	else if (sd->state.storage_flag == 2)
+		storage_guild_storageclose(sd);
+	*/
 }
 }
 
 
 /*==========================================
 /*==========================================
@@ -133,56 +149,55 @@ int impossible_trade_check(struct map_session_data *sd) {
 			memset(&inventory[i], 0, sizeof(struct item));
 			memset(&inventory[i], 0, sizeof(struct item));
 
 
 	// check items in player inventory
 	// check items in player inventory
-	for(i = 0; i < 10; i++)
-		if (sd->deal.item[i].amount < 0) { // negativ? -> hack
-//			printf("Negativ amount in trade, by hack!\n"); // normal client send cancel when we type negativ amount
-			return -1;
-		} else if (sd->deal.item[i].amount > 0) {
-			index = sd->deal.item[i].index;
-			inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory
-//			printf("%d items left\n", inventory[index].amount);
-			if (inventory[index].amount < 0) { // if more than the player have -> hack
-//				printf("A player try to trade more items that he has: hack!\n");
-				sprintf(message_to_gm, msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has.
-				intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
-				sprintf(message_to_gm, msg_txt(539), sd->status.inventory[index].amount, sd->status.inventory[index].nameid, sd->status.inventory[index].amount - inventory[index].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them.
-				intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
-				// if we block people
-				if (battle_config.ban_hack_trade < 0) {
-					chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
-					clif_setwaitclose(sd->fd); // forced to disconnect because of the hack
-					// message about the ban
-					sprintf(message_to_gm, msg_txt(540), battle_config.ban_spoof_namer); //  This player has been definitivly blocked.
-				// if we ban people
-				} else if (battle_config.ban_hack_trade > 0) {
-					chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_hack_trade, 0); // type: 2 - ban (year, month, day, hour, minute, second)
-					clif_setwaitclose(sd->fd); // forced to disconnect because of the hack
-					// message about the ban
-					sprintf(message_to_gm, msg_txt(507), battle_config.ban_spoof_namer); //  This player has been banned for %d minute(s).
-				} else {
-					// message about the ban
-					sprintf(message_to_gm, msg_txt(508)); //  This player hasn't been banned (Ban option is disabled).
-				}
-				intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
-				return 1;
-			}
+	for(i = 0; i < 10; i++) {
+		if (!sd->deal.item[i].amount)
+			continue;
+		index = sd->deal.item[i].index;
+		if (inventory[index].amount < sd->deal.item[i].amount)
+		{ // if more than the player have -> hack
+			sprintf(message_to_gm, msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has.
+			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+			sprintf(message_to_gm, msg_txt(539), sd->status.inventory[index].amount, sd->status.inventory[index].nameid, sd->deal.item[i].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them.
+			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+			// if we block people
+			if (battle_config.ban_hack_trade < 0) {
+				chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
+				clif_setwaitclose(sd->fd); // forced to disconnect because of the hack
+				// message about the ban
+				sprintf(message_to_gm, msg_txt(540), battle_config.ban_spoof_namer); //  This player has been definitivly blocked.
+			// if we ban people
+			} else if (battle_config.ban_hack_trade > 0) {
+				chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_hack_trade, 0); // type: 2 - ban (year, month, day, hour, minute, second)
+				clif_setwaitclose(sd->fd); // forced to disconnect because of the hack
+				// message about the ban
+				sprintf(message_to_gm, msg_txt(507), battle_config.ban_spoof_namer); //  This player has been banned for %d minute(s).
+			} else
+				// message about the ban
+				sprintf(message_to_gm, msg_txt(508)); //  This player hasn't been banned (Ban option is disabled).
+			
+			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+			return 1;
 		}
 		}
-
+		inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory
+	}
 	return 0;
 	return 0;
 }
 }
 
 
 /*==========================================
 /*==========================================
- * Check here if we can add item in inventory (against full inventory)
+ * Checks if trade is possible (against zeny limits, inventory limits, etc)
  *------------------------------------------
  *------------------------------------------
  */
  */
-int trade_check(struct map_session_data *sd) {
+int trade_check(struct map_session_data *sd, struct map_session_data *target_sd) {
 	struct item inventory[MAX_INVENTORY];
 	struct item inventory[MAX_INVENTORY];
 	struct item inventory2[MAX_INVENTORY];
 	struct item inventory2[MAX_INVENTORY];
 	struct item_data *data;
 	struct item_data *data;
-	struct map_session_data *target_sd;
-	int trade_i, i, amount;
+	int trade_i, i, amount, n;
 
 
-	target_sd = map_id2sd(sd->trade_partner);
+	// check zenys value against hackers (Zeny was already checked on time of adding, but you never know when you lost some zeny since then.
+	if(sd->deal.zeny > sd->status.zeny || (target_sd->status.zeny + sd->deal.zeny) > MAX_ZENY)
+		return 0;
+	if(target_sd->deal.zeny > target_sd->status.zeny || (sd->status.zeny + target_sd->deal.zeny) > MAX_ZENY)
+		return 0;
 
 
 	// get inventory of player
 	// get inventory of player
 	memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY);
 	memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY);
@@ -191,85 +206,72 @@ int trade_check(struct map_session_data *sd) {
 	// check free slot in both inventory
 	// check free slot in both inventory
 	for(trade_i = 0; trade_i < 10; trade_i++) {
 	for(trade_i = 0; trade_i < 10; trade_i++) {
 		amount = sd->deal.item[trade_i].amount;
 		amount = sd->deal.item[trade_i].amount;
-		if (amount > 0) {
-			int n = sd->deal.item[trade_i].index;
-			// check quantity
+		if (amount) {
+			n = sd->deal.item[trade_i].index;
 			if (amount > inventory[n].amount)
 			if (amount > inventory[n].amount)
-				amount = inventory[n].amount;
-			if (amount > 0) {
-				data = itemdb_search(inventory[n].nameid);
-				i = MAX_INVENTORY;
-				// check for non-equipement item
-				if (!itemdb_isequip2(data)) {
-					for(i = 0; i < MAX_INVENTORY; i++)
-						if (inventory2[i].nameid == inventory[n].nameid &&
-							inventory2[i].card[0] == inventory[n].card[0] && inventory2[i].card[1] == inventory[n].card[1] &&
-							inventory2[i].card[2] == inventory[n].card[2] && inventory2[i].card[3] == inventory[n].card[3]) {
-							if (inventory2[i].amount + amount > MAX_AMOUNT)
-								return 0;
-							inventory2[i].amount += amount;
-							inventory[n].amount -= amount;
-							if (inventory[n].amount <= 0)
-								memset(&inventory[n], 0, sizeof(struct item));
-							break;
-						}
-				}
-				// check for equipement
-				if (i == MAX_INVENTORY) {
-					for(i = 0; i < MAX_INVENTORY; i++) {
-						if (inventory2[i].nameid == 0) {
-							memcpy(&inventory2[i], &inventory[n], sizeof(struct item));
-							inventory2[i].amount = amount;
-							inventory[n].amount -= amount;
-							if (inventory[n].amount <= 0)
-								memset(&inventory[n], 0, sizeof(struct item));
-							break;
-						}
+				return 0; //qty Exploit?
+			
+			data = itemdb_search(inventory[n].nameid);
+			i = MAX_INVENTORY;
+			if (!itemdb_isequip2(data)) { //Stackable item.
+				for(i = 0; i < MAX_INVENTORY; i++)
+					if (inventory2[i].nameid == inventory[n].nameid &&
+						inventory2[i].card[0] == inventory[n].card[0] && inventory2[i].card[1] == inventory[n].card[1] &&
+						inventory2[i].card[2] == inventory[n].card[2] && inventory2[i].card[3] == inventory[n].card[3]) {
+						if (inventory2[i].amount + amount > MAX_AMOUNT)
+							return 0;
+						inventory2[i].amount += amount;
+						inventory[n].amount -= amount;
+						//let's not make room, as pc_additem is done before pc_delitem, so it could lead to problems depending on order.
+//							if (!inventory[n].amount) 
+//								memset(&inventory[n], 0, sizeof(struct item));
+						break;
 					}
 					}
-					if (i == MAX_INVENTORY)
-						return 0;
-				}
+			}
+			
+			if (i == MAX_INVENTORY) {// look for an empty slot.
+				for(i = 0; i < MAX_INVENTORY && inventory2[i].nameid; i++);
+				if (i == MAX_INVENTORY)
+					return 0;
+				memcpy(&inventory2[i], &inventory[n], sizeof(struct item));
+				inventory2[i].amount = amount;
+				inventory[n].amount -= amount;
+//					if (!inventory[n].amount)
+//						memset(&inventory[n], 0, sizeof(struct item));
 			}
 			}
 		}
 		}
 		amount = target_sd->deal.item[trade_i].amount;
 		amount = target_sd->deal.item[trade_i].amount;
-		if (amount > 0) {
-			int n = target_sd->deal.item[trade_i].index;
-			// check quantity
-			if (amount > inventory2[n].amount)
-				amount = inventory2[n].amount;
-			if (amount > 0) {
-				// search if it's possible to add item (for full inventory)
-				data = itemdb_search(inventory2[n].nameid);
-				i = MAX_INVENTORY;
-				if (!itemdb_isequip2(data)) {
-					for(i = 0; i < MAX_INVENTORY; i++)
-						if (inventory[i].nameid == inventory2[n].nameid &&
-							inventory[i].card[0] == inventory2[n].card[0] && inventory[i].card[1] == inventory2[n].card[1] &&
-							inventory[i].card[2] == inventory2[n].card[2] && inventory[i].card[3] == inventory2[n].card[3]) {
-							if (inventory[i].amount + amount > MAX_AMOUNT)
-								return 0;
-							inventory[i].amount += amount;
-							inventory2[n].amount -= amount;
-							if (inventory2[n].amount <= 0)
-								memset(&inventory2[n], 0, sizeof(struct item));
-							break;
-						}
-				}
-				if (i == MAX_INVENTORY) {
-					for(i = 0; i < MAX_INVENTORY; i++) {
-						if (inventory[i].nameid == 0) {
-							memcpy(&inventory[i], &inventory2[n], sizeof(struct item));
-							inventory[i].amount = amount;
-							inventory2[n].amount -= amount;
-							if (inventory2[n].amount <= 0)
-								memset(&inventory2[n], 0, sizeof(struct item));
-							break;
-						}
-					}
-					if (i == MAX_INVENTORY)
+		if (!amount)
+			continue;
+		n = target_sd->deal.item[trade_i].index;
+		if (amount > inventory2[n].amount)
+			return 0;
+		// search if it's possible to add item (for full inventory)
+		data = itemdb_search(inventory2[n].nameid);
+		i = MAX_INVENTORY;
+		if (!itemdb_isequip2(data)) {
+			for(i = 0; i < MAX_INVENTORY; i++)
+				if (inventory[i].nameid == inventory2[n].nameid &&
+					inventory[i].card[0] == inventory2[n].card[0] && inventory[i].card[1] == inventory2[n].card[1] &&
+					inventory[i].card[2] == inventory2[n].card[2] && inventory[i].card[3] == inventory2[n].card[3]) {
+					if (inventory[i].amount + amount > MAX_AMOUNT)
 						return 0;
 						return 0;
+					inventory[i].amount += amount;
+					inventory2[n].amount -= amount;
+//					if (!inventory2[n].amount)
+//						memset(&inventory2[n], 0, sizeof(struct item));
+					break;
 				}
 				}
-			}
+		}
+		if (i == MAX_INVENTORY) {
+			for(i = 0; i < MAX_INVENTORY && inventory[i].nameid; i++);
+			if (i == MAX_INVENTORY)
+				return 0;
+			memcpy(&inventory[i], &inventory2[n], sizeof(struct item));
+			inventory[i].amount = amount;
+			inventory2[n].amount -= amount;
+//			if (!inventory2[n].amount)
+//				memset(&inventory2[n], 0, sizeof(struct item));
 		}
 		}
 	}
 	}
 
 
@@ -285,9 +287,14 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount) {
 	int trade_i, trade_weight, nameid;
 	int trade_i, trade_weight, nameid;
 
 
 	nullpo_retv(sd);
 	nullpo_retv(sd);
-	if (!sd->state.trading || (target_sd = map_id2sd(sd->trade_partner)) == NULL || sd->state.deal_locked > 0)
+	if (!sd->state.trading || sd->state.deal_locked > 0)
 		return; //Can't add stuff.
 		return; //Can't add stuff.
 
 
+	if ((target_sd = map_id2sd(sd->trade_partner)) == NULL) {
+		trade_tradecancel(sd);
+		return;
+	}
+	
 	if (index == 0)
 	if (index == 0)
 	{	//Adding Zeny
 	{	//Adding Zeny
 		if (amount >= 0 && amount <= MAX_ZENY && amount <= sd->status.zeny && // check amount
 		if (amount >= 0 && amount <= MAX_ZENY && amount <= sd->status.zeny && // check amount
@@ -296,7 +303,7 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount) {
 			sd->deal.zeny = amount;
 			sd->deal.zeny = amount;
 			clif_tradeadditem(sd, target_sd, 0, amount);
 			clif_tradeadditem(sd, target_sd, 0, amount);
 		} else //Cancel Transaction
 		} else //Cancel Transaction
-			trade_tradecancel(sd);
+			clif_tradeitemok(sd, 0, 1); //Send overweight when trying to add too much zeny? Hope they get the idea...
 		return;
 		return;
 	}
 	}
 	//Add an Item
 	//Add an Item
@@ -328,7 +335,7 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount) {
 	trade_weight = sd->inventory_data[index]->weight * amount;
 	trade_weight = sd->inventory_data[index]->weight * amount;
 	if (target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight)
 	if (target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight)
 	{	//fail to add item -- the player was over weighted.
 	{	//fail to add item -- the player was over weighted.
-		clif_tradeitemok(sd, index, 1);
+		clif_tradeitemok(sd, index+2, 1);
 		return;
 		return;
 	}
 	}
 
 
@@ -346,96 +353,78 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount) {
 	}
 	}
 	sd->deal.weight += trade_weight;
 	sd->deal.weight += trade_weight;
 
 
-	if (impossible_trade_check(sd))
-	{ // check exploit (trade more items that you have)
-		trade_tradecancel(sd);
-		return;
-	}
-
 	clif_tradeitemok(sd, index+2, 0); // Return the index as it was received
 	clif_tradeitemok(sd, index+2, 0); // Return the index as it was received
 	clif_tradeadditem(sd, target_sd, index+2, amount); //index fix
 	clif_tradeadditem(sd, target_sd, index+2, amount); //index fix
 }
 }
 
 
 /*==========================================
 /*==========================================
- * アイテム追加完了(ok押し)
+ * 'Ok' button on the trade window is pressed.
  *------------------------------------------
  *------------------------------------------
  */
  */
 void trade_tradeok(struct map_session_data *sd) {
 void trade_tradeok(struct map_session_data *sd) {
 	struct map_session_data *target_sd;
 	struct map_session_data *target_sd;
-	int trade_i;
-
-	nullpo_retv(sd);
-
-	// check items
-	for(trade_i = 0; trade_i < 10; trade_i++) {
-		if ((((sd->deal.item[trade_i].index) >= 0) &&
-		    (sd->deal.item[trade_i].amount > sd->status.inventory[sd->deal.item[trade_i].index].amount)) ||
-		    (sd->deal.item[trade_i].amount < 0)) {
-			trade_tradecancel(sd);
-			return;
-		}
-	}
 
 
-	// check exploit (trade more items that you have)
-	if (impossible_trade_check(sd)) {
-		trade_tradecancel(sd);
+	if(sd->state.deal_locked || !sd->state.trading)
 		return;
 		return;
-	}
-
-	// check zeny
-	if (sd->deal.zeny < 0 || sd->deal.zeny > MAX_ZENY || sd->deal.zeny > sd->status.zeny) { // check amount
+	
+	if ((target_sd = map_id2sd(sd->trade_partner)) == NULL) {
 		trade_tradecancel(sd);
 		trade_tradecancel(sd);
 		return;
 		return;
 	}
 	}
-
-	if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) {
-		sd->state.deal_locked = 1;
-		clif_tradeitemok(sd, 0, 0);
-		clif_tradedeal_lock(sd, 0);
-		clif_tradedeal_lock(target_sd, 1);
-	}
+	sd->state.deal_locked = 1;
+	clif_tradeitemok(sd, 0, 0);
+	clif_tradedeal_lock(sd, 0);
+	clif_tradedeal_lock(target_sd, 1);
 }
 }
 
 
 /*==========================================
 /*==========================================
- * 取引キャンセル
+ * 'Cancel' is pressed. (or trade was force-cancelled by the code)
  *------------------------------------------
  *------------------------------------------
  */
  */
 void trade_tradecancel(struct map_session_data *sd) {
 void trade_tradecancel(struct map_session_data *sd) {
 	struct map_session_data *target_sd;
 	struct map_session_data *target_sd;
 	int trade_i;
 	int trade_i;
 
 
-	nullpo_retv(sd);
+	if(!sd->state.trading)
+		return;
+	
+	for(trade_i = 0; trade_i < 10; trade_i++) { // give items back (only virtual)
+		if (!sd->deal.item[trade_i].amount)
+			continue;
+		clif_additem(sd, sd->deal.item[trade_i].index, sd->deal.item[trade_i].amount, 0);
+		sd->deal.item[trade_i].index = 0;
+		sd->deal.item[trade_i].amount = 0;
+	}
+	if (sd->deal.zeny) {
+		clif_updatestatus(sd, SP_ZENY);
+		sd->deal.zeny = 0;
+	}
 
 
-	if ((target_sd = map_id2sd(sd->trade_partner)) != NULL) {
-		for(trade_i = 0; trade_i < 10; trade_i++) { // give items back (only virtual)
-			if (sd->deal.item[trade_i].amount != 0) {
-				clif_additem(sd, sd->deal.item[trade_i].index, sd->deal.item[trade_i].amount, 0);
-				sd->deal.item[trade_i].index = 0;
-				sd->deal.item[trade_i].amount = 0;
-			}
-			if (target_sd->deal.item[trade_i].amount != 0) {
-				clif_additem(target_sd, target_sd->deal.item[trade_i].index, target_sd->deal.item[trade_i].amount, 0);
-				target_sd->deal.item[trade_i].index = 0;
-				target_sd->deal.item[trade_i].amount = 0;
-			}
-		}
-		if (sd->deal.zeny) {
-			clif_updatestatus(sd, SP_ZENY);
-			sd->deal.zeny = 0;
-		}
-		if (target_sd->deal.zeny) {
-			clif_updatestatus(target_sd, SP_ZENY);
-			target_sd->deal.zeny = 0;
-		}
-		sd->state.deal_locked = 0;
-		sd->trade_partner = 0;
-		sd->state.trading = 0;
-		target_sd->state.deal_locked = 0;
-		target_sd->trade_partner = 0;
-		target_sd->state.trading = 0;
-		clif_tradecancelled(sd);
-		clif_tradecancelled(target_sd);
+	target_sd = map_id2sd(sd->trade_partner);
+	sd->state.deal_locked = 0;
+	sd->state.trading = 0;
+	sd->trade_partner = 0;
+	clif_tradecancelled(sd);
+
+	if (!target_sd)
+		return;
+
+	for(trade_i = 0; trade_i < 10; trade_i++) { // give items back (only virtual)
+		if (!target_sd->deal.item[trade_i].amount)
+			continue;
+		clif_additem(target_sd, target_sd->deal.item[trade_i].index, target_sd->deal.item[trade_i].amount, 0);
+		target_sd->deal.item[trade_i].index = 0;
+		target_sd->deal.item[trade_i].amount = 0;
+	}
+	
+	if (target_sd->deal.zeny) {
+		clif_updatestatus(target_sd, SP_ZENY);
+		target_sd->deal.zeny = 0;
 	}
 	}
+	target_sd->state.deal_locked = 0;
+	target_sd->trade_partner = 0;
+	target_sd->state.trading = 0;
+	clif_tradecancelled(target_sd);
 }
 }
 
 
 /*==========================================
 /*==========================================
@@ -443,122 +432,106 @@ void trade_tradecancel(struct map_session_data *sd) {
  *------------------------------------------
  *------------------------------------------
  */
  */
 void trade_tradecommit(struct map_session_data *sd) {
 void trade_tradecommit(struct map_session_data *sd) {
-	struct map_session_data *target_sd;
+	struct map_session_data *tsd;
 	int trade_i;
 	int trade_i;
 	int flag;
 	int flag;
 
 
-	nullpo_retv(sd);
+	if (!sd->state.trading || !sd->state.deal_locked) //Locked should be 1 (pressed ok) before you can press trade.
+		return;
 
 
-	if (sd->state.trading && (target_sd = map_id2sd(sd->trade_partner)) != NULL) {
-		if ((sd->state.deal_locked >= 1) && (target_sd->state.deal_locked >= 1)) { // both have pressed 'ok'
-			if (sd->state.deal_locked < 2) { // set locked to 2
-				sd->state.deal_locked = 2;
-			}
-			if (target_sd->state.deal_locked == 2) { // the other one pressed 'trade' too
-				// check exploit (trade more items that you have)
-				if (impossible_trade_check(sd)) {
-					trade_tradecancel(sd);
-					return;
-				}
-				// check exploit (trade more items that you have)
-				if (impossible_trade_check(target_sd)) {
-					trade_tradecancel(target_sd);
-					return;
-				}
-				// check zenys value against hackers
-				if (sd->deal.zeny >= 0 && sd->deal.zeny <= MAX_ZENY && sd->deal.zeny <= sd->status.zeny && // check amount
-				    (target_sd->status.zeny + sd->deal.zeny) <= MAX_ZENY && // fix positiv overflow
-				    target_sd->deal.zeny >= 0 && target_sd->deal.zeny <= MAX_ZENY && target_sd->deal.zeny <= target_sd->status.zeny && // check amount
-				    (sd->status.zeny + target_sd->deal.zeny) <= MAX_ZENY) { // fix positiv overflow
-
-					// check for full inventory (can not add traded items)
-					if (!trade_check(sd)) { // check the both players
-						trade_tradecancel(sd);
-						return;
-					}
+	if ((tsd = map_id2sd(sd->trade_partner)) == NULL) {
+		trade_tradecancel(sd);
+		return;
+	}
+	
+	sd->state.deal_locked = 2;
+	
+	if (sd->state.deal_locked < 2 || tsd->state.deal_locked < 2)
+		return; //Not yet time for trading.
 
 
-					// trade is accepted
-					for(trade_i = 0; trade_i < 10; trade_i++) {
-						if (sd->deal.item[trade_i].amount != 0) {
-							int n = sd->deal.item[trade_i].index;
-
-							if (sd->status.inventory[n].amount < sd->deal.item[trade_i].amount)
-								sd->deal.item[trade_i].amount = sd->status.inventory[n].amount;
-
-							flag = pc_additem(target_sd, &sd->status.inventory[n], sd->deal.item[trade_i].amount);
-							if (flag == 0) {
-								//Logs (T)rade [Lupus]
-								if(log_config.pick > 0 )
-									log_pick(sd, "T", 0, sd->status.inventory[n].nameid, -(sd->deal.item[trade_i].amount), &sd->status.inventory[n]);
-									log_pick(target_sd, "T", 0, sd->status.inventory[n].nameid, sd->deal.item[trade_i].amount, &sd->status.inventory[n]);
-								//Logs
-								pc_delitem(sd, n, sd->deal.item[trade_i].amount, 1);
-							} else {
-								clif_additem(sd, n, sd->deal.item[trade_i].amount, 0);
-							}
-							sd->deal.item[trade_i].index = 0;
-							sd->deal.item[trade_i].amount = 0;
-                                                        
-						}
-						if (target_sd->deal.item[trade_i].amount != 0) {
-							int n = target_sd->deal.item[trade_i].index;
-
-							if (target_sd->status.inventory[n].amount < target_sd->deal.item[trade_i].amount)
-								target_sd->deal.item[trade_i].amount = target_sd->status.inventory[n].amount;
-
-							flag = pc_additem(sd, &target_sd->status.inventory[n], target_sd->deal.item[trade_i].amount);
-							if (flag == 0) {
-								//Logs (T)rade [Lupus]
-								if(log_config.pick > 0 )
-									log_pick(target_sd, "T", 0, target_sd->status.inventory[n].nameid, -(target_sd->deal.item[trade_i].amount), &target_sd->status.inventory[n]);
-									log_pick(sd, "T", 0, target_sd->status.inventory[n].nameid, target_sd->deal.item[trade_i].amount, &target_sd->status.inventory[n]);
-								//Logs
-								pc_delitem(target_sd, n, target_sd->deal.item[trade_i].amount, 1);
-							} else {
-								clif_additem(target_sd, n, target_sd->deal.item[trade_i].amount, 0);
-							}
-							target_sd->deal.item[trade_i].index = 0;
-							target_sd->deal.item[trade_i].amount = 0;
-						}
-					}
-					if (sd->deal.zeny) {
-						//Logs Zeny (T)rade [Lupus]
-						if(log_config.zeny > 0 )
-							log_zeny(target_sd, "T", sd, sd->deal.zeny);
-						//Logs
-						sd->status.zeny -= sd->deal.zeny;
-						target_sd->status.zeny += sd->deal.zeny;
-					}
-					if (target_sd->deal.zeny) {
-						//Logs Zeny (T)rade [Lupus]
-						if(log_config.zeny > 0 )
-							log_zeny(sd, "T", target_sd, target_sd->deal.zeny);
-						//Logs
-						target_sd->status.zeny -= target_sd->deal.zeny;
-						sd->status.zeny += target_sd->deal.zeny;
-					}
-					if (sd->deal.zeny || target_sd->deal.zeny) {
-						clif_updatestatus(sd, SP_ZENY);
-						sd->deal.zeny = 0;
-						clif_updatestatus(target_sd, SP_ZENY);
-						target_sd->deal.zeny = 0;
-					}
-					sd->state.deal_locked = 0;
-					sd->trade_partner = 0;
-					sd->state.trading = 0;
-					target_sd->state.deal_locked = 0;
-					target_sd->trade_partner = 0;
-					target_sd->state.trading = 0;
-					clif_tradecompleted(sd, 0);
-					clif_tradecompleted(target_sd, 0);
-					// save both player to avoid crash: they always have no advantage/disadvantage between the 2 players
-					chrif_save(sd,0); // do pc_makesavestatus and save storage too
-					chrif_save(target_sd,0); // do pc_makesavestatus and save storage too
-				// zeny value was modified!!!! hacker with packet modified
-				} else {
-					trade_tradecancel(sd);
-				}
-			}
+	//Now is a good time (to save on resources) to check that the trade can indeed be made and it's not exploitable.
+	// check exploit (trade more items that you have)
+	if (impossible_trade_check(sd)) {
+		trade_tradecancel(sd);
+		return;
+	}
+	// check exploit (trade more items that you have)
+	if (impossible_trade_check(tsd)) {
+		trade_tradecancel(tsd);
+		return;
+	}
+	// check for full inventory (can not add traded items)
+	if (!trade_check(sd,tsd)) { // check the both players
+		trade_tradecancel(sd);
+		return;
+	}
+	
+	// trade is accepted and correct.
+	for(trade_i = 0; trade_i < 10; trade_i++) {
+		int n;
+		if (sd->deal.item[trade_i].amount) {
+			n = sd->deal.item[trade_i].index;
+
+			flag = pc_additem(tsd, &sd->status.inventory[n], sd->deal.item[trade_i].amount);
+			if (flag == 0) {
+				//Logs (T)rade [Lupus]
+				if(log_config.pick > 0 )
+					log_pick(sd, "T", 0, sd->status.inventory[n].nameid, -(sd->deal.item[trade_i].amount), &sd->status.inventory[n]);
+					log_pick(tsd, "T", 0, sd->status.inventory[n].nameid, sd->deal.item[trade_i].amount, &sd->status.inventory[n]);
+				//Logs
+				pc_delitem(sd, n, sd->deal.item[trade_i].amount, 1);
+			} else
+				clif_additem(sd, n, sd->deal.item[trade_i].amount, 0);
+			sd->deal.item[trade_i].index = 0;
+			sd->deal.item[trade_i].amount = 0;
+		}
+		if (tsd->deal.item[trade_i].amount) {
+			n = tsd->deal.item[trade_i].index;
+
+			flag = pc_additem(sd, &tsd->status.inventory[n], tsd->deal.item[trade_i].amount);
+			if (flag == 0) {
+				//Logs (T)rade [Lupus]
+				if(log_config.pick > 0 )
+					log_pick(tsd, "T", 0, tsd->status.inventory[n].nameid, -(tsd->deal.item[trade_i].amount), &tsd->status.inventory[n]);
+					log_pick(sd, "T", 0, tsd->status.inventory[n].nameid, tsd->deal.item[trade_i].amount, &tsd->status.inventory[n]);
+				//Logs
+				pc_delitem(tsd, n, tsd->deal.item[trade_i].amount, 1);
+			} else
+				clif_additem(tsd, n, tsd->deal.item[trade_i].amount, 0);
+			tsd->deal.item[trade_i].index = 0;
+			tsd->deal.item[trade_i].amount = 0;
 		}
 		}
 	}
 	}
+	if (sd->deal.zeny || tsd->deal.zeny) {
+		if (sd->deal.zeny) {
+			sd->status.zeny -= sd->deal.zeny;
+			tsd->status.zeny += sd->deal.zeny;
+			if (log_config.zeny)
+				log_zeny(tsd, "T", sd, sd->deal.zeny);//Logs Zeny (T)rade [Lupus]
+			sd->deal.zeny = 0;
+		}
+		if (tsd->deal.zeny) {
+			tsd->status.zeny -= tsd->deal.zeny;
+			sd->status.zeny += tsd->deal.zeny;
+			if (log_config.zeny)
+				log_zeny(sd, "T", tsd, tsd->deal.zeny);//Logs Zeny (T)rade [Lupus]
+			tsd->deal.zeny = 0;
+		}
+		clif_updatestatus(sd, SP_ZENY);
+		clif_updatestatus(tsd, SP_ZENY);
+	}
+	
+	sd->state.deal_locked = 0;
+	sd->trade_partner = 0;
+	sd->state.trading = 0;
+	
+	tsd->state.deal_locked = 0;
+	tsd->trade_partner = 0;
+	tsd->state.trading = 0;
+	
+	clif_tradecompleted(sd, 0);
+	clif_tradecompleted(tsd, 0);
+	// save both player to avoid crash: they always have no advantage/disadvantage between the 2 players
+	chrif_save(sd,0); // do pc_makesavestatus and save storage too
+	chrif_save(tsd,0); // do pc_makesavestatus and save storage too
 }
 }