naev 0.10.4
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
45void commodity_exchange_open( unsigned int wid )
46{
47 int j, ngoods;
48 ImageArrayCell *cgoods;
49 int w, h, iw, ih, dw, bw, titleHeight, infoHeight;
50 char buf[STRMAX_SHORT];
51 size_t l = 0;
52 int iconsize;
53
54 /* Mark as generated. */
55 land_tabGenerate(LAND_WINDOW_COMMODITY);
56
57 /* Get window dimensions. */
58 window_dimWindow( wid, &w, &h );
59
60 /* Calculate image array dimensions. */
61 /* Window size minus right column size minus space on left and right */
62 iw = 565 + (w - LAND_WIDTH);
63 ih = h - 60;
64 dw = w - iw - 60;
65
66 /* buttons */
67 bw = (dw - 40) / 3;
68 window_addButtonKey( wid, 40 + iw, 20, bw, LAND_BUTTON_HEIGHT,
69 "btnCommodityBuy", _("Buy"), commodity_buy, SDLK_b );
70 window_addButtonKey( wid, 60 + iw + bw, 20, bw, LAND_BUTTON_HEIGHT,
71 "btnCommoditySell", _("Sell"), commodity_sell, SDLK_s );
72 window_addButtonKey( wid, 80 + iw + 2*bw, 20, bw, LAND_BUTTON_HEIGHT,
73 "btnCommodityClose", _("Take Off"), land_buttonTakeoff, SDLK_t );
74
75 /* cust draws the modifier : # of tons one click buys or sells */
76 window_addCust( wid, 40 + iw, 40 + LAND_BUTTON_HEIGHT, 2*bw + 20,
77 gl_smallFont.h + 6, "cstMod", 0, commodity_renderMod, NULL, NULL, NULL, NULL );
78 window_canFocusWidget( wid, "cstMod", 0 );
79
80 /* store gfx */
81 window_addRect( wid, -20, -40, 192, 192, "rctStore", &cBlack, 0 );
82 window_addImage( wid, -20, -40, 192, 192, "imgStore", NULL, 1 );
83
84 /* text */
85 titleHeight = gl_printHeightRaw(&gl_defFont, LAND_BUTTON_WIDTH+80, _("None"));
86 window_addText( wid, 40 + iw, -40, dw, titleHeight, 0,
87 "txtName", &gl_defFont, NULL, _("None") );
88
89 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", (player.fleet_capacity > 0) ? _("Your fleet has:") : _("You have:") );
90 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", (player.fleet_capacity > 0) ? _("Free Space (fleet):") : _("Free Space:") );
91 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Money:") );
92 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Market Price:") );
93 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Average price here:") );
94 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Average galactic price:") );
95 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Purchased for:") );
96 infoHeight = gl_printHeightRaw( &gl_smallFont, LAND_BUTTON_WIDTH+80, buf );
97 window_addText( wid, 40 + iw, -60 - titleHeight, 200, infoHeight, 0,
98 "txtSInfo", &gl_smallFont, &cFontGrey, buf );
99 window_addText( wid, 40 + iw + 224, -60 - titleHeight,
100 dw - (200 + 20+192), infoHeight, 0,
101 "txtDInfo", &gl_smallFont, NULL, NULL );
102
103 window_addText( wid, 40 + iw, -80-titleHeight-infoHeight,
104 dw, 100, 0, "txtDRef", &gl_smallFont, NULL, NULL );
105 window_addText( wid, 40 + iw, MIN(-80-titleHeight-infoHeight, -192-60),
106 dw, h - (80+titleHeight+infoHeight) - (40+LAND_BUTTON_HEIGHT), 0,
107 "txtDesc", &gl_smallFont, NULL, NULL );
108
109 /* goods list */
110 ngoods = array_size( land_spob->commodities );
111
112 /* Count always sellable goods. */
113 for (int i=0; i<array_size(player.p->commodities); i++) {
115 if (pc->id > 0) /* Ignore mission stuff. */
116 continue;
117 if (!commodity_isFlag(pc->commodity, COMMODITY_FLAG_ALWAYS_CAN_SELL))
118 continue;
119 ngoods++;
120 }
121 if (ngoods > 0) {
122 cgoods = calloc( ngoods, sizeof(ImageArrayCell) );
123 if (commodity_list != NULL)
124 free(commodity_list);
125 commodity_list = malloc( ngoods*sizeof(Commodity*) );
126 j = 0;
127
128 /* First add special sellable. */
129 for (int i=0; i<array_size(player.p->commodities); i++) {
131 if (pc->id > 0) /* Ignore mission stuff. */
132 continue;
133 if (!commodity_isFlag(pc->commodity, COMMODITY_FLAG_ALWAYS_CAN_SELL))
134 continue;
135 cgoods[j].image = gl_dupTexture(pc->commodity->gfx_store);
136 cgoods[j].caption = strdup( _(pc->commodity->name) );
137 commodity_list[j] = (Commodity*) pc->commodity;
138 j++;
139 }
140
141 /* Then add default. */
142 for (int i=0; i<array_size(land_spob->commodities); i++) {
143 cgoods[j].image = gl_dupTexture(land_spob->commodities[i]->gfx_store);
144 cgoods[j].caption = strdup( _(land_spob->commodities[i]->name) );
145 commodity_list[j] = land_spob->commodities[i];
146 j++;
147 }
148 }
149 else {
150 ngoods = 1;
151 cgoods = calloc( ngoods, sizeof(ImageArrayCell) );
152 cgoods[0].image = NULL;
153 cgoods[0].caption = strdup(_("None"));
154 }
155
156 /* set up the goods to buy/sell */
157 iconsize = 128;
158 if (!conf.big_icons) {
159 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) < ngoods)
160 iconsize = 96;
161 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) < ngoods)
162 iconsize = 64;
163 }
164 window_addImageArray( wid, 20, 20,
165 iw, ih, "iarTrade", iconsize, iconsize,
167
168 /* Set default keyboard focuse to the list */
169 window_setFocus( wid , "iarTrade" );
170}
171
172void commodity_exchange_cleanup (void)
173{
174 free(commodity_list);
175 commodity_list = NULL;
176}
177
183void commodity_update( unsigned int wid, const char *str )
184{
185 (void) str;
186 char buf[STRMAX];
187 char buf_purchase_price[ECON_CRED_STRLEN], buf_credits[ECON_CRED_STRLEN];
188 size_t l = 0;
189 const Commodity *com;
190 credits_t mean,globalmean;
191 double std, globalstd;
192 char buf_mean[ECON_CRED_STRLEN], buf_globalmean[ECON_CRED_STRLEN];
193 char buf_std[ECON_CRED_STRLEN], buf_globalstd[ECON_CRED_STRLEN];
194 char buf_local_price[ECON_CRED_STRLEN];
195 char buf_tonnes_owned[ECON_MASS_STRLEN], buf_tonnes_free[ECON_MASS_STRLEN];
196 int owned, cargo_free;
197 int i = toolkit_getImageArrayPos( wid, "iarTrade" );
198 credits2str( buf_credits, player.p->credits, 2 );
199 cargo_free = pfleet_cargoFree();
200 tonnes2str( buf_tonnes_free, cargo_free );
201
202 if (i < 0 || array_size(land_spob->commodities) == 0) {
203 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", _("N/A") );
204 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_tonnes_free );
205 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_credits );
206 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
207 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("N/A") );
208 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("N/A") );
209 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("N/A") );
210 window_modifyText( wid, "txtDInfo", buf );
211 window_modifyText( wid, "txtDesc", _("No commodities available.") );
212 window_disableButton( wid, "btnCommodityBuy" );
213 window_disableButton( wid, "btnCommoditySell" );
214 return;
215 }
216 com = commodity_list[i];
217
218 /* modify image */
219 window_modifyImage( wid, "imgStore", com->gfx_store, 192, 192 );
220
221 spob_averageSpobPrice( land_spob, com, &mean, &std);
222 credits2str( buf_mean, mean, -1 );
223 snprintf( buf_std, sizeof(buf_std), _("%.1f ¤"), std ); /* TODO credit2str could learn to do this... */
224 economy_getAveragePrice( com, &globalmean, &globalstd );
225 credits2str( buf_globalmean, globalmean, -1 );
226 snprintf( buf_globalstd, sizeof(buf_globalstd), _("%.1f ¤"), globalstd ); /* TODO credit2str could learn to do this... */
227 /* modify text */
228 buf_purchase_price[0]='\0';
229 owned = pfleet_cargoOwned( com );
230 if (owned > 0)
231 credits2str( buf_purchase_price, com->lastPurchasePrice, -1 );
232 credits2str( buf_local_price, spob_commodityPrice( land_spob, com ), -1 );
233 tonnes2str( buf_tonnes_owned, owned );
234 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", buf_tonnes_owned );
235 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_tonnes_free );
236 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_credits );
237 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
238 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s/t"), buf_local_price );
239 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
240 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s/t ± %s/t"), buf_mean, buf_std );
241 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
242 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s/t ± %s/t"), buf_globalmean, buf_globalstd );
243 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_purchase_price );
244
245 window_modifyText( wid, "txtDInfo", buf );
246 window_modifyText( wid, "txtName", _(com->name) );
247 window_modifyText( wid, "txtDesc", _(com->description) );
248
249 /* Add relative price. */
250 l = 0;
251 if (commodity_isFlag(com, COMMODITY_FLAG_PRICE_CONSTANT)) {
252 l += scnprintf( &buf[l], sizeof(buf)-l, _("Price is constant.") );
253 window_modifyText( wid, "txtDRef", buf );
254 }
255 else if (com->price_ref != NULL) {
256 char c = '0';
257 if (com->price_mod > 1.)
258 c = 'g';
259 else if (com->price_mod < 1.)
260 c = 'r';
261 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) );
262 window_modifyText( wid, "txtDRef", buf );
263 }
264 else
265 window_modifyText( wid, "txtDRef", NULL );
266
267 /* Button enabling/disabling */
268 if (commodity_canBuy( com ))
269 window_enableButton( wid, "btnCommodityBuy" );
270 else
271 window_disableButtonSoft( wid, "btnCommodityBuy" );
272
273 if (commodity_canSell( com ))
274 window_enableButton( wid, "btnCommoditySell" );
275 else
276 window_disableButtonSoft( wid, "btnCommoditySell" );
277}
278
283{
284 int failure, incommodities;
285 unsigned int q, price;
286 char buf[ECON_CRED_STRLEN];
287
288 failure = 0;
289 q = commodity_getMod();
290 price = spob_commodityPrice( land_spob, com ) * q;
291
292 if (!player_hasCredits( price )) {
293 credits2str( buf, price - player.p->credits, 2 );
294 land_errDialogueBuild(_("You need %s more."), buf );
295 failure = 1;
296 }
297 if (pfleet_cargoFree() <= 0) {
298 land_errDialogueBuild(_("No cargo space available!"));
299 failure = 1;
300 }
301
302 incommodities = 0;
303 for (int i=0; i<array_size(land_spob->commodities); i++) {
304 if (land_spob->commodities[i] == com) {
305 incommodities = 1;
306 break;
307 }
308 }
309 if (!incommodities) {
310 land_errDialogueBuild(_("%s is not sold here!"), _(com->name));
311 failure = 1;
312 }
313
314 return !failure;
315}
316
321{
322 int failure = 0;
323 if (pfleet_cargoOwned( com ) ==0) {
324 land_errDialogueBuild(_("You can't sell something you don't have!"));
325 failure = 1;
326 }
327 return !failure;
328}
329
335void commodity_buy( unsigned int wid, const char *str )
336{
337 (void)str;
338 int i;
339 Commodity *com;
340 unsigned int q;
341 credits_t price;
342 HookParam hparam[3];
343
344 /* Get selected. */
345 q = commodity_getMod();
346 i = toolkit_getImageArrayPos( wid, "iarTrade" );
347 com = commodity_list[i];
348 price = spob_commodityPrice( land_spob, com );
349
350 /* Check stuff. */
351 if (land_errDialogue( com->name, "buyCommodity" ))
352 return;
353
354 /* Make the buy. */
355 q = pfleet_cargoAdd( com, q );
356 com->lastPurchasePrice = price; /* To show the player how much they paid for it */
357 price *= q;
358 player_modCredits( -price );
359 commodity_update(wid, NULL);
360
361 /* Run hooks. */
362 hparam[0].type = HOOK_PARAM_STRING;
363 hparam[0].u.str = com->name;
364 hparam[1].type = HOOK_PARAM_NUMBER;
365 hparam[1].u.num = q;
366 hparam[2].type = HOOK_PARAM_SENTINEL;
367 hooks_runParam( "comm_buy", hparam );
368 land_needsTakeoff( 1 );
369}
370
376void commodity_sell( unsigned int wid, const char *str )
377{
378 (void) str;
379 int i;
380 Commodity *com;
381 unsigned int q;
382 credits_t price;
383 HookParam hparam[3];
384
385 /* Get parameters. */
386 q = commodity_getMod();
387 i = toolkit_getImageArrayPos( wid, "iarTrade" );
388 com = commodity_list[i];
389 price = spob_commodityPrice( land_spob, com );
390
391 /* Check stuff. */
392 if (land_errDialogue( com->name, "sellCommodity" ))
393 return;
394
395 /* Remove commodity. */
396 q = pfleet_cargoRm( com, q, 0 );
397 price = price * (credits_t)q;
398 player_modCredits( price );
399 if (pfleet_cargoOwned( com ) == 0) /* None left, set purchase price to zero, in case missions add cargo. */
400 com->lastPurchasePrice = 0;
401 commodity_update(wid, NULL);
402
403 /* Run hooks. */
404 hparam[0].type = HOOK_PARAM_STRING;
405 hparam[0].u.str = com->name;
406 hparam[1].type = HOOK_PARAM_NUMBER;
407 hparam[1].u.num = q;
408 hparam[2].type = HOOK_PARAM_SENTINEL;
409 hooks_runParam( "comm_sell", hparam );
410 land_needsTakeoff( 1 );
411}
412
418{
419 SDL_Keymod mods = SDL_GetModState();
420 int q = 10;
421 if (mods & (KMOD_LCTRL | KMOD_RCTRL))
422 q *= 5;
423 if (mods & (KMOD_LSHIFT | KMOD_RSHIFT))
424 q *= 10;
425
426 return q;
427}
428
437void commodity_renderMod( double bx, double by, double w, double h, void *data )
438{
439 (void) data;
440 (void) h;
441 int q;
442 char buf[8];
443
444 q = commodity_getMod();
445 if (q != commodity_mod) {
446 //commodity_update( land_getWid(LAND_WINDOW_COMMODITY), NULL );
447 commodity_mod = q;
448 }
449 snprintf( buf, sizeof(buf), "%dx", q );
450 gl_printMidRaw( &gl_smallFont, w, bx, by, &cFontWhite, -1, buf );
451}
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
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:1026
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:787
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition: hook.c:967
void land_errDialogueBuild(const char *fmt,...)
Generates error dialogues used by several landing tabs.
Definition: land.c:288
int land_errDialogue(const char *name, const char *type)
Generates error dialogues used by several landing tabs.
Definition: land.c:256
Spob * land_spob
Definition: land.c:82
void land_buttonTakeoff(unsigned int wid, const char *unused)
Wrapper for takeoff mission button.
Definition: land.c:925
int commodity_canBuy(const Commodity *com)
Checks to see if the player can buy a commodity.
Definition: land_trade.c:282
int commodity_getMod(void)
Gets the current modifier status.
Definition: land_trade.c:417
void commodity_exchange_open(unsigned int wid)
Opens the local market window.
Definition: land_trade.c:45
void commodity_sell(unsigned int wid, const char *str)
Attempts to sell a commodity.
Definition: land_trade.c:376
void commodity_renderMod(double bx, double by, double w, double h, void *data)
Renders the commodity buying modifier.
Definition: land_trade.c:437
void commodity_buy(unsigned int wid, const char *str)
Buys the selected commodity.
Definition: land_trade.c:335
int commodity_canSell(const Commodity *com)
Checks to see if a player can sell a commodity.
Definition: land_trade.c:320
void commodity_update(unsigned int wid, const char *str)
Updates the commodity window.
Definition: land_trade.c:183
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:178
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition: opengl_tex.c:809
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition: player.c:947
Player_t player
Definition: player.c:73
int player_hasCredits(credits_t amount)
Checks to see if the player has enough credits.
Definition: player.c:936
int pfleet_cargoFree(void)
Gets the total amount of free cargo space in the player's fleet.
Definition: player_fleet.c:255
int pfleet_cargoOwned(const Commodity *com)
Gets the total amount of a commodity type owned by the player's fleet.
Definition: player_fleet.c:280
int pfleet_cargoAdd(const Commodity *com, int q)
Adds some cargo to the player's fleet.
Definition: player_fleet.c:306
int pfleet_cargoRm(const Commodity *com, int q, int jet)
Removes some cargo from the player's fleet.
Definition: player_fleet.c:335
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:312
credits_t spob_commodityPrice(const Spob *p, const Commodity *c)
Gets the price of a commodity at a spob.
Definition: space.c:272
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:35
const char * str
Definition: hook.h:39
union HookParam::@4 u
HookParamType type
Definition: hook.h:36
double num
Definition: hook.h:38
Stores a pilot commodity.
Definition: pilot.h:172
const Commodity * commodity
Definition: pilot.h:173
unsigned int id
Definition: pilot.h:175
PilotCommodity * commodities
Definition: pilot.h:318
credits_t credits
Definition: pilot.h:317
int big_icons
Definition: conf.h:126
Pilot * p
Definition: player.h:101
int fleet_capacity
Definition: player.h:131
Commodity ** commodities
Definition: space.h:114
int h
Definition: font.h:18
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition: toolkit.c:2460
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition: toolkit.c:371
void window_canFocusWidget(unsigned int wid, const char *name, int canfocus)
Allows or disallows focusing a widget.
Definition: toolkit.c:523