1 | // Copyright (c) Athena Dev Teams - Licensed under GNU GPL |
---|
2 | // For more information, see LICENCE in the main folder |
---|
3 | |
---|
4 | #include "../common/nullpo.h" |
---|
5 | #include "../common/socket.h" |
---|
6 | #include "clif.h" |
---|
7 | #include "itemdb.h" |
---|
8 | #include "map.h" |
---|
9 | #include "path.h" |
---|
10 | #include "trade.h" |
---|
11 | #include "pc.h" |
---|
12 | #include "npc.h" |
---|
13 | #include "battle.h" |
---|
14 | #include "chrif.h" |
---|
15 | #include "storage.h" |
---|
16 | #include "intif.h" |
---|
17 | #include "atcommand.h" |
---|
18 | #include "log.h" |
---|
19 | |
---|
20 | #include <stdio.h> |
---|
21 | #include <string.h> |
---|
22 | |
---|
23 | |
---|
24 | //Max distance from traders to enable a trade to take place. |
---|
25 | #define TRADE_DISTANCE 2 |
---|
26 | |
---|
27 | /*========================================== |
---|
28 | * Initiates a trade request. |
---|
29 | *------------------------------------------*/ |
---|
30 | void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd) |
---|
31 | { |
---|
32 | int level; |
---|
33 | |
---|
34 | nullpo_retv(sd); |
---|
35 | |
---|
36 | if (map[sd->bl.m].flag.notrade) { |
---|
37 | clif_displaymessage (sd->fd, msg_txt(272)); |
---|
38 | return; //Can't trade in notrade mapflag maps. |
---|
39 | } |
---|
40 | |
---|
41 | if (target_sd == NULL || sd == target_sd) { |
---|
42 | clif_tradestart(sd, 1); // character does not exist |
---|
43 | return; |
---|
44 | } |
---|
45 | |
---|
46 | if (target_sd->npc_id) |
---|
47 | { //Trade fails if you are using an NPC. |
---|
48 | clif_tradestart(sd, 2); |
---|
49 | return; |
---|
50 | } |
---|
51 | |
---|
52 | if (!battle_config.invite_request_check) { |
---|
53 | if (target_sd->guild_invite > 0 || target_sd->party_invite > 0 || target_sd->adopt_invite) { |
---|
54 | clif_tradestart(sd, 2); |
---|
55 | return; |
---|
56 | } |
---|
57 | } |
---|
58 | |
---|
59 | if ((target_sd->trade_partner != 0) || (sd->trade_partner != 0)) { |
---|
60 | clif_tradestart(sd, 2); // person is in another trade |
---|
61 | return; |
---|
62 | } |
---|
63 | |
---|
64 | level = pc_isGM(sd); |
---|
65 | if ( !pc_can_give_items(level) || !pc_can_give_items(pc_isGM(target_sd)) ) //check if both GMs are allowed to trade |
---|
66 | { |
---|
67 | clif_displaymessage(sd->fd, msg_txt(246)); |
---|
68 | clif_tradestart(sd, 2); // GM is not allowed to trade |
---|
69 | return; |
---|
70 | } |
---|
71 | |
---|
72 | //Fixed. Only real GMs can request trade from far away! [Lupus] |
---|
73 | if (level < lowest_gm_level && (sd->bl.m != target_sd->bl.m || |
---|
74 | !check_distance_bl(&sd->bl, &target_sd->bl, TRADE_DISTANCE) |
---|
75 | )) { |
---|
76 | clif_tradestart(sd, 0); // too far |
---|
77 | return ; |
---|
78 | } |
---|
79 | |
---|
80 | target_sd->trade_partner = sd->status.account_id; |
---|
81 | sd->trade_partner = target_sd->status.account_id; |
---|
82 | clif_traderequest(target_sd, sd->status.name); |
---|
83 | } |
---|
84 | |
---|
85 | /*========================================== |
---|
86 | * Reply to a trade-request. |
---|
87 | * Type values: |
---|
88 | * 0: Char is too far |
---|
89 | * 1: Character does not exist |
---|
90 | * 2: Trade failed |
---|
91 | * 3: Accept |
---|
92 | * 4: Cancel |
---|
93 | * Weird enough, the client should only send 3/4 |
---|
94 | * and the server is the one that can reply 0~2 |
---|
95 | *------------------------------------------*/ |
---|
96 | void trade_tradeack(struct map_session_data *sd, int type) |
---|
97 | { |
---|
98 | struct map_session_data *tsd; |
---|
99 | nullpo_retv(sd); |
---|
100 | |
---|
101 | if (sd->state.trading || !sd->trade_partner) |
---|
102 | return; //Already trading or no partner set. |
---|
103 | |
---|
104 | if ((tsd = map_id2sd(sd->trade_partner)) == NULL) { |
---|
105 | clif_tradestart(sd, 1); // character does not exist |
---|
106 | sd->trade_partner=0; |
---|
107 | return; |
---|
108 | } |
---|
109 | |
---|
110 | if (tsd->state.trading || tsd->trade_partner != sd->bl.id) |
---|
111 | { |
---|
112 | clif_tradestart(sd, 2); |
---|
113 | return; //Already trading or wrong partner. |
---|
114 | } |
---|
115 | |
---|
116 | if (type == 4) { // Cancel |
---|
117 | clif_tradestart(tsd, type); |
---|
118 | clif_tradestart(sd, type); |
---|
119 | sd->state.deal_locked = 0; |
---|
120 | sd->trade_partner = 0; |
---|
121 | tsd->state.deal_locked = 0; |
---|
122 | tsd->trade_partner = 0; |
---|
123 | return; |
---|
124 | } |
---|
125 | |
---|
126 | if (type != 3) |
---|
127 | return; //If client didn't send accept, it's a broken packet? |
---|
128 | |
---|
129 | //Copied here as well since the original character could had warped. |
---|
130 | if (pc_isGM(tsd) < lowest_gm_level && (sd->bl.m != tsd->bl.m || |
---|
131 | !check_distance_bl(&sd->bl, &tsd->bl, TRADE_DISTANCE) |
---|
132 | )) { |
---|
133 | clif_tradestart(sd, 0); // too far |
---|
134 | sd->trade_partner=0; |
---|
135 | tsd->trade_partner = 0; |
---|
136 | return; |
---|
137 | } |
---|
138 | |
---|
139 | //Check if you can start trade. |
---|
140 | if (sd->npc_id || sd->vender_id || sd->state.storage_flag || |
---|
141 | tsd->npc_id || tsd->vender_id || tsd->state.storage_flag) |
---|
142 | { //Fail |
---|
143 | clif_tradestart(sd, 2); |
---|
144 | clif_tradestart(tsd, 2); |
---|
145 | sd->state.deal_locked = 0; |
---|
146 | sd->trade_partner = 0; |
---|
147 | tsd->state.deal_locked = 0; |
---|
148 | tsd->trade_partner = 0; |
---|
149 | return; |
---|
150 | } |
---|
151 | |
---|
152 | //Initiate trade |
---|
153 | sd->state.trading = 1; |
---|
154 | tsd->state.trading = 1; |
---|
155 | memset(&sd->deal, 0, sizeof(sd->deal)); |
---|
156 | memset(&tsd->deal, 0, sizeof(tsd->deal)); |
---|
157 | clif_tradestart(tsd, type); |
---|
158 | clif_tradestart(sd, type); |
---|
159 | } |
---|
160 | |
---|
161 | /*========================================== |
---|
162 | * Check here hacker for duplicate item in trade |
---|
163 | * normal client refuse to have 2 same types of item (except equipment) in same trade window |
---|
164 | * normal client authorise only no equiped item and only from inventory |
---|
165 | *------------------------------------------*/ |
---|
166 | int impossible_trade_check(struct map_session_data *sd) |
---|
167 | { |
---|
168 | struct item inventory[MAX_INVENTORY]; |
---|
169 | char message_to_gm[200]; |
---|
170 | int i, index; |
---|
171 | |
---|
172 | nullpo_retr(1, sd); |
---|
173 | |
---|
174 | if(sd->deal.zeny > sd->status.zeny) |
---|
175 | { |
---|
176 | pc_setglobalreg(sd,"ZENY_HACKER",1); |
---|
177 | return -1; |
---|
178 | } |
---|
179 | |
---|
180 | // get inventory of player |
---|
181 | memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY); |
---|
182 | |
---|
183 | // remove this part: arrows can be trade and equiped |
---|
184 | // re-added! [celest] |
---|
185 | // remove equiped items (they can not be trade) |
---|
186 | for (i = 0; i < MAX_INVENTORY; i++) |
---|
187 | if (inventory[i].nameid > 0 && inventory[i].equip && !(inventory[i].equip & EQP_AMMO)) |
---|
188 | memset(&inventory[i], 0, sizeof(struct item)); |
---|
189 | |
---|
190 | // check items in player inventory |
---|
191 | for(i = 0; i < 10; i++) { |
---|
192 | if (!sd->deal.item[i].amount) |
---|
193 | continue; |
---|
194 | index = sd->deal.item[i].index; |
---|
195 | if (inventory[index].amount < sd->deal.item[i].amount) |
---|
196 | { // if more than the player have -> hack |
---|
197 | 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. |
---|
198 | intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); |
---|
199 | sprintf(message_to_gm, msg_txt(539), inventory[index].amount, 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. |
---|
200 | intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); |
---|
201 | // if we block people |
---|
202 | if (battle_config.ban_hack_trade < 0) { |
---|
203 | chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block |
---|
204 | set_eof(sd->fd); // forced to disconnect because of the hack |
---|
205 | // message about the ban |
---|
206 | sprintf(message_to_gm, msg_txt(540)); // This player has been definitivly blocked. |
---|
207 | // if we ban people |
---|
208 | } else if (battle_config.ban_hack_trade > 0) { |
---|
209 | 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) |
---|
210 | set_eof(sd->fd); // forced to disconnect because of the hack |
---|
211 | // message about the ban |
---|
212 | sprintf(message_to_gm, msg_txt(507), battle_config.ban_hack_trade); // This player has been banned for %d minute(s). |
---|
213 | } else |
---|
214 | // message about the ban |
---|
215 | sprintf(message_to_gm, msg_txt(508)); // This player hasn't been banned (Ban option is disabled). |
---|
216 | |
---|
217 | intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); |
---|
218 | return 1; |
---|
219 | } |
---|
220 | inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory |
---|
221 | } |
---|
222 | return 0; |
---|
223 | } |
---|
224 | |
---|
225 | /*========================================== |
---|
226 | * Checks if trade is possible (against zeny limits, inventory limits, etc) |
---|
227 | *------------------------------------------*/ |
---|
228 | int trade_check(struct map_session_data *sd, struct map_session_data *tsd) |
---|
229 | { |
---|
230 | struct item inventory[MAX_INVENTORY]; |
---|
231 | struct item inventory2[MAX_INVENTORY]; |
---|
232 | struct item_data *data; |
---|
233 | int trade_i, i, n; |
---|
234 | short amount; |
---|
235 | |
---|
236 | // check zenys value against hackers (Zeny was already checked on time of adding, but you never know when you lost some zeny since then. |
---|
237 | if(sd->deal.zeny > sd->status.zeny || (tsd->status.zeny > MAX_ZENY - sd->deal.zeny)) |
---|
238 | return 0; |
---|
239 | if(tsd->deal.zeny > tsd->status.zeny || (sd->status.zeny > MAX_ZENY - tsd->deal.zeny)) |
---|
240 | return 0; |
---|
241 | |
---|
242 | // get inventory of player |
---|
243 | memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY); |
---|
244 | memcpy(&inventory2, &tsd->status.inventory, sizeof(struct item) * MAX_INVENTORY); |
---|
245 | |
---|
246 | // check free slot in both inventory |
---|
247 | for(trade_i = 0; trade_i < 10; trade_i++) { |
---|
248 | amount = sd->deal.item[trade_i].amount; |
---|
249 | if (amount) { |
---|
250 | n = sd->deal.item[trade_i].index; |
---|
251 | if (amount > inventory[n].amount) |
---|
252 | return 0; //qty Exploit? |
---|
253 | |
---|
254 | data = itemdb_search(inventory[n].nameid); |
---|
255 | i = MAX_INVENTORY; |
---|
256 | if (itemdb_isstackable2(data)) { //Stackable item. |
---|
257 | for(i = 0; i < MAX_INVENTORY; i++) |
---|
258 | if (inventory2[i].nameid == inventory[n].nameid && |
---|
259 | inventory2[i].card[0] == inventory[n].card[0] && inventory2[i].card[1] == inventory[n].card[1] && |
---|
260 | inventory2[i].card[2] == inventory[n].card[2] && inventory2[i].card[3] == inventory[n].card[3]) { |
---|
261 | if (inventory2[i].amount + amount > MAX_AMOUNT) |
---|
262 | return 0; |
---|
263 | inventory2[i].amount += amount; |
---|
264 | inventory[n].amount -= amount; |
---|
265 | break; |
---|
266 | } |
---|
267 | } |
---|
268 | |
---|
269 | if (i == MAX_INVENTORY) {// look for an empty slot. |
---|
270 | for(i = 0; i < MAX_INVENTORY && inventory2[i].nameid; i++); |
---|
271 | if (i == MAX_INVENTORY) |
---|
272 | return 0; |
---|
273 | memcpy(&inventory2[i], &inventory[n], sizeof(struct item)); |
---|
274 | inventory2[i].amount = amount; |
---|
275 | inventory[n].amount -= amount; |
---|
276 | } |
---|
277 | } |
---|
278 | amount = tsd->deal.item[trade_i].amount; |
---|
279 | if (!amount) |
---|
280 | continue; |
---|
281 | n = tsd->deal.item[trade_i].index; |
---|
282 | if (amount > inventory2[n].amount) |
---|
283 | return 0; |
---|
284 | // search if it's possible to add item (for full inventory) |
---|
285 | data = itemdb_search(inventory2[n].nameid); |
---|
286 | i = MAX_INVENTORY; |
---|
287 | if (itemdb_isstackable2(data)) { |
---|
288 | for(i = 0; i < MAX_INVENTORY; i++) |
---|
289 | if (inventory[i].nameid == inventory2[n].nameid && |
---|
290 | inventory[i].card[0] == inventory2[n].card[0] && inventory[i].card[1] == inventory2[n].card[1] && |
---|
291 | inventory[i].card[2] == inventory2[n].card[2] && inventory[i].card[3] == inventory2[n].card[3]) { |
---|
292 | if (inventory[i].amount + amount > MAX_AMOUNT) |
---|
293 | return 0; |
---|
294 | inventory[i].amount += amount; |
---|
295 | inventory2[n].amount -= amount; |
---|
296 | break; |
---|
297 | } |
---|
298 | } |
---|
299 | if (i == MAX_INVENTORY) { |
---|
300 | for(i = 0; i < MAX_INVENTORY && inventory[i].nameid; i++); |
---|
301 | if (i == MAX_INVENTORY) |
---|
302 | return 0; |
---|
303 | memcpy(&inventory[i], &inventory2[n], sizeof(struct item)); |
---|
304 | inventory[i].amount = amount; |
---|
305 | inventory2[n].amount -= amount; |
---|
306 | } |
---|
307 | } |
---|
308 | |
---|
309 | return 1; |
---|
310 | } |
---|
311 | |
---|
312 | /*========================================== |
---|
313 | * Adds an item/qty to the trade window |
---|
314 | *------------------------------------------*/ |
---|
315 | void trade_tradeadditem(struct map_session_data *sd, short index, short amount) |
---|
316 | { |
---|
317 | struct map_session_data *target_sd; |
---|
318 | struct item *item; |
---|
319 | int trade_i, trade_weight; |
---|
320 | int src_lv, dst_lv; |
---|
321 | |
---|
322 | nullpo_retv(sd); |
---|
323 | if( !sd->state.trading || sd->state.deal_locked > 0 ) |
---|
324 | return; //Can't add stuff. |
---|
325 | |
---|
326 | if( (target_sd = map_id2sd(sd->trade_partner)) == NULL ) |
---|
327 | { |
---|
328 | trade_tradecancel(sd); |
---|
329 | return; |
---|
330 | } |
---|
331 | |
---|
332 | if( amount == 0 ) |
---|
333 | { //Why do this.. ~.~ just send an ack, the item won't display on the trade window. |
---|
334 | clif_tradeitemok(sd, index, 0); |
---|
335 | return; |
---|
336 | } |
---|
337 | |
---|
338 | index -= 2; // 0 is for zeny, 1 is unknown. Gravity, go figure... |
---|
339 | |
---|
340 | //Item checks... |
---|
341 | if( index < 0 || index >= MAX_INVENTORY ) |
---|
342 | return; |
---|
343 | if( amount < 0 || amount > sd->status.inventory[index].amount ) |
---|
344 | return; |
---|
345 | |
---|
346 | item = &sd->status.inventory[index]; |
---|
347 | src_lv = pc_isGM(sd); |
---|
348 | dst_lv = pc_isGM(target_sd); |
---|
349 | if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade |
---|
350 | (pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade |
---|
351 | { |
---|
352 | clif_displaymessage (sd->fd, msg_txt(260)); |
---|
353 | clif_tradeitemok(sd, index+2, 1); |
---|
354 | return; |
---|
355 | } |
---|
356 | |
---|
357 | //Locate a trade position |
---|
358 | ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 ); |
---|
359 | if( trade_i == 10 ) //No space left |
---|
360 | { |
---|
361 | clif_tradeitemok(sd, index+2, 1); |
---|
362 | return; |
---|
363 | } |
---|
364 | |
---|
365 | trade_weight = sd->inventory_data[index]->weight * amount; |
---|
366 | if( target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight ) |
---|
367 | { //fail to add item -- the player was over weighted. |
---|
368 | clif_tradeitemok(sd, index+2, 1); |
---|
369 | return; |
---|
370 | } |
---|
371 | |
---|
372 | if( sd->deal.item[trade_i].index == index ) |
---|
373 | { //The same item as before is being readjusted. |
---|
374 | if( sd->deal.item[trade_i].amount + amount > sd->status.inventory[index].amount ) |
---|
375 | { //packet deal exploit check |
---|
376 | amount = sd->status.inventory[index].amount - sd->deal.item[trade_i].amount; |
---|
377 | trade_weight = sd->inventory_data[index]->weight * amount; |
---|
378 | } |
---|
379 | sd->deal.item[trade_i].amount += amount; |
---|
380 | } |
---|
381 | else |
---|
382 | { //New deal item |
---|
383 | sd->deal.item[trade_i].index = index; |
---|
384 | sd->deal.item[trade_i].amount = amount; |
---|
385 | } |
---|
386 | sd->deal.weight += trade_weight; |
---|
387 | |
---|
388 | clif_tradeitemok(sd, index+2, 0); // Return the index as it was received |
---|
389 | clif_tradeadditem(sd, target_sd, index+2, amount); |
---|
390 | } |
---|
391 | |
---|
392 | /*========================================== |
---|
393 | * Adds the specified amount of zeny to the trade window |
---|
394 | *------------------------------------------*/ |
---|
395 | void trade_tradeaddzeny(struct map_session_data* sd, int amount) |
---|
396 | { |
---|
397 | struct map_session_data* target_sd; |
---|
398 | nullpo_retv(sd); |
---|
399 | |
---|
400 | if( !sd->state.trading || sd->state.deal_locked > 0 ) |
---|
401 | return; //Can't add stuff. |
---|
402 | |
---|
403 | if( (target_sd = map_id2sd(sd->trade_partner)) == NULL ) |
---|
404 | { |
---|
405 | trade_tradecancel(sd); |
---|
406 | return; |
---|
407 | } |
---|
408 | |
---|
409 | if( amount < 0 || amount > sd->status.zeny || amount > MAX_ZENY - target_sd->status.zeny ) |
---|
410 | { // invalid values, no appropriate packet for it => abort |
---|
411 | trade_tradecancel(sd); |
---|
412 | return; |
---|
413 | } |
---|
414 | |
---|
415 | sd->deal.zeny = amount; |
---|
416 | clif_tradeadditem(sd, target_sd, 0, amount); |
---|
417 | } |
---|
418 | |
---|
419 | /*========================================== |
---|
420 | * 'Ok' button on the trade window is pressed. |
---|
421 | *------------------------------------------*/ |
---|
422 | void trade_tradeok(struct map_session_data *sd) |
---|
423 | { |
---|
424 | struct map_session_data *target_sd; |
---|
425 | |
---|
426 | if(sd->state.deal_locked || !sd->state.trading) |
---|
427 | return; |
---|
428 | |
---|
429 | if ((target_sd = map_id2sd(sd->trade_partner)) == NULL) { |
---|
430 | trade_tradecancel(sd); |
---|
431 | return; |
---|
432 | } |
---|
433 | sd->state.deal_locked = 1; |
---|
434 | clif_tradeitemok(sd, 0, 0); |
---|
435 | clif_tradedeal_lock(sd, 0); |
---|
436 | clif_tradedeal_lock(target_sd, 1); |
---|
437 | } |
---|
438 | |
---|
439 | /*========================================== |
---|
440 | * 'Cancel' is pressed. (or trade was force-cancelled by the code) |
---|
441 | *------------------------------------------*/ |
---|
442 | void trade_tradecancel(struct map_session_data *sd) |
---|
443 | { |
---|
444 | struct map_session_data *target_sd; |
---|
445 | int trade_i; |
---|
446 | |
---|
447 | target_sd = map_id2sd(sd->trade_partner); |
---|
448 | |
---|
449 | if(!sd->state.trading) |
---|
450 | { // Not trade acepted |
---|
451 | if( target_sd ) target_sd->trade_partner = 0; |
---|
452 | sd->trade_partner = 0; |
---|
453 | return; |
---|
454 | } |
---|
455 | |
---|
456 | for(trade_i = 0; trade_i < 10; trade_i++) { // give items back (only virtual) |
---|
457 | if (!sd->deal.item[trade_i].amount) |
---|
458 | continue; |
---|
459 | clif_additem(sd, sd->deal.item[trade_i].index, sd->deal.item[trade_i].amount, 0); |
---|
460 | sd->deal.item[trade_i].index = 0; |
---|
461 | sd->deal.item[trade_i].amount = 0; |
---|
462 | } |
---|
463 | if (sd->deal.zeny) { |
---|
464 | clif_updatestatus(sd, SP_ZENY); |
---|
465 | sd->deal.zeny = 0; |
---|
466 | } |
---|
467 | |
---|
468 | sd->state.deal_locked = 0; |
---|
469 | sd->state.trading = 0; |
---|
470 | sd->trade_partner = 0; |
---|
471 | clif_tradecancelled(sd); |
---|
472 | |
---|
473 | if (!target_sd) |
---|
474 | return; |
---|
475 | |
---|
476 | for(trade_i = 0; trade_i < 10; trade_i++) { // give items back (only virtual) |
---|
477 | if (!target_sd->deal.item[trade_i].amount) |
---|
478 | continue; |
---|
479 | clif_additem(target_sd, target_sd->deal.item[trade_i].index, target_sd->deal.item[trade_i].amount, 0); |
---|
480 | target_sd->deal.item[trade_i].index = 0; |
---|
481 | target_sd->deal.item[trade_i].amount = 0; |
---|
482 | } |
---|
483 | |
---|
484 | if (target_sd->deal.zeny) { |
---|
485 | clif_updatestatus(target_sd, SP_ZENY); |
---|
486 | target_sd->deal.zeny = 0; |
---|
487 | } |
---|
488 | target_sd->state.deal_locked = 0; |
---|
489 | target_sd->trade_partner = 0; |
---|
490 | target_sd->state.trading = 0; |
---|
491 | clif_tradecancelled(target_sd); |
---|
492 | } |
---|
493 | |
---|
494 | /*========================================== |
---|
495 | * æøø(tradeµ) |
---|
496 | *------------------------------------------*/ |
---|
497 | void trade_tradecommit(struct map_session_data *sd) |
---|
498 | { |
---|
499 | struct map_session_data *tsd; |
---|
500 | int trade_i; |
---|
501 | int flag; |
---|
502 | |
---|
503 | if (!sd->state.trading || !sd->state.deal_locked) //Locked should be 1 (pressed ok) before you can press trade. |
---|
504 | return; |
---|
505 | |
---|
506 | if ((tsd = map_id2sd(sd->trade_partner)) == NULL) { |
---|
507 | trade_tradecancel(sd); |
---|
508 | return; |
---|
509 | } |
---|
510 | |
---|
511 | sd->state.deal_locked = 2; |
---|
512 | |
---|
513 | if (tsd->state.deal_locked < 2) |
---|
514 | return; //Not yet time for trading. |
---|
515 | |
---|
516 | //Now is a good time (to save on resources) to check that the trade can indeed be made and it's not exploitable. |
---|
517 | // check exploit (trade more items that you have) |
---|
518 | if (impossible_trade_check(sd)) { |
---|
519 | trade_tradecancel(sd); |
---|
520 | return; |
---|
521 | } |
---|
522 | // check exploit (trade more items that you have) |
---|
523 | if (impossible_trade_check(tsd)) { |
---|
524 | trade_tradecancel(tsd); |
---|
525 | return; |
---|
526 | } |
---|
527 | // check for full inventory (can not add traded items) |
---|
528 | if (!trade_check(sd,tsd)) { // check the both players |
---|
529 | trade_tradecancel(sd); |
---|
530 | return; |
---|
531 | } |
---|
532 | |
---|
533 | // trade is accepted and correct. |
---|
534 | for( trade_i = 0; trade_i < 10; trade_i++ ) |
---|
535 | { |
---|
536 | int n; |
---|
537 | if (sd->deal.item[trade_i].amount) |
---|
538 | { |
---|
539 | n = sd->deal.item[trade_i].index; |
---|
540 | |
---|
541 | flag = pc_additem(tsd, &sd->status.inventory[n], sd->deal.item[trade_i].amount); |
---|
542 | if (flag == 0) |
---|
543 | { |
---|
544 | //Logs (T)rade [Lupus] |
---|
545 | if(log_config.enable_logs&0x2) |
---|
546 | { |
---|
547 | log_pick_pc(sd, "T", sd->status.inventory[n].nameid, -(sd->deal.item[trade_i].amount), &sd->status.inventory[n]); |
---|
548 | log_pick_pc(tsd, "T", sd->status.inventory[n].nameid, sd->deal.item[trade_i].amount, &sd->status.inventory[n]); |
---|
549 | } |
---|
550 | pc_delitem(sd, n, sd->deal.item[trade_i].amount, 1); |
---|
551 | } else |
---|
552 | clif_additem(sd, n, sd->deal.item[trade_i].amount, 0); |
---|
553 | sd->deal.item[trade_i].index = 0; |
---|
554 | sd->deal.item[trade_i].amount = 0; |
---|
555 | } |
---|
556 | if (tsd->deal.item[trade_i].amount) |
---|
557 | { |
---|
558 | n = tsd->deal.item[trade_i].index; |
---|
559 | |
---|
560 | flag = pc_additem(sd, &tsd->status.inventory[n], tsd->deal.item[trade_i].amount); |
---|
561 | if (flag == 0) |
---|
562 | { |
---|
563 | //Logs (T)rade [Lupus] |
---|
564 | if(log_config.enable_logs&0x2) |
---|
565 | { |
---|
566 | log_pick_pc(tsd, "T", tsd->status.inventory[n].nameid, -(tsd->deal.item[trade_i].amount), &tsd->status.inventory[n]); |
---|
567 | log_pick_pc(sd, "T", tsd->status.inventory[n].nameid, tsd->deal.item[trade_i].amount, &tsd->status.inventory[n]); |
---|
568 | } |
---|
569 | pc_delitem(tsd, n, tsd->deal.item[trade_i].amount, 1); |
---|
570 | } else |
---|
571 | clif_additem(tsd, n, tsd->deal.item[trade_i].amount, 0); |
---|
572 | tsd->deal.item[trade_i].index = 0; |
---|
573 | tsd->deal.item[trade_i].amount = 0; |
---|
574 | } |
---|
575 | } |
---|
576 | |
---|
577 | if( sd->deal.zeny || tsd->deal.zeny ) |
---|
578 | { |
---|
579 | sd->status.zeny += tsd->deal.zeny - sd->deal.zeny; |
---|
580 | tsd->status.zeny += sd->deal.zeny - tsd->deal.zeny; |
---|
581 | |
---|
582 | //Logs Zeny (T)rade [Lupus] |
---|
583 | if( sd->deal.zeny && log_config.zeny ) |
---|
584 | log_zeny(tsd, "T", sd, sd->deal.zeny); |
---|
585 | if( tsd->deal.zeny && log_config.zeny ) |
---|
586 | log_zeny(sd, "T", tsd, tsd->deal.zeny); |
---|
587 | |
---|
588 | sd->deal.zeny = 0; |
---|
589 | tsd->deal.zeny = 0; |
---|
590 | |
---|
591 | clif_updatestatus(sd, SP_ZENY); |
---|
592 | clif_updatestatus(tsd, SP_ZENY); |
---|
593 | } |
---|
594 | |
---|
595 | sd->state.deal_locked = 0; |
---|
596 | sd->trade_partner = 0; |
---|
597 | sd->state.trading = 0; |
---|
598 | |
---|
599 | tsd->state.deal_locked = 0; |
---|
600 | tsd->trade_partner = 0; |
---|
601 | tsd->state.trading = 0; |
---|
602 | |
---|
603 | clif_tradecompleted(sd, 0); |
---|
604 | clif_tradecompleted(tsd, 0); |
---|
605 | |
---|
606 | // save both player to avoid crash: they always have no advantage/disadvantage between the 2 players |
---|
607 | if (save_settings&1) |
---|
608 | { |
---|
609 | chrif_save(sd,0); |
---|
610 | chrif_save(tsd,0); |
---|
611 | } |
---|
612 | } |
---|