1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2011 by The Allacrost Project
3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 // All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See https://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10
11 /** ****************************************************************************
12 *** \file shop_utils.cpp
13 *** \author Tyler Olsen, roots@allacrost.org
14 *** \author Yohann Ferreira, yohann ferreira orange fr
15 *** \brief Source file for shop mode utility code.
16 ***
17 *** This file contains utility code that is shared among the various shop mode
18 *** classes.
19 *** ***************************************************************************/
20
21 #include "shop_utils.h"
22
23 #include "engine/video/video.h"
24
25 #include "common/global/global.h"
26
27 #include "shop.h"
28
29 using namespace vt_utils;
30 using namespace vt_system;
31 using namespace vt_video;
32 using namespace vt_gui;
33
34 using namespace vt_global;
35
36 namespace vt_shop
37 {
38
39 namespace private_shop
40 {
41
42 // *****************************************************************************
43 // ***** ShopObject class methods
44 // *****************************************************************************
45
ShopObject(const std::shared_ptr<vt_global::GlobalObject> & object)46 ShopObject::ShopObject(const std::shared_ptr<vt_global::GlobalObject>& object) :
47 _object(object),
48 _buy_price(0),
49 _sell_price(0),
50 _own_count(0),
51 _stock_count(0),
52 _infinite_buy_amount(false),
53 _buy_count(0),
54 _sell_count(0),
55 _trade_count(0)
56 {
57 assert(_object != nullptr);
58
59 // Init the trading price
60 _trade_price = _object->GetTradingPrice();
61 }
62
DetermineShopObjectType(GLOBAL_OBJECT global_type)63 SHOP_OBJECT ShopObject::DetermineShopObjectType(GLOBAL_OBJECT global_type)
64 {
65 SHOP_OBJECT shop_type;
66
67 switch(global_type) {
68 case GLOBAL_OBJECT_ITEM:
69 shop_type = SHOP_OBJECT_ITEM;
70 break;
71 case GLOBAL_OBJECT_WEAPON:
72 case GLOBAL_OBJECT_HEAD_ARMOR:
73 case GLOBAL_OBJECT_TORSO_ARMOR:
74 case GLOBAL_OBJECT_ARM_ARMOR:
75 case GLOBAL_OBJECT_LEG_ARMOR:
76 shop_type = SHOP_OBJECT_EQUIPMENT;
77 break;
78 case GLOBAL_OBJECT_SPIRIT:
79 shop_type = SHOP_OBJECT_SPIRIT;
80 break;
81 case GLOBAL_OBJECT_INVALID:
82 case GLOBAL_OBJECT_TOTAL:
83 default:
84 IF_PRINT_WARNING(SHOP_DEBUG) << "no conversion type existed for global object: " << global_type << std::endl;
85 shop_type = SHOP_OBJECT_INVALID;
86 break;
87 }
88
89 return shop_type;
90 }
91
92
93
DetermineShopObjectType()94 SHOP_OBJECT ShopObject::DetermineShopObjectType()
95 {
96 return DetermineShopObjectType(GetObject()->GetObjectType());
97 }
98
99
100
SetPricing(SHOP_PRICE_LEVEL buy_level,SHOP_PRICE_LEVEL sell_level)101 void ShopObject::SetPricing(SHOP_PRICE_LEVEL buy_level,
102 SHOP_PRICE_LEVEL sell_level)
103 {
104 _buy_price = _object->GetPrice();
105 _sell_price = _object->GetPrice();
106 _trade_price = _object->GetTradingPrice();
107 _trade_conditions = _object->GetTradeConditions();
108
109 switch(buy_level) {
110 case SHOP_PRICE_VERY_GOOD:
111 _buy_price *= BUY_PRICE_VERY_GOOD;
112 break;
113 case SHOP_PRICE_GOOD:
114 _buy_price *= BUY_PRICE_GOOD;
115 break;
116 case SHOP_PRICE_STANDARD:
117 _buy_price *= BUY_PRICE_STANDARD;
118 break;
119 case SHOP_PRICE_POOR:
120 _buy_price *= BUY_PRICE_POOR;
121 break;
122 case SHOP_PRICE_VERY_POOR:
123 _buy_price *= BUY_PRICE_VERY_POOR;
124 break;
125 default:
126 IF_PRINT_WARNING(SHOP_DEBUG) << "unknown buy level: " << buy_level << std::endl;
127 }
128
129 switch(sell_level) {
130 case SHOP_PRICE_VERY_GOOD:
131 _sell_price *= SELL_PRICE_VERY_GOOD;
132 break;
133 case SHOP_PRICE_GOOD:
134 _sell_price *= SELL_PRICE_GOOD;
135 break;
136 case SHOP_PRICE_STANDARD:
137 _sell_price *= SELL_PRICE_STANDARD;
138 break;
139 case SHOP_PRICE_POOR:
140 _sell_price *= SELL_PRICE_POOR;
141 break;
142 case SHOP_PRICE_VERY_POOR:
143 _sell_price *= SELL_PRICE_VERY_POOR;
144 break;
145 default:
146 IF_PRINT_WARNING(SHOP_DEBUG) << "unknown sell level: " << sell_level << std::endl;
147 }
148 }
149
150
151
IncrementOwnCount(uint32_t inc)152 void ShopObject::IncrementOwnCount(uint32_t inc)
153 {
154 _own_count += inc;
155 }
156
157
158
IncrementStockCount(uint32_t inc)159 void ShopObject::IncrementStockCount(uint32_t inc)
160 {
161 _stock_count += inc;
162 }
163
164
165
IncrementBuyCount(uint32_t inc)166 void ShopObject::IncrementBuyCount(uint32_t inc)
167 {
168 uint32_t old_count = _buy_count;
169 if(inc == 0) {
170 IF_PRINT_WARNING(SHOP_DEBUG) << "function received an argument with a value of zero" << std::endl;
171 return;
172 }
173
174 _buy_count += inc;
175 if(!IsInfiniteAmount() && _stock_count < _buy_count) {
176 IF_PRINT_WARNING(SHOP_DEBUG) << "incremented buy count beyond the amount available in stock" << std::endl;
177 _buy_count = old_count;
178 return;
179 }
180 if(old_count == 0) {
181 ShopMode::CurrentInstance()->AddObjectToBuyList(this);
182 }
183 }
184
185
186
IncrementSellCount(uint32_t inc)187 void ShopObject::IncrementSellCount(uint32_t inc)
188 {
189 uint32_t old_count = _sell_count;
190 if(inc == 0) {
191 IF_PRINT_WARNING(SHOP_DEBUG) << "function received an argument with a value of zero" << std::endl;
192 return;
193 }
194
195 _sell_count += inc;
196 if(_sell_count > _own_count) {
197 IF_PRINT_WARNING(SHOP_DEBUG) << "incremented sell count beyond the amount available to be sold" << std::endl;
198 _sell_count -= inc;
199 return;
200 }
201 if(old_count == 0) {
202 ShopMode::CurrentInstance()->AddObjectToSellList(this);
203 }
204 }
205
206
207
IncrementTradeCount(uint32_t inc)208 void ShopObject::IncrementTradeCount(uint32_t inc)
209 {
210 uint32_t old_count = _trade_count;
211 if(inc == 0) {
212 IF_PRINT_WARNING(SHOP_DEBUG) << "function received an argument with a value of zero" << std::endl;
213 return;
214 }
215
216 _trade_count += inc;
217 if(!IsInfiniteAmount() && _trade_count > _stock_count) {
218 IF_PRINT_WARNING(SHOP_DEBUG) << "incremented sell count beyond the amount available to be sold" << std::endl;
219 _trade_count -= inc;
220 return;
221 }
222 if(old_count == 0) {
223 ShopMode::CurrentInstance()->AddObjectToTradeList(this);
224 }
225 }
226
227
228
DecrementOwnCount(uint32_t dec)229 void ShopObject::DecrementOwnCount(uint32_t dec)
230 {
231 if(dec > _own_count) {
232 IF_PRINT_WARNING(SHOP_DEBUG) << "attempted to decrement own count below zero" << std::endl;
233 return;
234 }
235
236 _own_count -= dec;
237
238 if(_own_count < _sell_count) {
239 IF_PRINT_WARNING(SHOP_DEBUG) << "decremented own count below that of the sell count" << std::endl;
240 _own_count += dec;
241 }
242 }
243
244
245
DecrementStockCount(uint32_t dec)246 void ShopObject::DecrementStockCount(uint32_t dec)
247 {
248 // Doesn't apply when there is an infinity of such items.
249 if (IsInfiniteAmount())
250 return;
251
252 if(dec > _stock_count) {
253 IF_PRINT_WARNING(SHOP_DEBUG) << "attempted to decrement stock count below zero" << std::endl;
254 return;
255 }
256
257 _stock_count -= dec;
258
259 if(_stock_count < _buy_count) {
260 IF_PRINT_WARNING(SHOP_DEBUG) << "decremented stock count below that of the buy count" << std::endl;
261 _stock_count += dec;
262 }
263 }
264
265
266
DecrementBuyCount(uint32_t dec)267 void ShopObject::DecrementBuyCount(uint32_t dec)
268 {
269 if(dec == 0) {
270 IF_PRINT_WARNING(SHOP_DEBUG) << "function received an argument with a value of zero" << std::endl;
271 return;
272 }
273
274 if(dec > _buy_count) {
275 IF_PRINT_WARNING(SHOP_DEBUG) << "attempted to decrement buy count below zero" << std::endl;
276 return;
277 }
278
279 _buy_count -= dec;
280 if(_buy_count == 0) {
281 ShopMode::CurrentInstance()->RemoveObjectFromBuyList(this);
282 }
283 }
284
285
286
DecrementSellCount(uint32_t dec)287 void ShopObject::DecrementSellCount(uint32_t dec)
288 {
289 if(dec == 0) {
290 IF_PRINT_WARNING(SHOP_DEBUG) << "function received an argument with a value of zero" << std::endl;
291 return;
292 }
293
294 if(dec > _sell_count) {
295 IF_PRINT_WARNING(SHOP_DEBUG) << "attempted to decrement sell count below zero" << std::endl;
296 return;
297 }
298
299 _sell_count -= dec;
300 if(_sell_count == 0) {
301 ShopMode::CurrentInstance()->RemoveObjectFromSellList(this);
302 }
303 }
304
305
DecrementTradeCount(uint32_t dec)306 void ShopObject::DecrementTradeCount(uint32_t dec)
307 {
308 if(dec == 0) {
309 IF_PRINT_WARNING(SHOP_DEBUG) << "function received an argument with a value of zero" << std::endl;
310 return;
311 }
312
313 if(dec > _trade_count) {
314 IF_PRINT_WARNING(SHOP_DEBUG) << "attempted to decrement sell count below zero" << std::endl;
315 return;
316 }
317
318 _trade_count -= dec;
319 if(_trade_count == 0) {
320 ShopMode::CurrentInstance()->RemoveObjectFromTradeList(this);
321 }
322 }
323
324 // *****************************************************************************
325 // ***** ObjectCategoryDisplay class methods
326 // *****************************************************************************
327
328 // The time it takes to transition graphics to a new category (in milliseconds)
329 const uint32_t TRANSITION_TIME_ICON = 500;
330 // Represents the display speed when transitioning to new category text
331 const float TRANSITION_TIME_TEXT = 25.0f;
332
ObjectCategoryDisplay()333 ObjectCategoryDisplay::ObjectCategoryDisplay() :
334 _view_mode(SHOP_VIEW_MODE_LIST),
335 _selected_object(nullptr),
336 _current_icon(nullptr),
337 _last_icon(nullptr),
338 _object_icon(nullptr)
339 {
340 _name_text.SetStyle(TextStyle("text22"));
341
342 _name_textbox.SetOwner(ShopMode::CurrentInstance()->GetMiddleWindow());
343 _name_textbox.SetPosition(25.0f, 225.0f);
344 _name_textbox.SetDimensions(125.0f, 30.0f);
345 _name_textbox.SetTextStyle(TextStyle("text22"));
346 _name_textbox.SetDisplayMode(VIDEO_TEXT_FADECHAR);
347 _name_textbox.SetDisplaySpeed(TRANSITION_TIME_TEXT);
348 _name_textbox.SetAlignment(VIDEO_X_LEFT, VIDEO_Y_TOP);
349 // TODO: Alignment should be VIDEO_X_CENTER, but a bug is preventing it from working correctly right now
350 _name_textbox.SetTextAlignment(VIDEO_X_LEFT, VIDEO_Y_TOP);
351
352 _transition_timer.Initialize(TRANSITION_TIME_ICON, SYSTEM_TIMER_NO_LOOPS);
353 _transition_timer.EnableAutoUpdate(ShopMode::CurrentInstance());
354 }
355
356
357
~ObjectCategoryDisplay()358 ObjectCategoryDisplay::~ObjectCategoryDisplay()
359 {
360 _selected_object = nullptr;
361 _current_icon = nullptr;
362 _last_icon = nullptr;
363 _object_icon = nullptr;
364 }
365
366
367
Update()368 void ObjectCategoryDisplay::Update()
369 {
370 _name_textbox.Update();
371 }
372
373
374
Draw()375 void ObjectCategoryDisplay::Draw()
376 {
377 VideoManager->SetDrawFlags(VIDEO_X_CENTER, VIDEO_Y_CENTER, 0);
378
379 if(_view_mode == SHOP_VIEW_MODE_LIST) {
380 VideoManager->Move(200.0f, 358.0f);
381
382 if(_transition_timer.IsRunning()) {
383 // Alpha ranges from 0.0f at timer start to 1.0f at end
384 float alpha = static_cast<float>(_transition_timer.GetTimeExpired()) / static_cast<float>(TRANSITION_TIME_ICON);
385
386 if(_last_icon != nullptr)
387 _last_icon->Draw(Color(1.0f, 1.0f, 1.0f, 1.0f - alpha));
388 if(_current_icon != nullptr)
389 _current_icon->Draw(Color(1.0f, 1.0f, 1.0f, alpha));
390 } else if(_current_icon != nullptr) {
391 _current_icon->Draw();
392 }
393 _name_textbox.Draw();
394 } else if((_view_mode == SHOP_VIEW_MODE_INFO) && (_selected_object != nullptr)) {
395 VideoManager->Move(200.0f, 603.0f);
396 _object_icon->Draw();
397 VideoManager->MoveRelative(0.0f, 45.0f);
398 _name_text.Draw();
399 }
400 }
401
402
403
ChangeViewMode(SHOP_VIEW_MODE new_mode)404 void ObjectCategoryDisplay::ChangeViewMode(SHOP_VIEW_MODE new_mode)
405 {
406 if(_view_mode == new_mode) {
407 return;
408 }
409
410 if(new_mode == SHOP_VIEW_MODE_LIST) {
411 _view_mode = new_mode;
412 _transition_timer.Finish();
413 } else if(new_mode == SHOP_VIEW_MODE_INFO) {
414 _view_mode = new_mode;
415 } else {
416 IF_PRINT_WARNING(SHOP_DEBUG) << "invalid/unknown view mode requested: " << new_mode << std::endl;
417 return;
418 }
419 }
420
421
422
SetSelectedObject(ShopObject * shop_object)423 void ObjectCategoryDisplay::SetSelectedObject(ShopObject *shop_object)
424 {
425 if(_selected_object == shop_object) {
426 return;
427 }
428
429 _selected_object = shop_object;
430
431 if(_selected_object == nullptr) {
432 _object_icon = nullptr;
433 _name_text.SetText("");
434 return;
435 }
436 GLOBAL_OBJECT object_type = _selected_object->GetObject()->GetObjectType();
437 _name_text.SetText(*(ShopMode::CurrentInstance()->Media()->GetCategoryName(object_type)));
438 _object_icon = GlobalManager->Media().GetItemCategoryIcon(object_type);
439 }
440
441
442
ChangeCategory(ustring & name,const StillImage * icon)443 void ObjectCategoryDisplay::ChangeCategory(ustring &name, const StillImage *icon)
444 {
445 if(icon == nullptr) {
446 IF_PRINT_WARNING(SHOP_DEBUG) << "function was passed a nullptr pointer argument" << std::endl;
447 }
448
449 _name_textbox.SetDisplayText(name);
450
451 _last_icon = _current_icon;
452 _current_icon = icon;
453
454 if(_view_mode == SHOP_VIEW_MODE_LIST) {
455 _transition_timer.Reset();
456 _transition_timer.Run();
457 }
458 }
459
460 // *****************************************************************************
461 // ***** ObjectListDisplay class methods
462 // *****************************************************************************
463
ObjectListDisplay()464 ObjectListDisplay::ObjectListDisplay()
465 {
466 _identify_list.SetOwner(ShopMode::CurrentInstance()->GetMiddleWindow());
467 _identify_list.SetPosition(180.0f, 70.0f);
468 _identify_list.SetDimensions(300.0f, 300.0f, 1, 255, 1, 8);
469 _identify_list.SetOptionAlignment(VIDEO_X_LEFT, VIDEO_Y_CENTER);
470 _identify_list.SetTextStyle(TextStyle("text22"));
471 _identify_list.SetCursorState(VIDEO_CURSOR_STATE_VISIBLE);
472 _identify_list.SetSelectMode(VIDEO_SELECT_SINGLE);
473 _identify_list.SetCursorOffset(-50.0f, -20.0f);
474 _identify_list.SetHorizontalWrapMode(VIDEO_WRAP_MODE_NONE);
475 _identify_list.SetVerticalWrapMode(VIDEO_WRAP_MODE_STRAIGHT);
476
477 _property_list.SetOwner(ShopMode::CurrentInstance()->GetMiddleWindow());
478 _property_list.SetPosition(480.0f, 70.0f);
479 if(ShopMode::CurrentInstance()->GetState() == SHOP_STATE_SELL) {
480 _property_list.SetDimensions(300.0f, 300.0f, 2, 255, 2, 8);
481 } else {
482 _property_list.SetDimensions(300.0f, 300.0f, 3, 255, 3, 8);
483 }
484 _property_list.SetOptionAlignment(VIDEO_X_RIGHT, VIDEO_Y_CENTER);
485 _property_list.SetTextStyle(TextStyle("text22"));
486 _property_list.SetCursorState(VIDEO_CURSOR_STATE_HIDDEN);
487 _property_list.SetHorizontalWrapMode(VIDEO_WRAP_MODE_NONE);
488 _property_list.SetVerticalWrapMode(VIDEO_WRAP_MODE_STRAIGHT);
489 }
490
491
492
Clear()493 void ObjectListDisplay::Clear()
494 {
495 _objects.clear();
496 _identify_list.ClearOptions();
497 _property_list.ClearOptions();
498 }
499
PopulateList(const std::vector<ShopObject * > & objects)500 void ObjectListDisplay::PopulateList(const std::vector<ShopObject *>& objects)
501 {
502 _objects = objects;
503 ReconstructList();
504 }
505
GetSelectedObject()506 ShopObject *ObjectListDisplay::GetSelectedObject()
507 {
508 if(IsListEmpty())
509 return nullptr;
510
511 if(static_cast<uint32_t>(_identify_list.GetSelection()) >= _objects.size()) {
512 IF_PRINT_WARNING(SHOP_DEBUG) << "current selection index exceeds available objects: " << _identify_list.GetSelection() << std::endl;
513 return nullptr;
514 }
515
516 return _objects[_identify_list.GetSelection()];
517 }
518
519
520
ResetSelection()521 void ObjectListDisplay::ResetSelection()
522 {
523 if(IsListEmpty() == false) {
524 _identify_list.SetSelection(0);
525 _property_list.SetSelection(0);
526 }
527 }
528
529
530
GetCurrentSelection()531 uint32_t ObjectListDisplay::GetCurrentSelection()
532 {
533 if(IsListEmpty())
534 return 0;
535 return static_cast<uint32_t>(_identify_list.GetSelection());
536 }
537
538
539
InputUp()540 void ObjectListDisplay::InputUp()
541 {
542 _identify_list.InputUp();
543 _property_list.InputUp();
544 }
545
546
547
InputDown()548 void ObjectListDisplay::InputDown()
549 {
550 _identify_list.InputDown();
551 _property_list.InputDown();
552 }
553
554
555
Update()556 void ObjectListDisplay::Update()
557 {
558 _identify_list.Update();
559 _property_list.Update();
560 }
561
562
563
Draw()564 void ObjectListDisplay::Draw()
565 {
566 _identify_list.Draw();
567 _property_list.Draw();
568 }
569
570 } // namespace private_shop
571
572 } // namespace vt_shop
573