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