summaryrefslogblamecommitdiff
path: root/src/map/trade.cpp
blob: fc4c82218d5870e2d54f2178644f2c3075c54858 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12


                   








                               

                                            
                                 

                                            
                                                                   
 
                                       
 
                    
 
                                                   


                                                
                                            
             
                                                                                   





                                                  
                                   



                                                                        
                                                               








                                                        
                                                    




                                                                 
                                                              




             
                                                             
     


                                            
               

                                            
                                                          
 
                                       
                    
 
                                                           
     

                                         







                                         
                                  
                                   
                                         
 
                                                                                       
                                   
                                     
     


                                            
                     

                                            
                                                                           
 

                                       




                         
 
                    
 
                                                            






                                                                      
                                                            


















                                                                       
 















                                                                                                         
 


                                                          
                                                                                                              



                                                  
                                                                                                          







                                                                       
                                                      


                                       
                                                             

                                                                

                                                                                        
































                                                                                    


                                            
                                     

                                            
                                               
 
                                       
                
 
                    






                                                                         
                                  




                   
                                                           

                            


                                          
     


                                            
                        

                                            
                                                   
 
                                       
                
 
                    
 
                                                           




                                                                
                                                                  





                                                                
                                       








                                                                       
                                           


                                 
                                                  





                                     

                                       
     

 

                                                                                                                             
                                            
                            

                                            
                                                   
 
                                       
                
 
                    
 
                                                           
     
                                                             












                                                                    

                                                   




                                                                  

                                                   

                           

                                             



                                                           

                                                                 
                              
                                                                           

                                                                       
                                                                            

                                           
                                               





                                                                            

                                                                        
                              
                                                                           

                                                                              
                                                    


                                                                             
                                                      







                                                                     
                                             

                                            
                                                   
                                                   
                                                          


                                         
                                                    

                                                   
                                                          
                                            
                                                   

                                    
                                           


                                                  


             
 



                                                          
                                                  
 
                                       
 
                    
 
                                                           



                                            
                                                                                   
                
                                                                                

         
 
#include <stdio.h>
#include <string.h>

#include "clif.hpp"
#include "itemdb.hpp"
#include "map.hpp"
#include "trade.hpp"
#include "pc.hpp"
#include "npc.hpp"
#include "battle.hpp"
#include "storage.hpp"
#include "../common/nullpo.hpp"

/*==========================================
 * 取引要請を相手に送る
 *------------------------------------------
 */
void trade_traderequest(struct map_session_data *sd, int target_id)
{
    struct map_session_data *target_sd;

    nullpo_retv(sd);

    if ((target_sd = map_id2sd(target_id)) != NULL)
    {
        if (!battle_config.invite_request_check)
        {
            if (target_sd->party_invite > 0)
            {
                clif_tradestart(sd, 2);    // 相手はPT要請中かGuild要請中
                return;
            }
        }
        if (target_sd->npc_id)
        {
            //Trade fails if you are using an NPC.
            clif_tradestart(sd, 2);
            return;
        }
        if ((target_sd->trade_partner != 0) || (sd->trade_partner != 0))
        {
            trade_tradecancel(sd); //person is in another trade
        }
        else
        {
            if (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
    {
        clif_tradestart(sd, 1);    //character does not exist
    }
}

/*==========================================
 * 取引要請
 *------------------------------------------
 */
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->deal_locked = 0;
            sd->trade_partner = 0;
            target_sd->deal_locked = 0;
            target_sd->trade_partner = 0;
        }
        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_open)
            storage_storageclose(sd);
    }
}

/*==========================================
 * アイテム追加
 *------------------------------------------
 */
void trade_tradeadditem(struct map_session_data *sd, int index, int amount)
{
    struct map_session_data *target_sd;
    struct item_data *id;
    int trade_i;
    int trade_weight = 0;
    int free = 0;
    int c;
    int i;

    nullpo_retv(sd);

    if (((target_sd = map_id2sd(sd->trade_partner)) != NULL)
        && (sd->deal_locked < 1))
    {
        if (index < 2 || index >= MAX_INVENTORY + 2)
        {
            if (index == 0 && amount > 0 && amount <= sd->status.zeny)
            {
                sd->deal_zeny = amount;
                clif_tradeadditem(sd, target_sd, 0, amount);
            }
        }
        else if (amount <= sd->status.inventory[index - 2].amount
                 && amount > 0)
        {
            // determine free slots of receiver
            for (i = 0; i < MAX_INVENTORY; i++)
            {
                if (target_sd->status.inventory[i].nameid == 0
                    && target_sd->inventory_data[i] == NULL)
                    free++;
            }
            for (trade_i = 0; trade_i < 10; trade_i++)
            {
                if (sd->deal_item_amount[trade_i] == 0)
                {
                    // calculate trade weight
                    trade_weight +=
                        sd->inventory_data[index - 2]->weight * amount;

                    // determine if item is a stackable already in receivers inventory, and up free count
                    for (i = 0; i < MAX_INVENTORY; i++)
                    {
                        if (target_sd->status.inventory[i].nameid ==
                            sd->status.inventory[index - 2].nameid
                            && target_sd->inventory_data[i] != NULL)
                        {
                            id = target_sd->inventory_data[i];
                            if (id->type != 4 && id->type != 5
                                && id->type != 7 && id->type != 8)
                            {
                                free++;
                                break;
                            }
                        }
                    }

                    if (target_sd->weight + trade_weight >
                        target_sd->max_weight)
                    {
                        clif_tradeitemok(sd, index, 0, 1); //fail to add item -- the player was over weighted.
                        amount = 0; // [MouseJstr]
                    }
                    else if (free <= 0)
                    {
                        clif_tradeitemok(sd, index, 0, 2); //fail to add item -- no free slots at receiver
                        amount = 0; // peavey
                    }
                    else
                    {
                        for (c = 0; c == trade_i - 1; c++)
                        {       // re-deal exploit protection [Valaris]
                            if (sd->deal_item_index[c] == index)
                            {
                                trade_tradecancel(sd);
                                return;
                            }
                        }
                        pc_unequipinvyitem(sd, index - 2, 0);
                        sd->deal_item_index[trade_i] = index;
                        sd->deal_item_amount[trade_i] += amount;
                        clif_tradeitemok(sd, index, amount, 0);    //success to add item
                        clif_tradeadditem(sd, target_sd, index, amount);
                    }
                    break;
                }
                else
                {
                    // calculate weight for stored deal
                    trade_weight +=
                        sd->inventory_data[sd->deal_item_index[trade_i] -
                                           2]->weight *
                        sd->deal_item_amount[trade_i];
                    // count free stackables in stored deal
                    for (i = 0; i < MAX_INVENTORY; i++)
                    {
                        if (target_sd->status.inventory[i].nameid ==
                            sd->status.
                            inventory[sd->deal_item_index[trade_i] - 2].nameid
                            && target_sd->inventory_data[i] != NULL)
                        {
                            id = target_sd->inventory_data[i];
                            if (id->type != 4 && id->type != 5
                                && id->type != 7 && id->type != 8)
                            {
                                free++;
                                break;
                            }
                        }
                    }
                }
                // used a slot, but might be cancelled out by stackable checks above
                free--;
            }
        }
    }
}

/*==========================================
 * アイテム追加完了(ok押し)
 *------------------------------------------
 */
void trade_tradeok(struct map_session_data *sd)
{
    struct map_session_data *target_sd;
    int trade_i;

    nullpo_retv(sd);

    for (trade_i = 0; trade_i < 10; trade_i++)
    {
        if (sd->deal_item_amount[trade_i] >
            sd->status.inventory[sd->deal_item_index[trade_i] - 2].amount
            || sd->deal_item_amount[trade_i] < 0)
        {
            trade_tradecancel(sd);
            return;
        }

    }

    if ((target_sd = map_id2sd(sd->trade_partner)) != NULL)
    {
        sd->deal_locked = 1;
        clif_tradeitemok(sd, 0, 0, 0);
        clif_tradedeal_lock(sd, 0);
        clif_tradedeal_lock(target_sd, 1);
    }
}

/*==========================================
 * 取引キャンセル
 *------------------------------------------
 */
void trade_tradecancel(struct map_session_data *sd)
{
    struct map_session_data *target_sd;
    int trade_i;

    nullpo_retv(sd);

    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_amount[trade_i] != 0)
            {
                clif_additem(sd, sd->deal_item_index[trade_i] - 2,
                              sd->deal_item_amount[trade_i], 0);
                sd->deal_item_index[trade_i] = 0;
                sd->deal_item_amount[trade_i] = 0;
            }
            if (target_sd->deal_item_amount[trade_i] != 0)
            {
                clif_additem(target_sd,
                              target_sd->deal_item_index[trade_i] - 2,
                              target_sd->deal_item_amount[trade_i], 0);
                target_sd->deal_item_index[trade_i] = 0;
                target_sd->deal_item_amount[trade_i] = 0;
            }
        }
        if (sd->deal_zeny)
        {
            sd->deal_zeny = 0;
            clif_updatestatus(sd, SP_ZENY);
        }
        if (target_sd->deal_zeny)
        {
            clif_updatestatus(target_sd, SP_ZENY);
            target_sd->deal_zeny = 0;
        }
        sd->deal_locked = 0;
        sd->trade_partner = 0;
        target_sd->deal_locked = 0;
        target_sd->trade_partner = 0;
        clif_tradecancelled(sd);
        clif_tradecancelled(target_sd);
    }
}

#define MAP_LOG_PC(sd, fmt, args...) MAP_LOG("PC%d %d:%d,%d " fmt, sd->status.char_id, sd->bl.m, sd->bl.x, sd->bl.y, ## args)

/*==========================================
 * 取引許諾(trade押し)
 *------------------------------------------
 */
void trade_tradecommit(struct map_session_data *sd)
{
    struct map_session_data *target_sd;
    int trade_i;

    nullpo_retv(sd);

    if ((target_sd = map_id2sd(sd->trade_partner)) != NULL)
    {
        MAP_LOG_PC(sd, " TRADECOMMIT WITH %d GIVE %d GET %d",
                    target_sd->status.char_id, sd->deal_zeny,
                    target_sd->deal_zeny);
        if ((sd->deal_locked >= 1) && (target_sd->deal_locked >= 1))
        {                       // both have pressed 'ok'
            if (sd->deal_locked < 2)
            {
                sd->deal_locked = 2;
            }                   // set locked to 2
            if (target_sd->deal_locked == 2)
            {                   // the other one pressed 'trade' too
                if (sd->deal_zeny > sd->status.zeny)
                {
                    sd->deal_zeny = 0;
                    trade_tradecancel(sd);
                    MAP_LOG_PC(sd, " TRADECANCEL");
                    return;
                }
                if (target_sd->deal_zeny > target_sd->status.zeny)
                {
                    target_sd->deal_zeny = 0;
                    trade_tradecancel(sd);
                    MAP_LOG_PC(sd, " TRADECANCEL");
                    return;
                }
                sd->trade_partner = 0;
                target_sd->trade_partner = 0;
                for (trade_i = 0; trade_i < 10; trade_i++)
                {
                    if (sd->deal_item_amount[trade_i] != 0)
                    {
                        int n = sd->deal_item_index[trade_i] - 2;
                        int flag;
                        flag =
                            pc_additem(target_sd, &sd->status.inventory[n],
                                        sd->deal_item_amount[trade_i]);
                        if (flag == 0)
                            pc_delitem(sd, n, sd->deal_item_amount[trade_i],
                                        1);
                        else
                            clif_additem(sd, n,
                                          sd->deal_item_amount[trade_i], 0);
                        sd->deal_item_index[trade_i] = 0;
                        sd->deal_item_amount[trade_i] = 0;
                    }
                    if (target_sd->deal_item_amount[trade_i] != 0)
                    {
                        int n = target_sd->deal_item_index[trade_i] - 2;
                        int flag;
                        flag =
                            pc_additem(sd, &target_sd->status.inventory[n],
                                        target_sd->deal_item_amount[trade_i]);
                        if (flag == 0)
                            pc_delitem(target_sd, n,
                                        target_sd->deal_item_amount[trade_i],
                                        1);
                        else
                            clif_additem(target_sd, n,
                                          target_sd->deal_item_amount
                                          [trade_i], 0);
                        target_sd->deal_item_index[trade_i] = 0;
                        target_sd->deal_item_amount[trade_i] = 0;
                    }
                }
                if (sd->deal_zeny)
                {
                    int deal = sd->deal_zeny;
                    sd->deal_zeny = 0;
                    sd->status.zeny -= deal;
                    clif_updatestatus(sd, SP_ZENY);
                    target_sd->status.zeny += deal;
                    clif_updatestatus(target_sd, SP_ZENY);
                }
                if (target_sd->deal_zeny)
                {
                    int deal = target_sd->deal_zeny;
                    target_sd->deal_zeny = 0;
                    target_sd->status.zeny -= deal;
                    clif_updatestatus(target_sd, SP_ZENY);
                    sd->status.zeny += deal;
                    clif_updatestatus(sd, SP_ZENY);
                }
                sd->deal_locked = 0;
                target_sd->deal_locked = 0;
                clif_tradecompleted(sd, 0);
                clif_tradecompleted(target_sd, 0);
                MAP_LOG_PC(sd, " TRADEOK");
            }
        }
    }
}

// This is called when a char's zeny is changed
// This helps prevent money duplication and other problems
// [Jaxad0127]
void trade_verifyzeny(struct map_session_data *sd)
{
    struct map_session_data *target_sd;

    nullpo_retv(sd);

    if ((target_sd = map_id2sd(sd->trade_partner)) != NULL)
    {
        if (sd->deal_zeny > sd->status.zeny)
        {
            if (sd->deal_locked < 1)
                trade_tradeadditem(sd, 0, sd->status.zeny);    // Fix money ammount
            else
                trade_tradecancel(sd); // Or cancel the trade if we can't fix it
        }
    }
}