1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 #include "MoneyEffect.h"
10 
11 #include "../OpenRCT2.h"
12 #include "../drawing/Drawing.h"
13 #include "../interface/Viewport.h"
14 #include "../interface/Window.h"
15 #include "../localisation/Localisation.h"
16 #include "../network/network.h"
17 #include "Entity.h"
18 #include "Map.h"
19 #include "Sprite.h"
20 
21 static constexpr const CoordsXY _moneyEffectMoveOffset[] = {
22     { 1, -1 },
23     { 1, 1 },
24     { -1, 1 },
25     { -1, -1 },
26 };
27 
Is() const28 template<> bool EntityBase::Is<MoneyEffect>() const
29 {
30     return Type == EntityType::MoneyEffect;
31 }
32 
33 /**
34  *
35  *  rct2: 0x0067351F
36  */
CreateAt(money64 value,const CoordsXYZ & effectPos,bool vertical)37 void MoneyEffect::CreateAt(money64 value, const CoordsXYZ& effectPos, bool vertical)
38 {
39     if (value == MONEY(0, 00))
40         return;
41 
42     MoneyEffect* moneyEffect = CreateEntity<MoneyEffect>();
43     if (moneyEffect == nullptr)
44         return;
45 
46     moneyEffect->Value = value;
47     moneyEffect->Vertical = (vertical ? 1 : 0);
48     moneyEffect->sprite_width = 64;
49     moneyEffect->sprite_height_negative = 20;
50     moneyEffect->sprite_height_positive = 30;
51     moneyEffect->MoveTo(effectPos);
52     moneyEffect->NumMovements = 0;
53     moneyEffect->MoveDelay = 0;
54 
55     int16_t offsetX = 0;
56     if (!gOpenRCT2NoGraphics)
57     {
58         auto [stringId, newValue] = moneyEffect->GetStringId();
59         char buffer[128];
60         format_string(buffer, 128, stringId, &newValue);
61         offsetX = -(gfx_get_string_width(buffer, FontSpriteBase::MEDIUM) / 2);
62     }
63     moneyEffect->OffsetX = offsetX;
64     moneyEffect->Wiggle = 0;
65 }
66 
67 /**
68  *
69  *  rct2: 0x0069C5D0
70  */
Create(money64 value,const CoordsXYZ & loc)71 void MoneyEffect::Create(money64 value, const CoordsXYZ& loc)
72 {
73     auto offsetLoc = loc;
74     if (loc.IsNull())
75     {
76         // If game actions return no valid location of the action we can not use the screen
77         // coordinates as every client will have different ones.
78         if (network_get_mode() != NETWORK_MODE_NONE)
79         {
80             log_warning("Attempted to create money effect without a valid location in multiplayer");
81             return;
82         }
83 
84         rct_window* mainWindow = window_get_main();
85         if (mainWindow == nullptr)
86             return;
87 
88         rct_viewport* mainViewport = window_get_viewport(mainWindow);
89         auto mapPositionXY = screen_get_map_xy(
90             { mainViewport->pos.x + (mainViewport->width / 2), mainViewport->pos.y + (mainViewport->height / 2) }, nullptr);
91         if (!mapPositionXY.has_value())
92             return;
93 
94         offsetLoc = { mapPositionXY.value(), tile_element_height(*mapPositionXY) };
95     }
96     offsetLoc.z += 10;
97     CreateAt(-value, offsetLoc, false);
98 }
99 
100 /**
101  *
102  *  rct2: 0x00673232
103  */
Update()104 void MoneyEffect::Update()
105 {
106     Wiggle++;
107     if (Wiggle >= 22)
108     {
109         Wiggle = 0;
110     }
111 
112     MoveDelay++;
113     if (MoveDelay < 2)
114     {
115         return;
116     }
117 
118     int32_t newX = x;
119     int32_t newY = y;
120     int32_t newZ = z;
121     MoveDelay = 0;
122 
123     if (Vertical)
124     {
125         newZ += 1;
126     }
127     newY += _moneyEffectMoveOffset[get_current_rotation()].y;
128     newX += _moneyEffectMoveOffset[get_current_rotation()].x;
129 
130     MoveTo({ newX, newY, newZ });
131 
132     NumMovements++;
133     if (NumMovements < 55)
134     {
135         return;
136     }
137 
138     sprite_remove(this);
139 }
140 
GetStringId() const141 std::pair<rct_string_id, money64> MoneyEffect::GetStringId() const
142 {
143     rct_string_id spentStringId = Vertical ? STR_MONEY_EFFECT_SPEND_HIGHP : STR_MONEY_EFFECT_SPEND;
144     rct_string_id receiveStringId = Vertical ? STR_MONEY_EFFECT_RECEIVE_HIGHP : STR_MONEY_EFFECT_RECEIVE;
145     rct_string_id stringId = receiveStringId;
146     money64 outValue = Value;
147     if (Value < 0)
148     {
149         outValue *= -1;
150         stringId = spentStringId;
151     }
152 
153     return std::make_pair(stringId, outValue);
154 }
155