summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt5
-rw-r--r--conf-tmpl/atcommand_athena.conf3
-rw-r--r--conf-tmpl/msg_athena.conf4
-rw-r--r--src/map/atcommand.c23
-rw-r--r--src/map/atcommand.h2
-rw-r--r--src/map/skill.c10
-rw-r--r--src/map/status.c8
-rw-r--r--src/map/trade.c663
8 files changed, 357 insertions, 361 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 29b1688eb..07c6ae7e6 100644
--- a/Changelog-Trunk.txt
+++ b/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.
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
attempt at tabulating the commands presented. [Skotlex]
* Updated SKA to return a random value between 0 and 99 each time
diff --git a/conf-tmpl/atcommand_athena.conf b/conf-tmpl/atcommand_athena.conf
index 496e6132d..0cce4e09a 100644
--- a/conf-tmpl/atcommand_athena.conf
+++ b/conf-tmpl/atcommand_athena.conf
@@ -181,6 +181,9 @@ gmotd: 20
// follow a player (including warping to them)
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").
kick: 20
diff --git a/conf-tmpl/msg_athena.conf b/conf-tmpl/msg_athena.conf
index f604c55c3..46de6d187 100644
--- a/conf-tmpl/msg_athena.conf
+++ b/conf-tmpl/msg_athena.conf
@@ -284,7 +284,9 @@
272: You can't trade on this map
273: Commands available:
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
// --------------------
299: ?? Castles
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 1e6f76516..0fd9a0d7f 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -295,6 +295,7 @@ ACMD_FUNC(clone); // [Valaris]
ACMD_FUNC(tonpc); // LuzZza
ACMD_FUNC(commands); // [Skotlex]
ACMD_FUNC(noask); //LuzZza
+ACMD_FUNC(request); //LuzZza
/*==========================================
*AtCommandInfo atcommand_info[]構造体の定義
@@ -611,6 +612,7 @@ static AtCommandInfo atcommand_info[] = {
{ AtCommand_ToNPC, "@tonpc", 40, atcommand_tonpc }, // LuzZza
{ AtCommand_Commands, "@commands", 1, atcommand_commands }, // [Skotlex]
{ AtCommand_NoAsk, "@noask", 1, atcommand_noask }, // [LuzZza]
+ { AtCommand_Request, "@request", 20, atcommand_request }, // [LuzZza]
// add new commands before this line
{ AtCommand_Unknown, NULL, 1, NULL }
@@ -10273,6 +10275,27 @@ int atcommand_noask(
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() {
users_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int));
duel_count = 0;
diff --git a/src/map/atcommand.h b/src/map/atcommand.h
index a0c56821e..a9eb69aba 100644
--- a/src/map/atcommand.h
+++ b/src/map/atcommand.h
@@ -270,7 +270,7 @@ enum AtCommandType {
AtCommand_ToNPC, // LuzZza
AtCommand_Commands, // [Skotlex]
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]
AtCommand_Unknown,
AtCommand_MAX
diff --git a/src/map/skill.c b/src/map/skill.c
index d5ec79977..aebb74dbd 100644
--- a/src/map/skill.c
+++ b/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)
delay += 300 * battle_config.combo_delay_rate / 100;
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);
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))
delay += 300 * battle_config.combo_delay_rate /100;
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);
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;
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);
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;
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);
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))
delay += 300 * battle_config.combo_delay_rate /100;
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);
break;
}
diff --git a/src/map/status.c b/src/map/status.c
index b9d2b904e..6afc10bb0 100644
--- a/src/map/status.c
+++ b/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
case TK_STORMKICK:
clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1);
- if (ud) ud->attackabletime = gettick()+tick;
break;
case TK_DOWNKICK:
clif_skill_nodamage(bl,bl,TK_READYDOWN,1,1);
- if (ud) ud->attackabletime = gettick()+tick;
break;
case TK_TURNKICK:
clif_skill_nodamage(bl,bl,TK_READYTURN,1,1);
- if (ud) ud->attackabletime = gettick()+tick;
break;
case TK_COUNTER:
clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1);
- if (ud) ud->attackabletime = gettick()+tick;
break;
}
+ if (ud) {
+ ud->attackabletime = gettick()+tick;
+ unit_set_walkdelay(bl, gettick(), tick, 1);
+ }
}
break;
case SC_TKREST:
diff --git a/src/map/trade.c b/src/map/trade.c
index aa9f236f3..002d974da 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -20,7 +20,7 @@
/*==========================================
- * 取引要請を相手に送る
+ * Initiates a trade request.
*------------------------------------------
*/
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.
}
- 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
+ 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) {
struct map_session_data *target_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));
// 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;
}
/*==========================================
- * 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 inventory2[MAX_INVENTORY];
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
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
for(trade_i = 0; trade_i < 10; trade_i++) {
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)
- 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;
- 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;
+ 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;
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.
+ if ((target_sd = map_id2sd(sd->trade_partner)) == NULL) {
+ trade_tradecancel(sd);
+ return;
+ }
+
if (index == 0)
{ //Adding Zeny
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;
clif_tradeadditem(sd, target_sd, 0, amount);
} 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;
}
//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;
if (target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight)
{ //fail to add item -- the player was over weighted.
- clif_tradeitemok(sd, index, 1);
+ clif_tradeitemok(sd, index+2, 1);
return;
}
@@ -346,96 +353,78 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount) {
}
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_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) {
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;
- }
-
- // 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);
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) {
struct map_session_data *target_sd;
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) {
- struct map_session_data *target_sd;
+ struct map_session_data *tsd;
int trade_i;
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
}