File: faction_price_rules_test.cpp

package info (click to toggle)
cataclysm-dda 0.H-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 710,808 kB
  • sloc: cpp: 524,019; python: 11,580; sh: 1,228; makefile: 1,169; xml: 507; javascript: 150; sql: 56; exp: 41; perl: 37
file content (160 lines) | stat: -rw-r--r-- 7,169 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "avatar.h"
#include "cata_catch.h"
#include "itype.h"
#include "npc.h"
#include "npctrade.h"
#include "player_helpers.h"

static const skill_id skill_speech( "speech" );

TEST_CASE( "basic_price_check", "[npc][trade]" )
{
    using namespace npc_trading;
    clear_avatar();
    avatar &u = get_avatar();
    npc &guy = spawn_npc( { 50, 50 }, "test_npc_trader" );
    clear_character( guy );

    bool const u_buy = GENERATE( true, false );
    CAPTURE( u_buy );

    Character *seller = nullptr;
    Character *buyer = nullptr;
    if( u_buy ) {
        buyer = &u;
        seller = &guy;
    } else {
        buyer = &guy;
        seller = &u;
    }

    item m4( "modular_m4_carbine" );
    item mag( m4.magazine_default() );
    int const ammo_amount = mag.remaining_ammo_capacity();
    item ammo( mag.ammo_default(), calendar::turn, ammo_amount );
    item bomba( "test_bomba" );
    REQUIRE( bomba.type->price_post != units::from_cent( 0 ) );
    item backpack( "debug_backpack" );

    int const price_separate = adjusted_price( &m4, 1, *buyer, *seller ) +
                               adjusted_price( &mag, 1, *buyer, *seller ) +
                               adjusted_price( &ammo, ammo_amount, *buyer, *seller ) +
                               adjusted_price( &backpack, 1, *buyer, *seller );

    mag.put_in( ammo, pocket_type::MAGAZINE );
    m4.put_in( mag, pocket_type::MAGAZINE_WELL );
    backpack.put_in( m4, pocket_type::CONTAINER );
    if( !u_buy ) {
        REQUIRE( !guy.wants_to_buy( bomba ) );
        backpack.put_in( bomba, pocket_type::CONTAINER );
    }

    trade_selector::entry_t bck_entry{
        item_location{ map_cursor( tripoint_zero ), &backpack }, 1 };

    int const price_combined = trading_price( *buyer, *seller, bck_entry );

    CHECK( price_separate == Approx( price_combined ).margin( 1 ) );
}

TEST_CASE( "faction_price_rules", "[npc][factions][trade]" )
{
    clear_avatar();
    npc &guy = spawn_npc( { 50, 50 }, "test_npc_trader" );
    faction const &fac = *guy.my_fac;

    WHEN( "item has no rules (default adjustment)" ) {
        item const hammer( "hammer" );
        clear_character( guy );
        REQUIRE( npc_trading::adjusted_price( &hammer, 1, get_avatar(), guy ) ==
                 Approx( units::to_cent( hammer.type->price_post ) * 1.25 ).margin( 1 ) );
        REQUIRE( npc_trading::adjusted_price( &hammer, 1, guy, get_avatar() ) ==
                 Approx( units::to_cent( hammer.type->price_post ) * 0.75 ).margin( 1 ) );
    }

    WHEN( "item is main currency (implicit price rule)" ) {
        guy.int_max = 1000;
        guy.set_skill_level( skill_speech, 10 );
        item const fmcnote( "FMCNote" );
        REQUIRE( npc_trading::adjusted_price( &fmcnote, 1, get_avatar(), guy ) ==
                 units::to_cent( fmcnote.type->price_post ) );
        REQUIRE( npc_trading::adjusted_price( &fmcnote, 1, guy, get_avatar() ) ==
                 units::to_cent( fmcnote.type->price_post ) );
    }

    item const pants_fur( "test_pants_fur" );
    WHEN( "item is secondary currency (fixed_adj=0)" ) {
        get_avatar().int_max = 1000;
        get_avatar().set_skill_level( skill_speech, 10 );
        REQUIRE( npc_trading::adjusted_price( &pants_fur, 1, get_avatar(), guy ) ==
                 units::to_cent( pants_fur.type->price_post ) );
        REQUIRE( npc_trading::adjusted_price( &pants_fur, 1, guy, get_avatar() ) ==
                 units::to_cent( pants_fur.type->price_post ) );
    }
    WHEN( "faction desperately needs this item (premium=25)" ) {
        item const multitool( "test_multitool" );
        REQUIRE( fac.get_price_rules( multitool, guy )->premium == 25 );
        REQUIRE( fac.get_price_rules( multitool, guy )->markup == 1.1 );
        THEN( "NPC selling to avatar includes premium and markup" ) {
            REQUIRE( npc_trading::adjusted_price( &multitool, 1, get_avatar(), guy ) ==
                     Approx( units::to_cent( multitool.type->price_post ) * 25 * 1.1 ).margin( 1 ) );
        }
        THEN( "avatar selling to NPC includes only premium" ) {
            REQUIRE( npc_trading::adjusted_price( &multitool, 1, guy, get_avatar() ) ==
                     Approx( units::to_cent( multitool.type->price_post ) * 25 ).margin( 1 ) );
        }
    }
    WHEN( "faction has a custom price for this item (price=10000000)" ) {
        item const log = GENERATE( item( "log" ), item( "scrap" ) );
        clear_character( guy );
        double price = *fac.get_price_rules( log, guy )->price;
        REQUIRE( price == 10000000 );
        if( log.count_by_charges() ) {
            price /= log.type->stack_size;
        }
        REQUIRE( npc_trading::adjusted_price( &log, 1, get_avatar(), guy ) ==
                 Approx( price * 1.25 ).margin( 1 ) );
        REQUIRE( npc_trading::adjusted_price( &log, 1, guy, get_avatar() ) ==
                 Approx( price * 0.75 ).margin( 1 ) );
    }
    item const carafe( "test_nuclear_carafe" );
    WHEN( "condition for price rules not satisfied" ) {
        clear_character( guy );
        REQUIRE( fac.get_price_rules( carafe, guy ) == nullptr );
        REQUIRE( npc_trading::adjusted_price( &carafe, 1, get_avatar(), guy ) ==
                 Approx( units::to_cent( carafe.type->price_post ) * 1.25 ).margin( 1 ) );
    }
    WHEN( "condition for price rules satisfied" ) {
        guy.set_value( "npctalk_var_bool_allnighter_thirsty", "yes" );
        REQUIRE( fac.get_price_rules( carafe, guy )->markup == 2.0 );
        THEN( "NPC selling to avatar includes markup and positive fixed adjustment" ) {
            REQUIRE( npc_trading::adjusted_price( &carafe, 1, get_avatar(), guy ) ==
                     Approx( units::to_cent( carafe.type->price_post ) * 2.0 * 1.1 ).margin( 1 ) );
        }
        THEN( "avatar selling to NPC includes only negative fixed adjustment" ) {
            REQUIRE( npc_trading::adjusted_price( &carafe, 1, guy, get_avatar() ) ==
                     Approx( units::to_cent( carafe.type->price_post ) * 0.9 ).margin( 1 ) );
        }
    }
    WHEN( "personal price rule overrides faction rule" ) {
        double const fmarkup = fac.get_price_rules( pants_fur, guy )->markup;
        REQUIRE( guy.get_price_rules( pants_fur )->markup == fmarkup );
        REQUIRE( fmarkup != - 100 );
        guy.set_value( "npctalk_var_bool_preference_vegan", "yes" );
        REQUIRE( guy.get_price_rules( pants_fur )->markup == -100 );
    }
    WHEN( "price rule affects magazine contents" ) {
        clear_character( guy );
        item const battery( "battery" );
        item tbd( "test_battery_disposable" );
        int const battery_price = *guy.get_price_rules( battery )->price;
        REQUIRE( battery.price( true ) != battery_price );
        trade_selector::entry_t tbd_entry{
            item_location{ map_cursor( tripoint_zero ), &tbd }, 1 };

        REQUIRE( npc_trading::trading_price( get_avatar(), guy, tbd_entry ) ==
                 Approx( units::to_cent( tbd.type->price_post ) * 1.25 +
                         battery_price * 1.25 * tbd.ammo_remaining( nullptr ) / battery.type->stack_size )
                 .margin( 1 ) );
    }
}