naev 0.11.5
land_trade.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <assert.h>
11#include <math.h>
12#include <stdio.h>
13#include <stdlib.h>
14
15#include "naev.h"
18#include "land_trade.h"
19
20#include "array.h"
21#include "commodity.h"
22#include "dialogue.h"
23#include "economy.h"
24#include "hook.h"
25#include "land_shipyard.h"
26#include "log.h"
27#include "map_find.h"
28#include "ndata.h"
29#include "nstring.h"
30#include "player.h"
31#include "player_fleet.h"
32#include "space.h"
33#include "tk/toolkit_priv.h"
34#include "toolkit.h"
35
36/*
37 * Quantity to buy on one click
38*/
39static int commodity_mod = 10;
40static Commodity **commodity_list = NULL;
41
42static void commodity_exchange_modifiers( unsigned int wid )
43{
44 int q = commodity_getMod();
45 if (q != commodity_mod) {
46 char buf[STRMAX_SHORT];
47 commodity_mod = q;
48 snprintf( buf, sizeof(buf), _("Buy (%d %s)"), q, UNIT_MASS );
49 window_buttonCaption( wid, "btnCommodityBuy", buf );
50 snprintf( buf, sizeof(buf), _("Sell (%d %s)"), q, UNIT_MASS );
51 window_buttonCaption( wid, "btnCommoditySell", buf );
53 }
54}
55
56static int commodity_exchange_events( unsigned int wid, SDL_Event *evt )
57{
58 if ((evt->type==SDL_KEYDOWN) || (evt->type==SDL_KEYUP))
59 commodity_exchange_modifiers( wid );
60 return 0;
61}
62
66void commodity_exchange_open( unsigned int wid )
67{
68 int j, ngoods;
69 ImageArrayCell *cgoods;
70 int w, h, iw, ih, dw, bw, titleHeight, infoHeight;
71 char buf[STRMAX_SHORT];
72 size_t l = 0;
73 int iconsize;
74 int q = commodity_getMod();
75
76 /* Mark as generated. */
77 land_tabGenerate(LAND_WINDOW_COMMODITY);
78
79 /* Get window dimensions. */
80 window_dimWindow( wid, &w, &h );
81
82 /* Calculate image array dimensions. */
83 /* Window size minus right column size minus space on left and right */
84 iw = 565 + (w - LAND_WIDTH);
85 ih = h - 60;
86 dw = w - iw - 60;
87
88 /* buttons */
89 bw = (dw - 40) / 3;
90 snprintf( buf, sizeof(buf), _("Buy (%d %s)"), q, UNIT_MASS );
91 window_addButtonKey( wid, 40 + iw, 20, bw, LAND_BUTTON_HEIGHT,
92 "btnCommodityBuy", buf, commodity_buy, SDLK_b );
93 snprintf( buf, sizeof(buf), _("Sell (%d %s)"), q, UNIT_MASS );
94 window_addButtonKey( wid, 60 + iw + bw, 20, bw, LAND_BUTTON_HEIGHT,
95 "btnCommoditySell", buf, commodity_sell, SDLK_s );
96 window_addButtonKey( wid, 80 + iw + 2*bw, 20, bw, LAND_BUTTON_HEIGHT,
97 "btnCommodityClose", _("Take Off"), land_buttonTakeoff, SDLK_t );
98
99 /* handle multipliers. */
100 window_handleEvents( wid, commodity_exchange_events );
101 window_setOnFocus( wid, commodity_exchange_modifiers );
102
103 /* store gfx */
104 window_addRect( wid, -20, -40, 192, 192, "rctStore", &cBlack, 0 );
105 window_addImage( wid, -20, -40, 192, 192, "imgStore", NULL, 1 );
106
107 /* text */
108 titleHeight = gl_printHeightRaw(&gl_defFont, LAND_BUTTON_WIDTH+80, _("None"));
109 window_addText( wid, 40 + iw, -40, dw, titleHeight, 0,
110 "txtName", &gl_defFont, NULL, _("None") );
111
112 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", (player.fleet_capacity > 0) ? _("Your fleet has:") : _("You have:") );
113 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", (player.fleet_capacity > 0) ? _("Free Space (fleet):") : _("Free Space:") );
114 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Money:") );
115 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Market Price:") );
116 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Average price here:") );
117 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Average galactic price:") );
118 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Purchased for:") );
119 infoHeight = gl_printHeightRaw( &gl_smallFont, LAND_BUTTON_WIDTH+80, buf );
120 window_addText( wid, 40 + iw, -60 - titleHeight, 200, infoHeight, 0,
121 "txtSInfo", &gl_smallFont, &cFontGrey, buf );
122 window_addText( wid, 40 + iw + 224, -60 - titleHeight,
123 dw - (200 + 20+192), infoHeight, 0,
124 "txtDInfo", &gl_smallFont, NULL, NULL );
125
126 window_addText( wid, 40 + iw, -80-titleHeight-infoHeight,
127 dw, 100, 0, "txtDRef", &gl_smallFont, NULL, NULL );
128 window_addText( wid, 40 + iw, MIN(-80-titleHeight-infoHeight, -192-60),
129 dw, h - (80+titleHeight+infoHeight) - (40+LAND_BUTTON_HEIGHT), 0,
130 "txtDesc", &gl_smallFont, NULL, NULL );
131
132 /* goods list */
133 ngoods = array_size( land_spob->commodities );
134
135 /* Count always sellable goods. */
137 for (int i=0; i<array_size(pclist); i++) {
138 PilotCommodity *pc = &pclist[i];
139 if (pc->id > 0) /* Ignore mission stuff. */
140 continue;
141 if (!commodity_isFlag(pc->commodity, COMMODITY_FLAG_ALWAYS_CAN_SELL))
142 continue;
143 ngoods++;
144 }
145 if (ngoods > 0) {
146 cgoods = calloc( ngoods, sizeof(ImageArrayCell) );
147 if (commodity_list != NULL)
148 free(commodity_list);
149 commodity_list = malloc( ngoods*sizeof(Commodity*) );
150 j = 0;
151
152 /* First add special sellable. */
153 for (int i=0; i<array_size(pclist); i++) {
154 PilotCommodity *pc = &pclist[i];
155 if (pc->id > 0) /* Ignore mission stuff. */
156 continue;
157 if (!commodity_isFlag(pc->commodity, COMMODITY_FLAG_ALWAYS_CAN_SELL))
158 continue;
159 cgoods[j].image = gl_dupTexture(pc->commodity->gfx_store);
160 cgoods[j].caption = strdup( _(pc->commodity->name) );
161 commodity_list[j] = (Commodity*) pc->commodity;
162 j++;
163 }
164
165 /* Then add default. */
166 for (int i=0; i<array_size(land_spob->commodities); i++) {
167 cgoods[j].image = gl_dupTexture(land_spob->commodities[i]->gfx_store);
168 cgoods[j].caption = strdup( _(land_spob->commodities[i]->name) );
169 commodity_list[j] = land_spob->commodities[i];
170 j++;
171 }
172 }
173 else {
174 ngoods = 1;
175 cgoods = calloc( ngoods, sizeof(ImageArrayCell) );
176 cgoods[0].image = NULL;
177 cgoods[0].caption = strdup(_("None"));
178 }
179 array_free(pclist);
180
181 /* set up the goods to buy/sell */
182 iconsize = 128;
183 if (!conf.big_icons) {
184 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) < ngoods)
185 iconsize = 96;
186 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) < ngoods)
187 iconsize = 64;
188 }
189 window_addImageArray( wid, 20, 20,
190 iw, ih, "iarTrade", iconsize, iconsize,
192
193 /* Set default keyboard focuse to the list */
194 window_setFocus( wid , "iarTrade" );
195}
196
197void commodity_exchange_cleanup (void)
198{
199 free(commodity_list);
200 commodity_list = NULL;
201}
202
208void commodity_update( unsigned int wid, const char *str )
209{
210 (void) str;
211 char buf[STRMAX];
212 char buf_purchase_price[ECON_CRED_STRLEN], buf_credits[ECON_CRED_STRLEN];
213 size_t l = 0;
214 const Commodity *com;
215 credits_t mean,globalmean;
216 double std, globalstd;
217 char buf_mean[ECON_CRED_STRLEN], buf_globalmean[ECON_CRED_STRLEN];
218 char buf_std[ECON_CRED_STRLEN], buf_globalstd[ECON_CRED_STRLEN];
219 char buf_local_price[ECON_CRED_STRLEN];
220 char buf_tonnes_owned[ECON_MASS_STRLEN], buf_tonnes_free[ECON_MASS_STRLEN];
221 int owned, cargo_free;
222 int i = toolkit_getImageArrayPos( wid, "iarTrade" );
223 credits2str( buf_credits, player.p->credits, 2 );
224 cargo_free = pfleet_cargoFree();
225 tonnes2str( buf_tonnes_free, cargo_free );
226
227 if (i < 0 || array_size(land_spob->commodities) == 0) {
228 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", _("N/A") );
229 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_tonnes_free );
230 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_credits );
231 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
232 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("N/A") );
233 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("N/A") );
234 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("N/A") );
235 window_modifyText( wid, "txtDInfo", buf );
236 window_modifyText( wid, "txtDesc", _("No commodities available.") );
237 window_disableButton( wid, "btnCommodityBuy" );
238 window_disableButton( wid, "btnCommoditySell" );
239 return;
240 }
241 com = commodity_list[i];
242
243 /* modify image */
244 window_modifyImage( wid, "imgStore", com->gfx_store, 192, 192 );
245
246 spob_averageSpobPrice( land_spob, com, &mean, &std);
247 credits2str( buf_mean, mean, -1 );
248 snprintf( buf_std, sizeof(buf_std), _("%.1f ¤"), std ); /* TODO credit2str could learn to do this... */
249 economy_getAveragePrice( com, &globalmean, &globalstd );
250 credits2str( buf_globalmean, globalmean, -1 );
251 snprintf( buf_globalstd, sizeof(buf_globalstd), _("%.1f ¤"), globalstd ); /* TODO credit2str could learn to do this... */
252 /* modify text */
253 buf_purchase_price[0]='\0';
254 owned = pfleet_cargoOwned( com );
255 if (owned > 0)
256 credits2str( buf_purchase_price, com->lastPurchasePrice, -1 );
257 credits2str( buf_local_price, spob_commodityPrice( land_spob, com ), -1 );
258 tonnes2str( buf_tonnes_owned, owned );
259 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", buf_tonnes_owned );
260 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_tonnes_free );
261 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_credits );
262 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
263 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s/t"), buf_local_price );
264 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
265 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s/t ± %s/t"), buf_mean, buf_std );
266 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
267 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s/t ± %s/t"), buf_globalmean, buf_globalstd );
268 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_purchase_price );
269
270 window_modifyText( wid, "txtDInfo", buf );
271 window_modifyText( wid, "txtName", _(com->name) );
272 window_modifyText( wid, "txtDesc", _(com->description) );
273
274 /* Add relative price. */
275 l = 0;
276 if (commodity_isFlag(com, COMMODITY_FLAG_PRICE_CONSTANT)) {
277 l += scnprintf( &buf[l], sizeof(buf)-l, _("Price is constant.") );
278 window_modifyText( wid, "txtDRef", buf );
279 }
280 else if (com->price_ref != NULL) {
281 char c = '0';
282 if (com->price_mod > 1.)
283 c = 'g';
284 else if (com->price_mod < 1.)
285 c = 'r';
286 l += scnprintf( &buf[l], sizeof(buf)-l, _("Price is based on #%c%.0f%%#0 of the price of #o%s#0."), c, com->price_mod*100., _(com->price_ref) );
287 window_modifyText( wid, "txtDRef", buf );
288 }
289 else
290 window_modifyText( wid, "txtDRef", NULL );
291
292 /* Button enabling/disabling */
293 if (commodity_canBuy( com ))
294 window_enableButton( wid, "btnCommodityBuy" );
295 else
296 window_disableButtonSoft( wid, "btnCommodityBuy" );
297
298 if (commodity_canSell( com ))
299 window_enableButton( wid, "btnCommoditySell" );
300 else
301 window_disableButtonSoft( wid, "btnCommoditySell" );
302}
303
308{
309 int failure, incommodities;
310 unsigned int q, price;
311 char buf[ECON_CRED_STRLEN];
312
314 failure = 0;
315 q = commodity_getMod();
316 price = spob_commodityPrice( land_spob, com ) * q;
317
318 if (!player_hasCredits( price )) {
319 credits2str( buf, price - player.p->credits, 2 );
320 land_errDialogueBuild(_("You need %s more."), buf );
321 failure = 1;
322 }
323 if (pfleet_cargoFree() <= 0) {
324 land_errDialogueBuild(_("No cargo space available!"));
325 failure = 1;
326 }
327
328 incommodities = 0;
329 for (int i=0; i<array_size(land_spob->commodities); i++) {
330 if (land_spob->commodities[i] == com) {
331 incommodities = 1;
332 break;
333 }
334 }
335 if (!incommodities) {
336 land_errDialogueBuild(_("%s is not sold here!"), _(com->name));
337 failure = 1;
338 }
339
340 return !failure;
341}
342
347{
348 int failure = 0;
350 if (pfleet_cargoOwned( com ) ==0) {
351 land_errDialogueBuild(_("You can't sell something you don't have!"));
352 failure = 1;
353 }
354 return !failure;
355}
356
362void commodity_buy( unsigned int wid, const char *str )
363{
364 (void)str;
365 int i;
366 Commodity *com;
367 unsigned int q;
368 credits_t price;
369 HookParam hparam[3];
370
371 /* Get selected. */
372 q = commodity_getMod();
373 i = toolkit_getImageArrayPos( wid, "iarTrade" );
374 com = commodity_list[i];
375 price = spob_commodityPrice( land_spob, com );
376
377 /* Check stuff. */
378 if (!commodity_canBuy( com )) {
380 return;
381 }
382
383 /* Make the buy. */
384 q = pfleet_cargoAdd( com, q );
385 com->lastPurchasePrice = price; /* To show the player how much they paid for it */
386 price *= q;
387 player_modCredits( -price );
388 commodity_update(wid, NULL);
389
390 /* Run hooks. */
391 hparam[0].type = HOOK_PARAM_COMMODITY;
392 hparam[0].u.commodity = com;
393 hparam[1].type = HOOK_PARAM_NUMBER;
394 hparam[1].u.num = q;
395 hparam[2].type = HOOK_PARAM_SENTINEL;
396 hooks_runParam( "comm_buy", hparam );
397 land_needsTakeoff( 1 );
398}
399
405void commodity_sell( unsigned int wid, const char *str )
406{
407 (void) str;
408 int i;
409 Commodity *com;
410 unsigned int q;
411 credits_t price;
412 HookParam hparam[3];
413
414 /* Get parameters. */
415 q = commodity_getMod();
416 i = toolkit_getImageArrayPos( wid, "iarTrade" );
417 com = commodity_list[i];
418 price = spob_commodityPrice( land_spob, com );
419
420 /* Check stuff. */
421 if (!commodity_canSell( com )) {
423 return;
424 }
425
426 /* Remove commodity. */
427 q = pfleet_cargoRm( com, q, 0 );
428 price = price * (credits_t)q;
429 player_modCredits( price );
430 if (pfleet_cargoOwned( com ) == 0) /* None left, set purchase price to zero, in case missions add cargo. */
431 com->lastPurchasePrice = 0;
432 commodity_update(wid, NULL);
433
434 /* Run hooks. */
435 hparam[0].type = HOOK_PARAM_COMMODITY;
436 hparam[0].u.commodity = com;
437 hparam[1].type = HOOK_PARAM_NUMBER;
438 hparam[1].u.num = q;
439 hparam[2].type = HOOK_PARAM_SENTINEL;
440 hooks_runParam( "comm_sell", hparam );
441 land_needsTakeoff( 1 );
442}
443
449{
450 SDL_Keymod mods = SDL_GetModState();
451 int q = 10;
452 if (mods & (KMOD_LCTRL | KMOD_RCTRL))
453 q *= 5;
454 if (mods & (KMOD_LSHIFT | KMOD_RSHIFT))
455 q *= 10;
456 if (mods & (KMOD_LALT | KMOD_RALT))
457 q = 1;
458
459 return q;
460}
461
470void commodity_renderMod( double bx, double by, double w, double h, void *data )
471{
472 (void) data;
473 (void) h;
474 int q;
475 char buf[8];
476
477 q = commodity_getMod();
478 if (q != commodity_mod) {
479 //commodity_update( land_getWid(LAND_WINDOW_COMMODITY), NULL );
480 commodity_mod = q;
481 }
482 snprintf( buf, sizeof(buf), "%dx", q );
483 gl_printMidRaw( &gl_smallFont, w, bx, by, &cFontWhite, -1, buf );
484}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
void credits2str(char *str, credits_t credits, int decimals)
Converts credits to a usable string for displaying.
Definition commodity.c:59
void tonnes2str(char *str, int tonnes)
Converts tonnes to a usable string for displaying.
Definition commodity.c:108
int economy_getAveragePrice(const Commodity *com, credits_t *mean, double *std)
Gets the average price of a good as seen by the player (anywhere).
Definition economy.c:242
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition font.c:1027
glFont gl_smallFont
Definition font.c:154
glFont gl_defFont
Definition font.c:153
int gl_printMidRaw(const glFont *ft_font, int width, double x, double y, const glColour *c, double outlineR, const char *text)
Displays text centered in position and width.
Definition font.c:788
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:979
void land_errDialogueBuild(const char *fmt,...)
Generates error dialogues used by several landing tabs.
Definition land.c:208
Spob * land_spob
Definition land.c:83
void land_errClear(void)
Clear error dialogues.
Definition land.c:199
void land_buttonTakeoff(unsigned int wid, const char *unused)
Wrapper for takeoff mission button.
Definition land.c:851
int land_errDisplay(void)
Displays an error if applicable.
Definition land.c:228
int commodity_canBuy(const Commodity *com)
Checks to see if the player can buy a commodity.
Definition land_trade.c:307
int commodity_getMod(void)
Gets the current modifier status.
Definition land_trade.c:448
void commodity_exchange_open(unsigned int wid)
Opens the local market window.
Definition land_trade.c:66
void commodity_sell(unsigned int wid, const char *str)
Attempts to sell a commodity.
Definition land_trade.c:405
void commodity_renderMod(double bx, double by, double w, double h, void *data)
Renders the commodity buying modifier.
Definition land_trade.c:470
void commodity_buy(unsigned int wid, const char *str)
Buys the selected commodity.
Definition land_trade.c:362
int commodity_canSell(const Commodity *com)
Checks to see if a player can sell a commodity.
Definition land_trade.c:346
void commodity_update(unsigned int wid, const char *str)
Updates the commodity window.
Definition land_trade.c:208
static int commodity_mod
Definition land_trade.c:39
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:40
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:99
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:917
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition player.c:975
Player_t player
Definition player.c:74
int player_hasCredits(credits_t amount)
Checks to see if the player has enough credits.
Definition player.c:964
PilotCommodity * pfleet_cargoList(void)
Gets a list of all the cargo in the fleet.
int pfleet_cargoFree(void)
Gets the total amount of free cargo space in the player's fleet.
int pfleet_cargoOwned(const Commodity *com)
Gets the total amount of a commodity type owned by the player's fleet.
int pfleet_cargoAdd(const Commodity *com, int q)
Adds some cargo to the player's fleet.
int pfleet_cargoRm(const Commodity *com, int q, int jet)
Removes some cargo from the player's fleet.
static const double c[]
Definition rng.c:264
int spob_averageSpobPrice(const Spob *p, const Commodity *c, credits_t *mean, double *std)
Gets the average price of a commodity at a spob that has been seen so far.
Definition space.c:316
credits_t spob_commodityPrice(const Spob *p, const Commodity *c)
Gets the price of a commodity at a spob.
Definition space.c:276
Represents a commodity.
Definition commodity.h:43
char * description
Definition commodity.h:45
glTexture * gfx_store
Definition commodity.h:53
char * name
Definition commodity.h:44
credits_t lastPurchasePrice
Definition commodity.h:57
double price_mod
Definition commodity.h:50
char * price_ref
Definition commodity.h:49
The actual hook parameter.
Definition hook.h:38
HookParamType type
Definition hook.h:39
Commodity * commodity
Definition hook.h:47
union HookParam::@25 u
double num
Definition hook.h:41
Stores a pilot commodity.
Definition pilot.h:179
const Commodity * commodity
Definition pilot.h:180
unsigned int id
Definition pilot.h:182
credits_t credits
Definition pilot.h:325
int big_icons
Definition conf.h:125
Pilot * p
Definition player.h:101
int fleet_capacity
Definition player.h:126
Commodity ** commodities
Definition space.h:116
void window_setOnFocus(unsigned int wid, void(*focus)(unsigned int))
Sets the focus function of the window.
Definition toolkit.c:888
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2471
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:371
void toolkit_rerender(void)
Marks the toolkit for needing a full rerender.
Definition toolkit.c:1661
void window_handleEvents(unsigned int wid, int(*eventhandler)(unsigned int, SDL_Event *))
Sets the event handler for the window.
Definition toolkit.c:977