1 #include "Directories.h"
2 #include "Font.h"
3 #include "Laptop.h"
4 #include "BobbyR.h"
5 #include "BobbyRGuns.h"
6 #include "Timer_Control.h"
7 #include "VObject.h"
8 #include "WordWrap.h"
9 #include "Cursors.h"
10 #include "Interface_Items.h"
11 #include "Weapons.h"
12 #include "Store_Inventory.h"
13 #include "Game_Event_Hook.h"
14 #include "Game_Clock.h"
15 #include "LaptopSave.h"
16 #include "Random.h"
17 #include "Text.h"
18 #include "Multi_Language_Graphic_Utils.h"
19 #include "ArmsDealerInvInit.h"
20 #include "Video.h"
21 #include "VSurface.h"
22 #include "Debug.h"
23 #include "Font_Control.h"
24 #include "Items.h"
25
26 #include "ContentManager.h"
27 #include "DealerInventory.h"
28 #include "GameInstance.h"
29
30 #include <algorithm>
31
32 #define BOBBIES_SIGN_FONT FONT14ARIAL
33 #define BOBBIES_SIGN_COLOR 2
34 #define BOBBIES_SIGN_BACKCOLOR FONT_MCOLOR_BLACK
35 #define BOBBIES_SIGN_BACKGROUNDCOLOR 78//NO_SHADOW
36
37 #define BOBBIES_NUMBER_SIGNS 5
38
39 #define BOBBIES_SENTENCE_FONT FONT12ARIAL
40 #define BOBBIES_SENTENCE_COLOR FONT_MCOLOR_WHITE
41 #define BOBBIES_SENTENCE_BACKGROUNDCOLOR 2//NO_SHADOW//226
42
43 #define BOBBY_WOOD_BACKGROUND_X LAPTOP_SCREEN_UL_X
44 #define BOBBY_WOOD_BACKGROUND_Y LAPTOP_SCREEN_WEB_UL_Y
45 #define BOBBY_WOOD_BACKGROUND_WIDTH 125
46 #define BOBBY_WOOD_BACKGROUND_HEIGHT 100
47
48 #define BOBBY_RAYS_NAME_X LAPTOP_SCREEN_UL_X + 77
49 #define BOBBY_RAYS_NAME_Y LAPTOP_SCREEN_WEB_UL_Y + 0
50
51 #define BOBBYS_PLAQUES_X LAPTOP_SCREEN_UL_X + 39
52 #define BOBBYS_PLAQUES_Y LAPTOP_SCREEN_WEB_UL_Y + 174
53
54 #define BOBBIES_TOPHINGE_X LAPTOP_SCREEN_UL_X
55 #define BOBBIES_TOPHINGE_Y LAPTOP_SCREEN_WEB_UL_Y + 42
56
57 #define BOBBIES_BOTTOMHINGE_X LAPTOP_SCREEN_UL_X
58 #define BOBBIES_BOTTOMHINGE_Y LAPTOP_SCREEN_WEB_UL_Y + 338
59
60 #define BOBBIES_STORE_PLAQUE_X LAPTOP_SCREEN_UL_X + 148
61 #define BOBBIES_STORE_PLAQUE_Y LAPTOP_SCREEN_WEB_UL_Y + 66
62 #define BOBBIES_STORE_PLAQUE_HEIGHT 93
63
64 #define BOBBIES_HANDLE_X LAPTOP_SCREEN_UL_X + 457
65 #define BOBBIES_HANDLE_Y LAPTOP_SCREEN_WEB_UL_Y + 147
66
67 #define BOBBIES_FIRST_SENTENCE_X LAPTOP_SCREEN_UL_X
68 #define BOBBIES_FIRST_SENTENCE_Y BOBBIES_STORE_PLAQUE_Y + BOBBIES_STORE_PLAQUE_HEIGHT - 3
69 #define BOBBIES_FIRST_SENTENCE_WIDTH 500
70
71 #define BOBBIES_2ND_SENTENCE_X LAPTOP_SCREEN_UL_X
72 #define BOBBIES_2ND_SENTENCE_Y BOBBIES_FIRST_SENTENCE_Y + 13
73 #define BOBBIES_2ND_SENTENCE_WIDTH 500
74
75 #define BOBBIES_CENTER_SIGN_OFFSET_Y 23
76
77 #define BOBBIES_USED_SIGN_X (UINT16)(BOBBYS_PLAQUES_X + 93)
78 #define BOBBIES_USED_SIGN_Y (UINT16)(BOBBYS_PLAQUES_Y + 32)
79 #define BOBBIES_USED_SIGN_WIDTH 92
80 #define BOBBIES_USED_SIGN_HEIGHT 50
81 #define BOBBIES_USED_SIGN_TEXT_OFFSET BOBBIES_USED_SIGN_Y + 10
82
83 #define BOBBIES_MISC_SIGN_X (UINT16)(BOBBYS_PLAQUES_X + 238)
84 #define BOBBIES_MISC_SIGN_Y (UINT16)(BOBBYS_PLAQUES_Y + 27)
85 #define BOBBIES_MISC_SIGN_WIDTH 103
86 #define BOBBIES_MISC_SIGN_HEIGHT 57
87 #define BOBBIES_MISC_SIGN_TEXT_OFFSET BOBBIES_MISC_SIGN_Y + BOBBIES_CENTER_SIGN_OFFSET_Y
88
89 #define BOBBIES_GUNS_SIGN_X (UINT16)(BOBBYS_PLAQUES_X + 3)
90 #define BOBBIES_GUNS_SIGN_Y (UINT16)(BOBBYS_PLAQUES_Y + 102)
91 #define BOBBIES_GUNS_SIGN_WIDTH 116
92 #define BOBBIES_GUNS_SIGN_HEIGHT 75
93 #define BOBBIES_GUNS_SIGN_TEXT_OFFSET BOBBIES_GUNS_SIGN_Y + BOBBIES_CENTER_SIGN_OFFSET_Y
94
95 #define BOBBIES_AMMO_SIGN_X (UINT16)(BOBBYS_PLAQUES_X + 150)
96 #define BOBBIES_AMMO_SIGN_Y (UINT16)(BOBBYS_PLAQUES_Y + 105)
97 #define BOBBIES_AMMO_SIGN_WIDTH 112
98 #define BOBBIES_AMMO_SIGN_HEIGHT 71
99 #define BOBBIES_AMMO_SIGN_TEXT_OFFSET BOBBIES_AMMO_SIGN_Y + BOBBIES_CENTER_SIGN_OFFSET_Y
100
101 #define BOBBIES_ARMOUR_SIGN_X (UINT16)(BOBBYS_PLAQUES_X + 290)
102 #define BOBBIES_ARMOUR_SIGN_Y (UINT16)(BOBBYS_PLAQUES_Y + 108)
103 #define BOBBIES_ARMOUR_SIGN_WIDTH 114
104 #define BOBBIES_ARMOUR_SIGN_HEIGHT 70
105 #define BOBBIES_ARMOUR_SIGN_TEXT_OFFSET BOBBIES_ARMOUR_SIGN_Y + BOBBIES_CENTER_SIGN_OFFSET_Y
106
107 #define BOBBIES_3RD_SENTENCE_X LAPTOP_SCREEN_UL_X
108 #define BOBBIES_3RD_SENTENCE_Y BOBBIES_BOTTOMHINGE_Y + 40
109 #define BOBBIES_3RD_SENTENCE_WIDTH 500
110
111 #define BOBBY_R_NEW_PURCHASE_ARRIVAL_TIME (1 * 60 * 24) // minutes in 1 day
112
113 #define BOBBY_R_USED_PURCHASE_OFFSET 1000
114
115 #define BOBBYR_UNDERCONSTRUCTION_ANI_DELAY 150
116 #define BOBBYR_UNDERCONSTRUCTION_NUM_FRAMES 5
117
118 #define BOBBYR_UNDERCONSTRUCTION_X LAPTOP_SCREEN_UL_X + ( LAPTOP_SCREEN_LR_X - LAPTOP_SCREEN_UL_X - BOBBYR_UNDERCONSTRUCTION_WIDTH ) / 2
119 #define BOBBYR_UNDERCONSTRUCTION_Y 175
120 #define BOBBYR_UNDERCONSTRUCTION1_Y 378
121
122 #define BOBBYR_UNDERCONSTRUCTION_WIDTH 414
123 #define BOBBYR_UNDERCONSTRUCTION_HEIGHT 64
124
125 #define BOBBYR_UNDER_CONSTRUCTION_TEXT_X LAPTOP_SCREEN_UL_X
126 #define BOBBYR_UNDER_CONSTRUCTION_TEXT_Y BOBBYR_UNDERCONSTRUCTION_Y + 62 + 60
127 #define BOBBYR_UNDER_CONSTRUCTION_TEXT_WIDTH LAPTOP_SCREEN_LR_X - LAPTOP_SCREEN_UL_X
128
129
130 static SGPVObject* guiBobbyName;
131 static SGPVObject* guiPlaque;
132 static SGPVObject* guiTopHinge;
133 static SGPVObject* guiBottomHinge;
134 static SGPVObject* guiStorePlaque;
135 static SGPVObject* guiHandle;
136 static SGPVObject* guiWoodBackground;
137 static SGPVObject* guiUnderConstructionImage;
138
139
140 LaptopMode guiLastBobbyRayPage;
141
142
143 static LaptopMode const gubBobbyRPages[] =
144 {
145 LAPTOP_MODE_BOBBY_R_USED,
146 LAPTOP_MODE_BOBBY_R_MISC,
147 LAPTOP_MODE_BOBBY_R_GUNS,
148 LAPTOP_MODE_BOBBY_R_AMMO,
149 LAPTOP_MODE_BOBBY_R_ARMOR
150 };
151
152
153 //Bobby's Sign menu mouse regions
154 static MOUSE_REGION gSelectedBobbiesSignMenuRegion[BOBBIES_NUMBER_SIGNS];
155
156
157 static void HandleBobbyRUnderConstructionAni(BOOLEAN fReset);
158 static void InitBobbiesMouseRegion(UINT8 ubNumerRegions, UINT16* usMouseRegionPosArray, MOUSE_REGION* MouseRegion);
159
160
EnterBobbyR()161 void EnterBobbyR()
162 {
163 UINT8 i;
164
165 // an array of mouse regions for the bobbies signs. Top Left corner, bottom right corner
166 UINT16 usMouseRegionPosArray[] = {
167 BOBBIES_USED_SIGN_X,
168 BOBBIES_USED_SIGN_Y,
169 (UINT16)(BOBBIES_USED_SIGN_X+BOBBIES_USED_SIGN_WIDTH),
170 (UINT16)(BOBBIES_USED_SIGN_Y+BOBBIES_USED_SIGN_HEIGHT),
171 BOBBIES_MISC_SIGN_X,
172 BOBBIES_MISC_SIGN_Y,
173 (UINT16)(BOBBIES_MISC_SIGN_X+BOBBIES_MISC_SIGN_WIDTH),
174 (UINT16)(BOBBIES_MISC_SIGN_Y+BOBBIES_MISC_SIGN_HEIGHT),
175 BOBBIES_GUNS_SIGN_X,
176 BOBBIES_GUNS_SIGN_Y,
177 (UINT16)(BOBBIES_GUNS_SIGN_X+BOBBIES_GUNS_SIGN_WIDTH),
178 (UINT16)(BOBBIES_GUNS_SIGN_Y+BOBBIES_GUNS_SIGN_HEIGHT),
179 BOBBIES_AMMO_SIGN_X,
180 BOBBIES_AMMO_SIGN_Y,
181 (UINT16)(BOBBIES_AMMO_SIGN_X+BOBBIES_AMMO_SIGN_WIDTH),
182 (UINT16)(BOBBIES_AMMO_SIGN_Y+BOBBIES_AMMO_SIGN_HEIGHT),
183 BOBBIES_ARMOUR_SIGN_X,
184 BOBBIES_ARMOUR_SIGN_Y,
185 (UINT16)(BOBBIES_ARMOUR_SIGN_X+BOBBIES_ARMOUR_SIGN_WIDTH),
186 (UINT16)(BOBBIES_ARMOUR_SIGN_Y+BOBBIES_ARMOUR_SIGN_HEIGHT)
187 };
188
189 InitBobbyRWoodBackground();
190
191 const char* ImageFile;
192
193 // load the Bobbyname graphic and add it
194 ImageFile = GetMLGFilename(MLG_BOBBYNAME);
195 guiBobbyName = AddVideoObjectFromFile(ImageFile);
196
197 // load the plaque graphic and add it
198 guiPlaque = AddVideoObjectFromFile(LAPTOPDIR "/bobbyplaques.sti");
199
200 // load the TopHinge graphic and add it
201 guiTopHinge = AddVideoObjectFromFile(LAPTOPDIR "/bobbytophinge.sti");
202
203 // load the BottomHinge graphic and add it
204 guiBottomHinge = AddVideoObjectFromFile(LAPTOPDIR "/bobbybottomhinge.sti");
205
206 // load the Store Plaque graphic and add it
207 ImageFile = GetMLGFilename(MLG_STOREPLAQUE);
208 guiStorePlaque = AddVideoObjectFromFile(ImageFile);
209
210 // load the Handle graphic and add it
211 guiHandle = AddVideoObjectFromFile(LAPTOPDIR "/bobbyhandle.sti");
212
213
214 InitBobbiesMouseRegion(BOBBIES_NUMBER_SIGNS, usMouseRegionPosArray, gSelectedBobbiesSignMenuRegion);
215
216
217 if( !LaptopSaveInfo.fBobbyRSiteCanBeAccessed )
218 {
219 // load the Handle graphic and add it
220 guiUnderConstructionImage = AddVideoObjectFromFile(LAPTOPDIR "/underconstruction.sti");
221
222 for(i=0; i<BOBBIES_NUMBER_SIGNS; i++)
223 {
224 gSelectedBobbiesSignMenuRegion[i].Disable();
225 }
226
227 LaptopSaveInfo.ubHaveBeenToBobbyRaysAtLeastOnceWhileUnderConstruction = BOBBYR_BEEN_TO_SITE_ONCE;
228 }
229
230
231 SetBookMark(BOBBYR_BOOKMARK);
232 HandleBobbyRUnderConstructionAni( TRUE );
233
234 RenderBobbyR();
235 }
236
237
ExitBobbyR()238 void ExitBobbyR()
239 {
240
241 DeleteVideoObject(guiBobbyName);
242 DeleteVideoObject(guiPlaque);
243 DeleteVideoObject(guiTopHinge);
244 DeleteVideoObject(guiBottomHinge);
245 DeleteVideoObject(guiStorePlaque);
246 DeleteVideoObject(guiHandle);
247
248 if( !LaptopSaveInfo.fBobbyRSiteCanBeAccessed )
249 {
250 DeleteVideoObject(guiUnderConstructionImage);
251 }
252
253
254 DeleteBobbyRWoodBackground();
255
256 FOR_EACH(MOUSE_REGION, i, gSelectedBobbiesSignMenuRegion) MSYS_RemoveRegion(&*i);
257
258 guiLastBobbyRayPage = LAPTOP_MODE_BOBBY_R;
259 }
260
HandleBobbyR()261 void HandleBobbyR()
262 {
263 HandleBobbyRUnderConstructionAni( FALSE );
264 }
265
RenderBobbyR()266 void RenderBobbyR()
267 {
268 DrawBobbyRWoodBackground();
269
270 BltVideoObject(FRAME_BUFFER, guiBobbyName, 0, BOBBY_RAYS_NAME_X, BOBBY_RAYS_NAME_Y);
271 BltVideoObject(FRAME_BUFFER, guiPlaque, 0, BOBBYS_PLAQUES_X, BOBBYS_PLAQUES_Y);
272 BltVideoObject(FRAME_BUFFER, guiTopHinge, 0, BOBBIES_TOPHINGE_X, BOBBIES_TOPHINGE_Y);
273 BltVideoObject(FRAME_BUFFER, guiBottomHinge, 0, BOBBIES_BOTTOMHINGE_X, BOBBIES_BOTTOMHINGE_Y);
274 BltVideoObject(FRAME_BUFFER, guiStorePlaque, 0, BOBBIES_STORE_PLAQUE_X, BOBBIES_STORE_PLAQUE_Y);
275 BltVideoObject(FRAME_BUFFER, guiHandle, 0, BOBBIES_HANDLE_X, BOBBIES_HANDLE_Y);
276
277 SetFontShadow(BOBBIES_SENTENCE_BACKGROUNDCOLOR);
278
279
280 if( LaptopSaveInfo.fBobbyRSiteCanBeAccessed )
281 {
282 //Bobbys first sentence
283 //ShadowText( FRAME_BUFFER, BobbyRaysFrontText[BOBBYR_ADVERTISMENT_1], BOBBIES_SENTENCE_FONT, BOBBIES_FIRST_SENTENCE_X, BOBBIES_FIRST_SENTENCE_Y );
284 DrawTextToScreen(BobbyRaysFrontText[BOBBYR_ADVERTISMENT_1], BOBBIES_FIRST_SENTENCE_X, BOBBIES_FIRST_SENTENCE_Y, BOBBIES_FIRST_SENTENCE_WIDTH, BOBBIES_SENTENCE_FONT, BOBBIES_SENTENCE_COLOR, BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED | TEXT_SHADOWED);
285
286 //Bobbys second sentence
287 DrawTextToScreen(BobbyRaysFrontText[BOBBYR_ADVERTISMENT_2], BOBBIES_2ND_SENTENCE_X, BOBBIES_2ND_SENTENCE_Y, BOBBIES_2ND_SENTENCE_WIDTH, BOBBIES_SENTENCE_FONT, BOBBIES_SENTENCE_COLOR, BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED | TEXT_SHADOWED);
288 }
289
290
291 SetFontShadow(BOBBIES_SIGN_BACKGROUNDCOLOR);
292 //Text on the Used Sign
293 DisplayWrappedString(BOBBIES_USED_SIGN_X, BOBBIES_USED_SIGN_TEXT_OFFSET, BOBBIES_USED_SIGN_WIDTH - 5, 2, BOBBIES_SIGN_FONT, BOBBIES_SIGN_COLOR, BobbyRaysFrontText[BOBBYR_USED], BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED);
294 //Text on the Misc Sign
295 DisplayWrappedString(BOBBIES_MISC_SIGN_X, BOBBIES_MISC_SIGN_TEXT_OFFSET, BOBBIES_MISC_SIGN_WIDTH, 2, BOBBIES_SIGN_FONT, BOBBIES_SIGN_COLOR, BobbyRaysFrontText[BOBBYR_MISC], BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED);
296 //Text on the Guns Sign
297 DisplayWrappedString(BOBBIES_GUNS_SIGN_X, BOBBIES_GUNS_SIGN_TEXT_OFFSET, BOBBIES_GUNS_SIGN_WIDTH, 2, BOBBIES_SIGN_FONT, BOBBIES_SIGN_COLOR, BobbyRaysFrontText[BOBBYR_GUNS], BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED);
298 //Text on the Ammo Sign
299 DisplayWrappedString(BOBBIES_AMMO_SIGN_X, BOBBIES_AMMO_SIGN_TEXT_OFFSET, BOBBIES_AMMO_SIGN_WIDTH, 2, BOBBIES_SIGN_FONT, BOBBIES_SIGN_COLOR, BobbyRaysFrontText[BOBBYR_AMMO], BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED);
300 //Text on the Armour Sign
301 DisplayWrappedString(BOBBIES_ARMOUR_SIGN_X, BOBBIES_ARMOUR_SIGN_TEXT_OFFSET, BOBBIES_ARMOUR_SIGN_WIDTH, 2, BOBBIES_SIGN_FONT, BOBBIES_SIGN_COLOR, BobbyRaysFrontText[BOBBYR_ARMOR], BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED);
302
303 if( LaptopSaveInfo.fBobbyRSiteCanBeAccessed )
304 {
305 //Bobbys Third sentence
306 SetFontShadow(BOBBIES_SENTENCE_BACKGROUNDCOLOR);
307 DrawTextToScreen(BobbyRaysFrontText[BOBBYR_ADVERTISMENT_3], BOBBIES_3RD_SENTENCE_X, BOBBIES_3RD_SENTENCE_Y, BOBBIES_3RD_SENTENCE_WIDTH, BOBBIES_SENTENCE_FONT, BOBBIES_SENTENCE_COLOR, BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED | TEXT_SHADOWED);
308 }
309
310 SetFontShadow(DEFAULT_SHADOW);
311
312 //if we cant go to any sub pages, darken the page out
313 if( !LaptopSaveInfo.fBobbyRSiteCanBeAccessed )
314 {
315 FRAME_BUFFER->ShadowRect(LAPTOP_SCREEN_UL_X, LAPTOP_SCREEN_WEB_UL_Y, LAPTOP_SCREEN_LR_X, LAPTOP_SCREEN_WEB_LR_Y);
316 }
317
318 RenderWWWProgramTitleBar( );
319 InvalidateRegion(LAPTOP_SCREEN_UL_X,LAPTOP_SCREEN_WEB_UL_Y,LAPTOP_SCREEN_LR_X,LAPTOP_SCREEN_WEB_LR_Y);
320 }
321
322
InitBobbyRWoodBackground()323 void InitBobbyRWoodBackground()
324 {
325 // load the Wood bacground graphic and add it
326 guiWoodBackground = AddVideoObjectFromFile(LAPTOPDIR "/bobbywood.sti");
327 }
328
329
DeleteBobbyRWoodBackground()330 void DeleteBobbyRWoodBackground()
331 {
332 DeleteVideoObject(guiWoodBackground);
333 }
334
335
DrawBobbyRWoodBackground()336 void DrawBobbyRWoodBackground()
337 {
338 UINT16 x,y, uiPosX, uiPosY;
339
340 uiPosY = BOBBY_WOOD_BACKGROUND_Y;
341 for(y=0; y<4; y++)
342 {
343 uiPosX = BOBBY_WOOD_BACKGROUND_X;
344 for(x=0; x<4; x++)
345 {
346 BltVideoObject(FRAME_BUFFER, guiWoodBackground, 0, uiPosX, uiPosY);
347 uiPosX += BOBBY_WOOD_BACKGROUND_WIDTH;
348 }
349 uiPosY += BOBBY_WOOD_BACKGROUND_HEIGHT;
350 }
351 }
352
353
354 static void SelectBobbiesSignMenuRegionCallBack(MOUSE_REGION* pRegion, INT32 iReason);
355
356
InitBobbiesMouseRegion(UINT8 ubNumerRegions,UINT16 * usMouseRegionPosArray,MOUSE_REGION * MouseRegion)357 static void InitBobbiesMouseRegion(UINT8 ubNumerRegions, UINT16* usMouseRegionPosArray, MOUSE_REGION* MouseRegion)
358 {
359 UINT8 i,ubCount=0;
360
361 for(i=0; i<ubNumerRegions; i++)
362 {
363 //Mouse region for the toc buttons
364 MSYS_DefineRegion(&MouseRegion[i], usMouseRegionPosArray[ubCount], usMouseRegionPosArray[ubCount+1],
365 usMouseRegionPosArray[ubCount+2], usMouseRegionPosArray[ubCount+3],
366 MSYS_PRIORITY_HIGH, CURSOR_WWW, MSYS_NO_CALLBACK,
367 SelectBobbiesSignMenuRegionCallBack);
368 MSYS_SetRegionUserData( &MouseRegion[i], 0, gubBobbyRPages[i]);
369
370 ubCount +=4;
371 }
372 }
373
374
SelectBobbiesSignMenuRegionCallBack(MOUSE_REGION * pRegion,INT32 iReason)375 static void SelectBobbiesSignMenuRegionCallBack(MOUSE_REGION* pRegion, INT32 iReason)
376 {
377 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
378 {
379 guiCurrentLaptopMode = static_cast<LaptopMode>(MSYS_GetRegionUserData(pRegion, 0));
380 }
381 }
382
383
HandleBobbyRUnderConstructionAni(BOOLEAN fReset)384 static void HandleBobbyRUnderConstructionAni(BOOLEAN fReset)
385 {
386 static UINT32 uiLastTime=1;
387 static UINT16 usCount=0;
388 UINT32 uiCurTime=GetJA2Clock();
389
390
391 if( LaptopSaveInfo.fBobbyRSiteCanBeAccessed )
392 return;
393
394 if( fReset )
395 usCount =1;
396
397 if( fShowBookmarkInfo )
398 {
399 fReDrawBookMarkInfo = TRUE;
400 }
401
402 if( ( ( uiCurTime - uiLastTime ) > BOBBYR_UNDERCONSTRUCTION_ANI_DELAY )||( fReDrawScreenFlag ) )
403 {
404 // The undercontsruction graphic
405 BltVideoObject(FRAME_BUFFER, guiUnderConstructionImage, usCount, BOBBYR_UNDERCONSTRUCTION_X, BOBBYR_UNDERCONSTRUCTION_Y);
406 BltVideoObject(FRAME_BUFFER, guiUnderConstructionImage, usCount, BOBBYR_UNDERCONSTRUCTION_X, BOBBYR_UNDERCONSTRUCTION1_Y);
407
408 DrawTextToScreen(BobbyRaysFrontText[BOBBYR_UNDER_CONSTRUCTION], BOBBYR_UNDER_CONSTRUCTION_TEXT_X, BOBBYR_UNDER_CONSTRUCTION_TEXT_Y, BOBBYR_UNDER_CONSTRUCTION_TEXT_WIDTH, FONT16ARIAL, BOBBIES_SENTENCE_COLOR, BOBBIES_SIGN_BACKCOLOR, CENTER_JUSTIFIED | INVALIDATE_TEXT);
409
410 InvalidateRegion( BOBBYR_UNDERCONSTRUCTION_X, BOBBYR_UNDERCONSTRUCTION_Y, BOBBYR_UNDERCONSTRUCTION_X+BOBBYR_UNDERCONSTRUCTION_WIDTH, BOBBYR_UNDERCONSTRUCTION_Y+BOBBYR_UNDERCONSTRUCTION_HEIGHT );
411 InvalidateRegion( BOBBYR_UNDERCONSTRUCTION_X, BOBBYR_UNDERCONSTRUCTION1_Y, BOBBYR_UNDERCONSTRUCTION_X+BOBBYR_UNDERCONSTRUCTION_WIDTH, BOBBYR_UNDERCONSTRUCTION1_Y+BOBBYR_UNDERCONSTRUCTION_HEIGHT );
412
413 uiLastTime = GetJA2Clock();
414
415 usCount++;
416
417 if( usCount >= BOBBYR_UNDERCONSTRUCTION_NUM_FRAMES )
418 usCount = 0;
419 }
420 }
421
422
423 static void InitBobbyRayNewInventory(void);
424 static void InitBobbyRayUsedInventory(void);
425
426
InitBobbyRayInventory()427 void InitBobbyRayInventory()
428 {
429 //Initializes which NEW items can be bought at Bobby Rays
430 InitBobbyRayNewInventory();
431
432 //Initializes the starting values for Bobby Rays NEW Inventory
433 SetupStoreInventory( LaptopSaveInfo.BobbyRayInventory, FALSE );
434
435 //Initializes which USED items can be bought at Bobby Rays
436 InitBobbyRayUsedInventory();
437
438 //Initializes the starting values for Bobby Rays USED Inventory
439 SetupStoreInventory( LaptopSaveInfo.BobbyRayUsedInventory, TRUE);
440 }
441
442
InitBobbyRayNewInventory(void)443 static void InitBobbyRayNewInventory(void)
444 {
445 UINT16 i;
446 UINT16 usBobbyrIndex = 0;
447
448
449 std::fill_n(LaptopSaveInfo.BobbyRayInventory, static_cast<size_t>(MAXITEMS), STORE_INVENTORY{});
450
451 // add all the NEW items he can ever sell into his possible inventory list, for now in order by item #
452 for( i = 0; i < MAXITEMS; i++ )
453 {
454 const ItemModel *item = GCM->getItem(i);
455 //if Bobby Ray sells this, it can be sold, and it's allowed into this game (some depend on e.g. gun-nut option)
456 if( (GCM->getBobbyRayNewInventory()->getMaxItemAmount(item) != 0) && !(item->getFlags() & ITEM_NOT_BUYABLE) && ItemIsLegal( i ) )
457 {
458 LaptopSaveInfo.BobbyRayInventory[ usBobbyrIndex ].usItemIndex = i;
459 usBobbyrIndex++;
460 }
461 }
462
463 if ( usBobbyrIndex > 1 )
464 {
465 // sort this list by object category, and by ascending price within each category
466 qsort( LaptopSaveInfo.BobbyRayInventory, usBobbyrIndex, sizeof( STORE_INVENTORY ), BobbyRayItemQsortCompare );
467 }
468
469
470 // remember how many entries in the list are valid
471 LaptopSaveInfo.usInventoryListLength[ BOBBY_RAY_NEW ] = usBobbyrIndex;
472 // also mark the end of the list of valid item entries
473 LaptopSaveInfo.BobbyRayInventory[ usBobbyrIndex ].usItemIndex = BOBBYR_NO_ITEMS;
474 }
475
476
InitBobbyRayUsedInventory(void)477 static void InitBobbyRayUsedInventory(void)
478 {
479 UINT16 i;
480 UINT16 usBobbyrIndex = 0;
481
482
483 std::fill_n(LaptopSaveInfo.BobbyRayUsedInventory, static_cast<size_t>(MAXITEMS), STORE_INVENTORY{});
484
485 // add all the NEW items he can ever sell into his possible inventory list, for now in order by item #
486 for( i = 0; i < MAXITEMS; i++ )
487 {
488 const ItemModel *item = GCM->getItem(i);
489
490 //if Bobby Ray sells this, it can be sold, and it's allowed into this game (some depend on e.g. gun-nut option)
491 if( (GCM->getBobbyRayUsedInventory()->getMaxItemAmount(item) != 0) && !(item->getFlags() & ITEM_NOT_BUYABLE) && ItemIsLegal( i ) )
492 {
493 // in case his store inventory list is wrong, make sure this category of item can be sold used
494 if ( CanDealerItemBeSoldUsed( i ) )
495 {
496 LaptopSaveInfo.BobbyRayUsedInventory[ usBobbyrIndex ].usItemIndex = i;
497 usBobbyrIndex++;
498 }
499 }
500 }
501
502 if ( usBobbyrIndex > 1 )
503 {
504 // sort this list by object category, and by ascending price within each category
505 qsort( LaptopSaveInfo.BobbyRayUsedInventory, usBobbyrIndex, sizeof( STORE_INVENTORY ), BobbyRayItemQsortCompare );
506 }
507
508 // remember how many entries in the list are valid
509 LaptopSaveInfo.usInventoryListLength[BOBBY_RAY_USED] = usBobbyrIndex;
510 // also mark the end of the list of valid item entries
511 LaptopSaveInfo.BobbyRayUsedInventory[ usBobbyrIndex ].usItemIndex = BOBBYR_NO_ITEMS;
512 }
513
514
515 static UINT8 HowManyBRItemsToOrder(UINT16 usItemIndex, UINT8 ubCurrentlyOnHand, UINT8 ubBobbyRayNewUsed);
516 static void OrderBobbyRItem(UINT16 usItemIndex);
517 static void SimulateBobbyRayCustomer(STORE_INVENTORY* pInventoryArray, BOOLEAN fUsed);
518
519
DailyUpdateOfBobbyRaysNewInventory()520 void DailyUpdateOfBobbyRaysNewInventory()
521 {
522 INT16 i;
523 UINT16 usItemIndex;
524 BOOLEAN fPrevElig;
525
526
527 //simulate other buyers by reducing the current quantity on hand
528 SimulateBobbyRayCustomer(LaptopSaveInfo.BobbyRayInventory, BOBBY_RAY_NEW);
529
530 //loop through all items BR can stock to see what needs reordering
531 for(i = 0; i < LaptopSaveInfo.usInventoryListLength[BOBBY_RAY_NEW]; i++)
532 {
533 // the index is NOT the item #, get that from the table
534 usItemIndex = LaptopSaveInfo.BobbyRayInventory[ i ].usItemIndex;
535 const ItemModel *item = GCM->getItem(usItemIndex);
536
537 Assert(usItemIndex < MAXITEMS);
538
539 // make sure this item is still sellable in the latest version of the store inventory
540 if (GCM->getBobbyRayNewInventory()->getMaxItemAmount(item) == 0 )
541 {
542 continue;
543 }
544
545 //if the item isn't already on order
546 if( LaptopSaveInfo.BobbyRayInventory[ i ].ubQtyOnOrder == 0)
547 {
548 //if the qty on hand is half the desired amount or fewer
549 if( LaptopSaveInfo.BobbyRayInventory[ i ].ubQtyOnHand <= (GCM->getBobbyRayNewInventory()->getMaxItemAmount(item) / 2 ) )
550 {
551 // remember value of the "previously eligible" flag
552 fPrevElig = LaptopSaveInfo.BobbyRayInventory[ i ].fPreviouslyEligible;
553
554 //determine if any can/should be ordered, and how many
555 LaptopSaveInfo.BobbyRayInventory[ i ].ubQtyOnOrder = HowManyBRItemsToOrder( usItemIndex, LaptopSaveInfo.BobbyRayInventory[ i ].ubQtyOnHand, BOBBY_RAY_NEW);
556
557 //if he found some to buy
558 if( LaptopSaveInfo.BobbyRayInventory[ i ].ubQtyOnOrder > 0 )
559 {
560 // if this is the first day the player is eligible to have access to this thing
561 if ( !fPrevElig )
562 {
563 // eliminate the ordering delay and stock the items instantly!
564 // This is just a way to reward the player right away for making progress without the reordering lag...
565 AddFreshBobbyRayInventory( usItemIndex );
566 }
567 else
568 {
569 OrderBobbyRItem(usItemIndex);
570 }
571 }
572 }
573 }
574 }
575 }
576
577
DailyUpdateOfBobbyRaysUsedInventory()578 void DailyUpdateOfBobbyRaysUsedInventory()
579 {
580 INT16 i;
581 UINT16 usItemIndex;
582 BOOLEAN fPrevElig;
583
584
585 //simulate other buyers by reducing the current quantity on hand
586 SimulateBobbyRayCustomer(LaptopSaveInfo.BobbyRayUsedInventory, BOBBY_RAY_USED);
587
588 for(i = 0; i < LaptopSaveInfo.usInventoryListLength[BOBBY_RAY_USED]; i++)
589 {
590 //if the used item isn't already on order
591 if( LaptopSaveInfo.BobbyRayUsedInventory[ i ].ubQtyOnOrder == 0 )
592 {
593 //if we don't have ANY
594 if( LaptopSaveInfo.BobbyRayUsedInventory[ i ].ubQtyOnHand == 0 )
595 {
596 // the index is NOT the item #, get that from the table
597 usItemIndex = LaptopSaveInfo.BobbyRayUsedInventory[ i ].usItemIndex;
598 Assert(usItemIndex < MAXITEMS);
599
600 // make sure this item is still sellable in the latest version of the store inventory
601 if (GCM->getBobbyRayUsedInventory()->getMaxItemAmount(GCM->getItem(usItemIndex)) == 0 )
602 {
603 continue;
604 }
605
606 // remember value of the "previously eligible" flag
607 fPrevElig = LaptopSaveInfo.BobbyRayUsedInventory[ i ].fPreviouslyEligible;
608
609 //determine if any can/should be ordered, and how many
610 LaptopSaveInfo.BobbyRayUsedInventory[ i ].ubQtyOnOrder = HowManyBRItemsToOrder(usItemIndex, LaptopSaveInfo.BobbyRayUsedInventory[ i ].ubQtyOnHand, BOBBY_RAY_USED);
611
612 //if he found some to buy
613 if( LaptopSaveInfo.BobbyRayUsedInventory[ i ].ubQtyOnOrder > 0 )
614 {
615 // if this is the first day the player is eligible to have access to this thing
616 if ( !fPrevElig )
617 {
618 // eliminate the ordering delay and stock the items instantly!
619 // This is just a way to reward the player right away for making progress without the reordering lag...
620 AddFreshBobbyRayInventory( usItemIndex );
621 }
622 else
623 {
624 OrderBobbyRItem((INT16) (usItemIndex + BOBBY_R_USED_PURCHASE_OFFSET));
625 }
626 }
627 }
628 }
629 }
630 }
631
632
633 //returns the number of items to order
HowManyBRItemsToOrder(UINT16 usItemIndex,UINT8 ubCurrentlyOnHand,UINT8 ubBobbyRayNewUsed)634 static UINT8 HowManyBRItemsToOrder(UINT16 usItemIndex, UINT8 ubCurrentlyOnHand, UINT8 ubBobbyRayNewUsed)
635 {
636 UINT8 ubItemsOrdered = 0;
637
638 const DealerInventory *inv = ubBobbyRayNewUsed ? GCM->getBobbyRayUsedInventory() : GCM->getBobbyRayNewInventory();
639 const ItemModel *item = GCM->getItem(usItemIndex);
640
641 Assert(usItemIndex < MAXITEMS);
642 // formulas below will fail if there are more items already in stock than optimal
643 Assert(ubCurrentlyOnHand <= inv->getMaxItemAmount(item));
644 Assert(ubBobbyRayNewUsed < BOBBY_RAY_LISTS);
645
646
647 // decide if he can get stock for this item (items are reordered an entire batch at a time)
648 if (ItemTransactionOccurs(ARMS_DEALER_BOBBYR, usItemIndex, DEALER_BUYING, ubBobbyRayNewUsed))
649 {
650 if (ubBobbyRayNewUsed == BOBBY_RAY_NEW)
651 {
652 ubItemsOrdered = HowManyItemsToReorder(inv->getMaxItemAmount(item), ubCurrentlyOnHand);
653 }
654 else
655 {
656 //Since these are used items we only should order 1 of each type
657 ubItemsOrdered = 1;
658 }
659 }
660 else
661 {
662 // can't obtain this item from suppliers
663 ubItemsOrdered = 0;
664 }
665
666
667 return(ubItemsOrdered);
668 }
669
670
OrderBobbyRItem(UINT16 usItemIndex)671 static void OrderBobbyRItem(UINT16 usItemIndex)
672 {
673 UINT32 uiArrivalTime;
674
675 //add the new item to the queue. The new item will arrive in 'uiArrivalTime' minutes.
676 uiArrivalTime = BOBBY_R_NEW_PURCHASE_ARRIVAL_TIME + Random( BOBBY_R_NEW_PURCHASE_ARRIVAL_TIME / 2 );
677 uiArrivalTime += GetWorldTotalMin();
678 AddStrategicEvent( EVENT_UPDATE_BOBBY_RAY_INVENTORY, uiArrivalTime, usItemIndex);
679 }
680
681
AddFreshBobbyRayInventory(UINT16 usItemIndex)682 void AddFreshBobbyRayInventory( UINT16 usItemIndex )
683 {
684 INT16 sInventorySlot;
685 STORE_INVENTORY *pInventoryArray;
686 BOOLEAN fUsed;
687 UINT8 ubItemQuality;
688
689
690 if( usItemIndex >= BOBBY_R_USED_PURCHASE_OFFSET )
691 {
692 usItemIndex -= BOBBY_R_USED_PURCHASE_OFFSET;
693 pInventoryArray = LaptopSaveInfo.BobbyRayUsedInventory;
694 fUsed = BOBBY_RAY_USED;
695 ubItemQuality = 20 + (UINT8) Random( 60 );
696 }
697 else
698 {
699 pInventoryArray = LaptopSaveInfo.BobbyRayInventory;
700 fUsed = BOBBY_RAY_NEW;
701 ubItemQuality = 100;
702 }
703
704
705 // find out which inventory slot that item is stored in
706 sInventorySlot = GetInventorySlotForItem(pInventoryArray, usItemIndex, fUsed);
707 if (sInventorySlot == -1)
708 {
709 AssertMsg( FALSE, String( "AddFreshBobbyRayInventory(), Item %d not found. AM-0.", usItemIndex ) );
710 return;
711 }
712
713
714 pInventoryArray[ sInventorySlot ].ubQtyOnHand += pInventoryArray[ sInventorySlot ].ubQtyOnOrder;
715 pInventoryArray[ sInventorySlot ].ubItemQuality = ubItemQuality;
716
717 // cancel order
718 pInventoryArray[ sInventorySlot ].ubQtyOnOrder = 0;
719 }
720
721
GetInventorySlotForItem(STORE_INVENTORY * pInventoryArray,UINT16 usItemIndex,BOOLEAN fUsed)722 INT16 GetInventorySlotForItem(STORE_INVENTORY *pInventoryArray, UINT16 usItemIndex, BOOLEAN fUsed)
723 {
724 INT16 i;
725
726 for(i = 0; i < LaptopSaveInfo.usInventoryListLength[fUsed]; i++)
727 {
728 //if we have some of this item in stock
729 if( pInventoryArray[ i ].usItemIndex == usItemIndex)
730 {
731 return(i);
732 }
733 }
734
735 // not found!
736 return(-1);
737 }
738
739
SimulateBobbyRayCustomer(STORE_INVENTORY * pInventoryArray,BOOLEAN fUsed)740 static void SimulateBobbyRayCustomer(STORE_INVENTORY* pInventoryArray, BOOLEAN fUsed)
741 {
742 INT16 i;
743 UINT8 ubItemsSold;
744
745 //loop through all items BR can stock to see what gets sold
746 for(i = 0; i < LaptopSaveInfo.usInventoryListLength[fUsed]; i++)
747 {
748 //if we have some of this item in stock
749 if( pInventoryArray[ i ].ubQtyOnHand > 0)
750 {
751 ubItemsSold = HowManyItemsAreSold(ARMS_DEALER_BOBBYR, pInventoryArray[i].usItemIndex, pInventoryArray[i].ubQtyOnHand, fUsed);
752 pInventoryArray[ i ].ubQtyOnHand -= ubItemsSold;
753 }
754 }
755 }
756
757
CancelAllPendingBRPurchaseOrders(void)758 void CancelAllPendingBRPurchaseOrders(void)
759 {
760 INT16 i;
761
762 // remove all the BR-Order events off the event queue
763 DeleteAllStrategicEventsOfType( EVENT_UPDATE_BOBBY_RAY_INVENTORY );
764
765 // zero out all the quantities on order
766 for(i = 0; i < MAXITEMS; i++)
767 {
768 LaptopSaveInfo.BobbyRayInventory[ i ].ubQtyOnOrder = 0;
769 LaptopSaveInfo.BobbyRayUsedInventory[ i ].ubQtyOnOrder = 0;
770 }
771
772 // do an extra daily update immediately to create new reorders ASAP
773 DailyUpdateOfBobbyRaysNewInventory();
774 DailyUpdateOfBobbyRaysUsedInventory();
775 }
776