1 /////////////////////////////////////////
2 //
3 //             OpenLieroX
4 //
5 // code under LGPL, based on JasonBs work,
6 // enhanced by Dark Charlie and Albert Zeyer
7 //
8 //
9 /////////////////////////////////////////
10 
11 
12 // Local menu
13 // Created 30/6/02
14 // Jason Boettcher
15 
16 
17 #include <assert.h>
18 #include <string>
19 
20 #include "LieroX.h"
21 #include "CGameScript.h"
22 #include "AuxLib.h"
23 #include "DeprecatedGUI/Graphics.h"
24 #include "CClient.h"
25 #include "CServer.h"
26 #include "DeprecatedGUI/Menu.h"
27 #include "DeprecatedGUI/CListview.h"
28 #include "GfxPrimitives.h"
29 #include "FindFile.h"
30 #include "StringUtils.h"
31 #include "DeprecatedGUI/CButton.h"
32 #include "DeprecatedGUI/CLabel.h"
33 #include "DeprecatedGUI/CImage.h"
34 #include "DeprecatedGUI/CTextbox.h"
35 #include "DeprecatedGUI/CSlider.h"
36 #include "DeprecatedGUI/CCheckbox.h"
37 #include "DeprecatedGUI/CTextButton.h"
38 #include "DeprecatedGUI/CListview.h"
39 #include "DeprecatedGUI/CGuiSkinnedLayout.h"
40 #include "DeprecatedGUI/CBrowser.h"
41 #include "Sounds.h"
42 #include "ProfileSystem.h"
43 #include "FeatureList.h"
44 #include "Options.h"
45 #include "CGameMode.h"
46 
47 
48 namespace DeprecatedGUI {
49 
50 /*
51 =======================
52 
53   Weapons Restrictions
54 
55  For both local & host
56 
57 =======================
58 */
59 
60 
61 CGuiLayout		cWeaponsRest;
62 static CWpnRest        cWpnRestList;
63 static CGameScript     *cWpnGameScript = NULL;
64 
65 // State strings
66 static const std::string szStates[] = {"Enabled", "Bonus", "Banned"};
67 
68 // Weapons Restrictions
69 enum {
70 	wr_Ok,
71     wr_Reset,
72 	wr_ListBox,
73 	wr_Cancel,
74     wr_Random,
75 	wr_Load,
76 	wr_Save,
77 	wr_List,
78 };
79 
80 static std::list<wpnrest_t *> tWeaponList;
81 
82 /////////////////
83 // Updates the weapon list that is shown in the dialog
UpdateWeaponList()84 static void UpdateWeaponList()
85 {
86 	tWeaponList.clear();
87 	wpnrest_t *psWpn = cWpnRestList.getList();
88 	if (!psWpn)
89 		return;
90 
91 	for(int i=0; i < cWpnRestList.getNumWeapons(); i++) {
92         if(cWpnGameScript->weaponExists(psWpn[i].psLink->szName))
93 			tWeaponList.push_back(&psWpn[i]);
94     }
95 }
96 
UpdateWeaponListWidget()97 static void UpdateWeaponListWidget()
98 {
99 	const Color cStateColours[] = { tLX->clNormalLabel, tLX->clSubHeading, tLX->clDisabled };
100 
101 	int idx = 0;
102 	CListview *listWidget = dynamic_cast<CListview *>(cWeaponsRest.getWidget(wr_List));
103 	if (!listWidget)
104 		return;
105 	listWidget->Clear();
106 	for (auto weapon: tWeaponList) {
107 		std::string buf = weapon->psLink->szName;
108 		stripdot(buf,245);
109 		listWidget->AddItem(buf, idx, tLX->clNormalLabel);
110 		listWidget->AddSubitem(buf);
111 		listWidget->AddSubitem(szStates[weapon->psLink->nState], VALIGN_MIDDLE, cStateColours[weapon->psLink->nState]);
112 		idx++;
113 	}
114 }
115 
116 ///////////////////
117 // Initialize the weapons restrictions
Menu_WeaponsRestrictions(const std::string & szMod)118 void Menu_WeaponsRestrictions(const std::string& szMod)
119 {
120 
121 	// Setup the buffer
122 	DrawImageAdv(tMenu->bmpBuffer.get(), tMenu->bmpMainBack_common, 120,150,120,150, 400,330);
123 	Menu_DrawBox(tMenu->bmpBuffer.get(), 120,150, 520,470);
124 	//DrawRectFillA(tMenu->bmpBuffer, 122,152, 518,438, 0, 100);
125 
126 
127 	Menu_RedrawMouse(true);
128 
129 	cWeaponsRest.Initialize();
130 	cWeaponsRest.Add( new CLabel("Weapon Options", tLX->clNormalLabel),     -1,        275,155, 0, 0);
131     cWeaponsRest.Add( new CButton(BUT_RESET, tMenu->bmpButtons),wr_Reset,  180,420, 60,15);
132     cWeaponsRest.Add( new CButton(BUT_RANDOM, tMenu->bmpButtons),wr_Random,280,420, 80,15);
133     cWeaponsRest.Add( new CButton(BUT_OK, tMenu->bmpButtons),	wr_Ok,     400,420, 30,15);
134     cWeaponsRest.Add( new CButton(BUT_LOAD, tMenu->bmpButtons),	wr_Load,   250,445, 60,15);
135     cWeaponsRest.Add( new CButton(BUT_SAVE, tMenu->bmpButtons),	wr_Save,   330,445, 60,15);
136 	CListview * listWidget = new CListview();
137 	cWeaponsRest.Add( listWidget,                               wr_List,   180,185, 320,230);
138 	listWidget->AddColumn("", 240);
139 	listWidget->AddColumn("", 55);
140 
141     // Load the weapons
142     cWpnRestList.loadList("cfg/wpnrest.dat");
143 
144 
145     //
146     // Update the list with the currently selected mod
147     //
148 
149     cWpnGameScript = new CGameScript;
150     if( cWpnGameScript ) {
151         if( cWpnGameScript->Load(szMod) )
152             cWpnRestList.updateList( cWpnGameScript );
153     }
154 
155     // Get the weapons for the list
156 	UpdateWeaponList();
157 	UpdateWeaponListWidget();
158 }
159 
160 //////////////////
161 // Shutdown the weapon restrictions
Menu_WeaponsRestrictionsShutdown()162 void Menu_WeaponsRestrictionsShutdown()
163 {
164 	cWeaponsRest.Shutdown();
165 
166     cWpnRestList.saveList("cfg/wpnrest.dat");
167     cWpnRestList.Shutdown();
168 
169 	if (cWpnGameScript)  {
170 		// HINT: the gamescript is shut down by the cache
171 		delete cWpnGameScript;
172 		cWpnGameScript = NULL;
173 	}
174 }
175 
176 
177 ///////////////////
178 // Weapons Restrictions frame
179 // Returns whether or not we have finished with the weapons restrictions
Menu_WeaponsRestrictions_Frame()180 bool Menu_WeaponsRestrictions_Frame()
181 {
182 	gui_event_t *ev = NULL;
183     //Uint32 blue = MakeColour(0,138,251);
184 
185     assert(cWpnGameScript);
186 
187 
188 	DrawImageAdv(VideoPostProcessor::videoSurface(), tMenu->bmpBuffer, 120,150, 120,150, 400,300);
189 
190 	/*
191     // Draw the list
192     int count = cWeaponsRest.SendMessage(wr_Scroll, SCM_GETVALUE,(DWORD)0,0);
193 
194 	int w, j;
195 	w = j = 0;
196 	for (std::list<wpnrest_t *>::iterator it = tWeaponList.begin(); it != tWeaponList.end(); it++)  {
197         if( w++ < count )
198             continue;
199         if( j > 10 )
200             break;
201 
202         int y = 190 + (j++)*20;
203         Color Colour = tLX->clNormalLabel;
204 		Color StateColour = Colour;
205 		if( (*it)->psLink->nState == wpr_bonus ) // Different color will make it more comfortable for eyes
206 			StateColour = tLX->clSubHeading;
207 		if( (*it)->psLink->nState == wpr_banned )
208 			StateColour = tLX->clDisabled;
209 
210         // If a mouse is over the line, highlight it
211         if( Mouse->X > 150 && Mouse->X < 450 ) {
212             if( Mouse->Y > y && Mouse->Y < y+20 ) {
213                 Colour = tLX->clMouseOver;
214 				StateColour = tLX->clMouseOver;
215 
216                 // If the mouse has been clicked, cycle through the states
217                 if( Mouse->Up & SDL_BUTTON(1) ) {
218                     (*it)->psLink->nState++;
219                     (*it)->psLink->nState %= 3;
220                 }
221             }
222         }
223 
224 		std::string buf = (*it)->psLink->szName;
225 		stripdot(buf,245);
226         tLX->cFont.Draw( VideoPostProcessor::videoSurface(), 150, y, Colour, buf );
227         tLX->cFont.Draw( VideoPostProcessor::videoSurface(), 400, y, StateColour, szStates[(*it)->psLink->nState] );
228 	}
229 
230     // Adjust the scrollbar
231     cWeaponsRest.SendMessage(wr_Scroll, SCM_SETITEMSPERBOX, 12, 0);
232     cWeaponsRest.SendMessage(wr_Scroll, SCM_SETMIN, (DWORD)0, 0);
233 	if(tWeaponList.size() > 10)
234 		cWeaponsRest.SendMessage(wr_Scroll, SCM_SETMAX, tWeaponList.size() + 1, 0);
235     else
236         cWeaponsRest.SendMessage(wr_Scroll, SCM_SETMAX, (DWORD)0, 0);
237 	*/
238 
239 
240 	ev = cWeaponsRest.Process();
241 	cWeaponsRest.Draw(VideoPostProcessor::videoSurface());
242 
243 	if(ev) {
244 
245 		switch(ev->iControlID) {
246 
247 			// OK, done
248 			case wr_Ok:
249 				if(ev->iEventMsg == BTN_CLICKED) {
250 
251 					Menu_WeaponsRestrictionsShutdown();
252 
253 					return true;
254 				}
255 				break;
256 
257             // Reset the list
258             case wr_Reset:
259                 if( ev->iEventMsg == BTN_CLICKED ) {
260                     cWpnRestList.cycleVisible(cWpnGameScript);
261                     UpdateWeaponListWidget();
262                 }
263                 break;
264 
265             // Randomize the list
266             case wr_Random:
267                 if(ev->iEventMsg == BTN_CLICKED) {
268                     cWpnRestList.randomizeVisible(cWpnGameScript);
269                     UpdateWeaponListWidget();
270                 }
271                 break;
272 
273             // Open the load dialog
274             case wr_Load:
275                 if(ev->iEventMsg == BTN_CLICKED) {
276                     Menu_WeaponPresets(false,&cWpnRestList);
277                     UpdateWeaponListWidget();
278                 }
279                 break;
280 
281             // Open the save dialog
282             case wr_Save:
283                 if(ev->iEventMsg == BTN_CLICKED) {
284                     Menu_WeaponPresets(true,&cWpnRestList);
285                     UpdateWeaponListWidget();
286                 }
287                 break;
288 
289 			case wr_List:
290 				if (ev->iEventMsg == LV_ENTER || ev->iEventMsg == LV_DOUBLECLK) {
291 					const Color cStateColours[] = { tLX->clNormalLabel, tLX->clSubHeading, tLX->clDisabled };
292 					CListview *listWidget = dynamic_cast<CListview *>(cWeaponsRest.getWidget(wr_List));
293 					lv_subitem_t *sub = listWidget->getCurSubitem(1);
294 					if (sub) {
295 						int idx = 0;
296 						for (auto weapon: tWeaponList) {
297 							if (idx == listWidget->getCurIndex()) {
298 								weapon->psLink->nState++;
299 								weapon->psLink->nState %= 3;
300 								sub->sText = szStates[weapon->psLink->nState];
301 								sub->iColour = cStateColours[weapon->psLink->nState];
302 								break;
303 							}
304 							idx++;
305 						}
306 					}
307 				}
308 				break;
309 		}
310 	}
311 
312 	// Draw the mouse
313 	DrawCursor(VideoPostProcessor::videoSurface());
314 
315 	return false;
316 }
317 
318 
319 ///////////////////
320 // Weapon presets load/save
321 // For both local and host
322 enum  {
323 	wp_Cancel=0,
324 	wp_Ok,
325 	wp_PresetList,
326 	wp_PresetName
327 };
328 
329 CGuiLayout cWpnPresets;
330 
331 	struct WeaponPresetsAdder {
332 		CListview* listview;
WeaponPresetsAdderDeprecatedGUI::WeaponPresetsAdder333 		WeaponPresetsAdder(CListview* lv_) : listview(lv_) {}
operator ()DeprecatedGUI::WeaponPresetsAdder334 		bool operator() (const std::string& f) {
335 			if(stringcaseequal(GetFileExtension(f),"wps")) {
336 				std::vector<std::string> fnparts = ListAsVector(SplitFilename(f, 3));
337 				if(fnparts.size() < 3) return true; // strange
338 				std::string fname = fnparts[1] + "/" + fnparts[2];
339 				if(stringcaseequal(fnparts[0], "cfg") && stringcaseequal(fnparts[1], "presets"))
340 					fname = fnparts[2];
341 				std::string name = GetBaseFilenameWithoutExt(fname);
342 				if(!listview->getItem(fname)) {
343 					listview->AddItem(fname,0,tLX->clListView);
344 					listview->AddSubitem(LVS_TEXT, name, (DynDrawIntf*)NULL, NULL);
345 				}
346 			}
347 			return true;
348 		}
349 	};
350 
Menu_WeaponPresets(bool save,CWpnRest * wpnrest)351 void Menu_WeaponPresets(bool save, CWpnRest *wpnrest)
352 {
353 	if (!wpnrest)
354 		return;
355 
356 	gui_event_t *ev = NULL;
357 	int quitloop = false;
358 	CTextbox *t;
359 
360 	// Save the background
361 	DrawImageAdv(tMenu->bmpBuffer.get(), VideoPostProcessor::videoSurface(), 0,0, 0,0, 640,480);
362 
363 	Menu_RedrawMouse(true);
364 
365 	cWpnPresets.Initialize();
366 
367 	cWpnPresets.Add( new CButton(BUT_CANCEL, tMenu->bmpButtons), wp_Cancel, 180,310, 75,15);
368 	cWpnPresets.Add( new CButton(BUT_OK, tMenu->bmpButtons),     wp_Ok, 430,310, 40,15);
369 	cWpnPresets.Add( new CListview(),                            wp_PresetList, 180,170, 280,110+(!save)*20);
370 	cWpnPresets.Add( new CTextbox(),                             wp_PresetName, 270,285, 190,tLX->cFont.GetHeight());
371 
372 	cWpnPresets.SendMessage(wp_PresetList,LVM_SETOLDSTYLE,(DWORD)0,0);
373 
374 	t = (CTextbox *)cWpnPresets.getWidget(wp_PresetName);
375 
376 	// Hide the textbox for Load
377 	t->setEnabled(save);
378 
379 	// Load the level list
380 
381 	CListview *lv = (CListview *)cWpnPresets.getWidget(wp_PresetList);
382 	lv->AddColumn("Weapon presets",60);
383 
384 	WeaponPresetsAdder adder(lv);
385 	FindFiles(adder, "cfg/presets/" + cWpnGameScript->directory(), false, FM_REG);
386 	FindFiles(adder, "cfg/presets", false, FM_REG);
387 
388 	lv->SortBy( 0, true );
389 
390 	ProcessEvents();
391 	while(!WasKeyboardEventHappening(SDLK_ESCAPE,false) && !quitloop && tMenu->bMenuRunning) {
392 		Menu_RedrawMouse(true);
393 
394 		//DrawImageAdv(VideoPostProcessor::videoSurface(),tMenu->bmpBuffer, 170,150, 170,150, 300, 180);
395 		Menu_DrawBox(VideoPostProcessor::videoSurface(), 170, 150, 470, 330);
396 		DrawImageAdv(VideoPostProcessor::videoSurface(), tMenu->bmpMainBack_common, 172,152, 172,152, 297,177);
397 		DrawImageAdv(tMenu->bmpBuffer.get(), tMenu->bmpMainBack_common, 172,152, 172,152, 297,177);
398 
399 		tLX->cFont.DrawCentre(VideoPostProcessor::videoSurface(), 320, 155, tLX->clNormalLabel, save ? "Save" : "Load");
400 		if (save)
401 			tLX->cFont.Draw(VideoPostProcessor::videoSurface(), 180,288,tLX->clNormalLabel,"Preset name");
402 
403 		ev = cWpnPresets.Process();
404 		cWpnPresets.Draw(VideoPostProcessor::videoSurface());
405 
406 		// Process the widgets
407 		if(ev)  {
408 
409 			switch(ev->iControlID) {
410 				// Cancel
411 				case wp_Cancel:
412 					if(ev->iEventMsg == BTN_CLICKED) {
413 						PlaySoundSample(sfxGeneral.smpClick);
414 						quitloop = true;
415 					}
416 					break;
417 
418 				// Presets list
419 				case wp_PresetList:
420 					if(ev->iEventMsg != LV_NONE) {
421 						if(save) t->setText( GetBaseFilenameWithoutExt(lv->getCurSIndex()) );
422 						else t->setText( lv->getCurSIndex() );
423 					}
424 				break;
425 			}
426 
427 			// OK and double click on listview
428 			if (ev->iControlID == wp_Ok || ev->iControlID == wp_PresetList)  {
429 				if((ev->iEventMsg == BTN_CLICKED && ev->iControlID == 1) || ev->iEventMsg == LV_DOUBLECLK || ev->iEventMsg == LV_ENTER) {
430 
431 					// Play the sound only for OK button
432 					if (ev->iControlID == wp_Ok)
433 						PlaySoundSample(sfxGeneral.smpClick);
434 
435 					// Don't process when nothing is selected
436 					if(t->getText().length() > 0) {
437 
438 						quitloop = true;
439 						if(save) {
440 
441 							// Save
442 							std::string fn = "cfg/presets/" + cWpnGameScript->directory() + "/" + t->getText(); // + ".wps";
443 							if(fn.find(".wps") == std::string::npos )
444 								fn += ".wps";
445 
446 							// Check if it exists already. If so, ask user if they wanna overwrite
447 							if(Menu_WeaponPresetsOkSave(fn))
448 								wpnrest->saveList(fn);
449 							else
450 								quitloop = false;
451 						} else {
452 
453 							// Load
454 							std::string fn = "cfg/presets/" + t->getText();
455 							wpnrest->loadList(fn);
456 							wpnrest->updateList(cWpnGameScript);
457 							UpdateWeaponList();
458 						}
459 					}
460 				}
461 			}
462 		}
463 
464 		// Draw mouse
465 		DrawCursor(VideoPostProcessor::videoSurface());
466 
467 		// Display the dialog
468 		doVideoFrameInMainThread();
469 
470 		CapFPS();
471 		WaitForNextEvent();
472 	}
473 
474 	// Redraw back to normal
475 	DrawImageAdv(tMenu->bmpBuffer.get(), tMenu->bmpMainBack_common, 120,150,122,152, 396,316);
476 	DrawImage(VideoPostProcessor::videoSurface(),tMenu->bmpBuffer,0,0);
477 
478 	Menu_RedrawMouse(true);
479 
480 	Menu_WeaponPresetsShutdown();
481 }
482 
483 /////////////
484 // Shutdown
Menu_WeaponPresetsShutdown()485 void Menu_WeaponPresetsShutdown()
486 {
487 	cWpnPresets.Shutdown();
488 }
489 
490 
491 ///////////////////
492 // Check if there is a possible overwrite
Menu_WeaponPresetsOkSave(const std::string & szFilename)493 bool Menu_WeaponPresetsOkSave(const std::string& szFilename)
494 {
495 	std::string filename = szFilename;
496 
497 	// Adjust the filename
498 	if( stringcasecmp(GetFileExtension( szFilename ), "wps") != 0)
499 		filename += ".wps";
500 
501 	FILE *fp = OpenGameFile(filename,"rb");
502 	if( fp == NULL)
503 		// File doesn't exist, ok to save
504 		return true;
505 
506 	fclose(fp);
507 
508 
509 	// The file already exists, show a message box to confirm the overwrite
510 	int nResult = Menu_MessageBox("Confirmation","The preset already exists. Overwrite?", LMB_YESNO);
511 	if( nResult == MBR_YES )
512 		return true;
513 
514 
515 	// No overwrite
516 	return false;
517 }
518 
519 }; // namespace DeprecatedGUI
520