1 /*
2 ** playermenu.cpp
3 ** The player setup menu
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 2001-2010 Randy Heit
7 ** Copyright 2010 Christoph Oelckers
8 ** All rights reserved.
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions
12 ** are met:
13 **
14 ** 1. Redistributions of source code must retain the above copyright
15 **    notice, this list of conditions and the following disclaimer.
16 ** 2. Redistributions in binary form must reproduce the above copyright
17 **    notice, this list of conditions and the following disclaimer in the
18 **    documentation and/or other materials provided with the distribution.
19 ** 3. The name of the author may not be used to endorse or promote products
20 **    derived from this software without specific prior written permission.
21 **
22 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 **---------------------------------------------------------------------------
33 **
34 */
35 
36 #include "menu/menu.h"
37 #include "v_video.h"
38 #include "v_font.h"
39 #include "gi.h"
40 #include "gstrings.h"
41 #include "d_player.h"
42 #include "d_event.h"
43 #include "d_gui.h"
44 #include "c_dispatch.h"
45 #include "teaminfo.h"
46 #include "v_palette.h"
47 #include "r_state.h"
48 #include "r_data/r_translate.h"
49 #include "v_text.h"
50 
EXTERN_CVAR(String,playerclass)51 EXTERN_CVAR (String, playerclass)
52 EXTERN_CVAR (String, name)
53 EXTERN_CVAR (Int, team)
54 EXTERN_CVAR (Float, autoaim)
55 EXTERN_CVAR(Bool, neverswitchonpickup)
56 EXTERN_CVAR (Bool, cl_run)
57 
58 //=============================================================================
59 //
60 // Player's name
61 //
62 //=============================================================================
63 
64 FPlayerNameBox::FPlayerNameBox(int x, int y, int height, int frameofs, const char *text, FFont *font, EColorRange color, FName action)
65 : FListMenuItemSelectable(x, y, height, action)
66 {
67 	mText = copystring(text);
68 	mFont = font;
69 	mFontColor = color;
70 	mFrameSize = frameofs;
71 	mPlayerName[0] = 0;
72 	mEntering = false;
73 }
74 
~FPlayerNameBox()75 FPlayerNameBox::~FPlayerNameBox()
76 {
77 	if (mText != NULL) delete [] mText;
78 }
79 
80 //=============================================================================
81 //
82 //
83 //
84 //=============================================================================
85 
SetString(int i,const char * s)86 bool FPlayerNameBox::SetString(int i, const char *s)
87 {
88 	if (i == 0)
89 	{
90 		strncpy(mPlayerName, s, MAXPLAYERNAME);
91 		mPlayerName[MAXPLAYERNAME] = 0;
92 		return true;
93 	}
94 	return false;
95 }
96 
GetString(int i,char * s,int len)97 bool FPlayerNameBox::GetString(int i, char *s, int len)
98 {
99 	if (i == 0)
100 	{
101 		strncpy(s, mPlayerName, len);
102 		s[len] = 0;
103 		return true;
104 	}
105 	return false;
106 }
107 
108 //=============================================================================
109 //
110 // [RH] Width of the border is variable
111 //
112 //=============================================================================
113 
DrawBorder(int x,int y,int len)114 void FPlayerNameBox::DrawBorder (int x, int y, int len)
115 {
116 	FTexture *left = TexMan[TexMan.CheckForTexture("M_LSLEFT", FTexture::TEX_MiscPatch)];
117 	FTexture *mid = TexMan[TexMan.CheckForTexture("M_LSCNTR", FTexture::TEX_MiscPatch)];
118 	FTexture *right = TexMan[TexMan.CheckForTexture("M_LSRGHT", FTexture::TEX_MiscPatch)];
119 	if (left != NULL && right != NULL && mid != NULL)
120 	{
121 		int i;
122 
123 		screen->DrawTexture (left, x-8, y+7, DTA_Clean, true, TAG_DONE);
124 
125 		for (i = 0; i < len; i++)
126 		{
127 			screen->DrawTexture (mid, x, y+7, DTA_Clean, true, TAG_DONE);
128 			x += 8;
129 		}
130 
131 		screen->DrawTexture (right, x, y+7, DTA_Clean, true, TAG_DONE);
132 	}
133 	else
134 	{
135 		FTexture *slot = TexMan[TexMan.CheckForTexture("M_FSLOT", FTexture::TEX_MiscPatch)];
136 		if (slot != NULL)
137 		{
138 			screen->DrawTexture (slot, x, y+1, DTA_Clean, true, TAG_DONE);
139 		}
140 		else
141 		{
142 			screen->Clear(x, y, x + len, y + SmallFont->GetHeight() * 3/2, -1, 0);
143 		}
144 	}
145 }
146 
147 //=============================================================================
148 //
149 //
150 //
151 //=============================================================================
152 
Drawer(bool selected)153 void FPlayerNameBox::Drawer(bool selected)
154 {
155 	const char *text = mText;
156 	if (text != NULL)
157 	{
158 		if (*text == '$') text = GStrings(text+1);
159 		screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
160 	}
161 
162 	// Draw player name box
163 	int x = mXpos + mFont->StringWidth(text) + 16 + mFrameSize;
164 	DrawBorder (x, mYpos - mFrameSize, MAXPLAYERNAME+1);
165 	if (!mEntering)
166 	{
167 		screen->DrawText (SmallFont, CR_UNTRANSLATED, x + mFrameSize, mYpos, mPlayerName,
168 			DTA_Clean, true, TAG_DONE);
169 	}
170 	else
171 	{
172 		size_t l = strlen(mEditName);
173 		mEditName[l] = SmallFont->GetCursor();
174 		mEditName[l+1] = 0;
175 
176 		screen->DrawText (SmallFont, CR_UNTRANSLATED, x + mFrameSize, mYpos, mEditName,
177 			DTA_Clean, true, TAG_DONE);
178 
179 		mEditName[l] = 0;
180 	}
181 }
182 
183 //=============================================================================
184 //
185 //
186 //
187 //=============================================================================
188 
MenuEvent(int mkey,bool fromcontroller)189 bool FPlayerNameBox::MenuEvent(int mkey, bool fromcontroller)
190 {
191 	if (mkey == MKEY_Enter)
192 	{
193 		S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
194 		strcpy(mEditName, mPlayerName);
195 		mEntering = true;
196 		DMenu *input = new DTextEnterMenu(DMenu::CurrentMenu, mEditName, MAXPLAYERNAME, 2, fromcontroller);
197 		M_ActivateMenu(input);
198 		return true;
199 	}
200 	else if (mkey == MKEY_Input)
201 	{
202 		strcpy(mPlayerName, mEditName);
203 		mEntering = false;
204 		return true;
205 	}
206 	else if (mkey == MKEY_Abort)
207 	{
208 		mEntering = false;
209 		return true;
210 	}
211 	return false;
212 }
213 
214 //=============================================================================
215 //
216 // items for the player menu
217 //
218 //=============================================================================
219 
FValueTextItem(int x,int y,int height,const char * text,FFont * font,EColorRange color,EColorRange valuecolor,FName action,FName values)220 FValueTextItem::FValueTextItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, EColorRange valuecolor, FName action, FName values)
221 : FListMenuItemSelectable(x, y, height, action)
222 {
223 	mText = copystring(text);
224 	mFont = font;
225 	mFontColor = color;
226 	mFontColor2 = valuecolor;
227 	mSelection = 0;
228 	if (values != NAME_None)
229 	{
230 		FOptionValues **opt = OptionValues.CheckKey(values);
231 		if (opt != NULL)
232 		{
233 			for(unsigned i=0;i<(*opt)->mValues.Size(); i++)
234 			{
235 				SetString(i, (*opt)->mValues[i].Text);
236 			}
237 		}
238 	}
239 }
240 
~FValueTextItem()241 FValueTextItem::~FValueTextItem()
242 {
243 	if (mText != NULL) delete [] mText;
244 }
245 
246 //=============================================================================
247 //
248 //
249 //
250 //=============================================================================
251 
SetString(int i,const char * s)252 bool FValueTextItem::SetString(int i, const char *s)
253 {
254 	// should actually use the index...
255 	FString str = s;
256 	if (i==0) mSelections.Clear();
257 	mSelections.Push(str);
258 	return true;
259 }
260 
261 //=============================================================================
262 //
263 //
264 //
265 //=============================================================================
266 
SetValue(int i,int value)267 bool FValueTextItem::SetValue(int i, int value)
268 {
269 	if (i == 0)
270 	{
271 		mSelection = value;
272 		return true;
273 	}
274 	return false;
275 }
276 
GetValue(int i,int * pvalue)277 bool FValueTextItem::GetValue(int i, int *pvalue)
278 {
279 	if (i == 0)
280 	{
281 		*pvalue = mSelection;
282 		return true;
283 	}
284 	return false;
285 }
286 
287 //=============================================================================
288 //
289 //
290 //
291 //=============================================================================
292 
MenuEvent(int mkey,bool fromcontroller)293 bool FValueTextItem::MenuEvent (int mkey, bool fromcontroller)
294 {
295 	if (mSelections.Size() > 1)
296 	{
297 		if (mkey == MKEY_Left)
298 		{
299 			S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
300 			if (--mSelection < 0) mSelection = mSelections.Size() - 1;
301 			return true;
302 		}
303 		else if (mkey == MKEY_Right || mkey == MKEY_Enter)
304 		{
305 			S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
306 			if (++mSelection >= (int)mSelections.Size()) mSelection = 0;
307 			return true;
308 		}
309 	}
310 	return (mkey == MKEY_Enter);	// needs to eat enter keys so that Activate won't get called
311 }
312 
313 //=============================================================================
314 //
315 //
316 //
317 //=============================================================================
318 
Drawer(bool selected)319 void FValueTextItem::Drawer(bool selected)
320 {
321 	const char *text = mText;
322 
323 	if (*text == '$') text = GStrings(text+1);
324 	screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
325 
326 	int x = mXpos + mFont->StringWidth(text) + 8;
327 	if (mSelections.Size() > 0)
328 	{
329 		const char *mOptValue = mSelections[mSelection];
330 		if (*mOptValue == '$') mOptValue = GStrings(mOptValue + 1);
331 		screen->DrawText(mFont, mFontColor2, x, mYpos, mOptValue, DTA_Clean, true, TAG_DONE);
332 	}
333 }
334 
335 //=============================================================================
336 //
337 // items for the player menu
338 //
339 //=============================================================================
340 
FSliderItem(int x,int y,int height,const char * text,FFont * font,EColorRange color,FName action,int min,int max,int step)341 FSliderItem::FSliderItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, FName action, int min, int max, int step)
342 : FListMenuItemSelectable(x, y, height, action)
343 {
344 	mText = copystring(text);
345 	mFont = font;
346 	mFontColor = color;
347 	mSelection = 0;
348 	mMinrange = min;
349 	mMaxrange = max;
350 	mStep = step;
351 }
352 
~FSliderItem()353 FSliderItem::~FSliderItem()
354 {
355 	if (mText != NULL) delete [] mText;
356 }
357 
358 //=============================================================================
359 //
360 //
361 //
362 //=============================================================================
363 
SetValue(int i,int value)364 bool FSliderItem::SetValue(int i, int value)
365 {
366 	if (i == 0)
367 	{
368 		mSelection = value;
369 		return true;
370 	}
371 	return false;
372 }
373 
GetValue(int i,int * pvalue)374 bool FSliderItem::GetValue(int i, int *pvalue)
375 {
376 	if (i == 0)
377 	{
378 		*pvalue = mSelection;
379 		return true;
380 	}
381 	return false;
382 }
383 
384 //=============================================================================
385 //
386 //
387 //
388 //=============================================================================
389 
MenuEvent(int mkey,bool fromcontroller)390 bool FSliderItem::MenuEvent (int mkey, bool fromcontroller)
391 {
392 	if (mkey == MKEY_Left)
393 	{
394 		S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
395 		if ((mSelection -= mStep) < mMinrange) mSelection = mMinrange;
396 		return true;
397 	}
398 	else if (mkey == MKEY_Right || mkey == MKEY_Enter)
399 	{
400 		S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
401 		if ((mSelection += mStep) > mMaxrange) mSelection = mMaxrange;
402 		return true;
403 	}
404 	return false;
405 }
406 
407 //=============================================================================
408 //
409 //
410 //
411 //=============================================================================
412 
MouseEvent(int type,int x,int y)413 bool FSliderItem::MouseEvent(int type, int x, int y)
414 {
415 	DListMenu *lm = static_cast<DListMenu*>(DMenu::CurrentMenu);
416 	if (type != DMenu::MOUSE_Click)
417 	{
418 		if (!lm->CheckFocus(this)) return false;
419 	}
420 	if (type == DMenu::MOUSE_Release)
421 	{
422 		lm->ReleaseFocus();
423 	}
424 
425 	int slide_left = SmallFont->StringWidth ("Green") + 8 + mXpos;
426 	int slide_right = slide_left + 12*8;	// 12 char cells with 8 pixels each.
427 
428 	if (type == DMenu::MOUSE_Click)
429 	{
430 		if (x < slide_left || x >= slide_right) return true;
431 	}
432 
433 	x = clamp(x, slide_left, slide_right);
434 	int v = mMinrange + Scale(x - slide_left, mMaxrange - mMinrange, slide_right - slide_left);
435 	if (v != mSelection)
436 	{
437 		mSelection = v;
438 		S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
439 	}
440 	if (type == DMenu::MOUSE_Click)
441 	{
442 		lm->SetFocus(this);
443 	}
444 	return true;
445 }
446 
447 //=============================================================================
448 //
449 //
450 //
451 //=============================================================================
452 
DrawSlider(int x,int y)453 void FSliderItem::DrawSlider (int x, int y)
454 {
455 	int range = mMaxrange - mMinrange;
456 	int cur = mSelection - mMinrange;
457 
458 	x = (x - 160) * CleanXfac + screen->GetWidth() / 2;
459 	y = (y - 100) * CleanYfac + screen->GetHeight() / 2;
460 
461 	screen->DrawText (ConFont, CR_WHITE, x, y,
462 		"\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12",
463 		DTA_CellX, 8 * CleanXfac,
464 		DTA_CellY, 8 * CleanYfac,
465 		TAG_DONE);
466 	screen->DrawText (ConFont, CR_ORANGE, x + (5 + (int)((cur * 78) / range)) * CleanXfac, y,
467 		"\x13",
468 		DTA_CellX, 8 * CleanXfac,
469 		DTA_CellY, 8 * CleanYfac,
470 		TAG_DONE);
471 }
472 
473 //=============================================================================
474 //
475 //
476 //
477 //=============================================================================
478 
Drawer(bool selected)479 void FSliderItem::Drawer(bool selected)
480 {
481 	const char *text = mText;
482 
483 	if (*text == '$') text = GStrings(text+1);
484 	screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
485 
486 	int x = SmallFont->StringWidth ("Green") + 8 + mXpos;
487 	int x2 = SmallFont->StringWidth (text) + 8 + mXpos;
488 	DrawSlider (MAX(x2, x), mYpos);
489 }
490 
491 
492 //=============================================================================
493 //
494 //
495 //
496 //=============================================================================
497 
498 class DPlayerMenu : public DListMenu
499 {
500 	DECLARE_CLASS(DPlayerMenu, DListMenu)
501 
502 	int PlayerClassIndex;
503 	FPlayerClass *PlayerClass;
504 	TArray<int> PlayerColorSets;
505 	TArray<int> PlayerSkins;
506 	int mRotation;
507 
508 	void PickPlayerClass ();
509 	void UpdateColorsets();
510 	void UpdateSkins();
511 	void UpdateTranslation();
512 	void SendNewColor (int red, int green, int blue);
513 
514 	void PlayerNameChanged(FListMenuItem *li);
515 	void ColorSetChanged (FListMenuItem *li);
516 	void ClassChanged (FListMenuItem *li);
517 	void AutoaimChanged (FListMenuItem *li);
518 	void SkinChanged (FListMenuItem *li);
519 
520 
521 public:
522 
DPlayerMenu()523 	DPlayerMenu() {}
524 	void Init(DMenu *parent, FListMenuDescriptor *desc);
525 	bool Responder (event_t *ev);
526 	bool MenuEvent (int mkey, bool fromcontroller);
527 	bool MouseEvent(int type, int x, int y);
528 	void Ticker ();
529 	void Drawer ();
530 };
531 
IMPLEMENT_CLASS(DPlayerMenu)532 IMPLEMENT_CLASS(DPlayerMenu)
533 
534 //=============================================================================
535 //
536 //
537 //
538 //=============================================================================
539 
540 void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc)
541 {
542 	FListMenuItem *li;
543 
544 	Super::Init(parent, desc);
545 	PickPlayerClass();
546 	mRotation = 0;
547 
548 	li = GetItem(NAME_Playerdisplay);
549 	if (li != NULL)
550 	{
551 		li->SetValue(FListMenuItemPlayerDisplay::PDF_ROTATION, 0);
552 		li->SetValue(FListMenuItemPlayerDisplay::PDF_MODE, 1);
553 		li->SetValue(FListMenuItemPlayerDisplay::PDF_TRANSLATE, 1);
554 		li->SetValue(FListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum());
555 		if (PlayerClass != NULL && !(GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN) &&
556 			players[consoleplayer].userinfo.GetPlayerClassNum() != -1)
557 		{
558 			li->SetValue(FListMenuItemPlayerDisplay::PDF_SKIN, players[consoleplayer].userinfo.GetSkin());
559 		}
560 	}
561 
562 	li = GetItem(NAME_Playerbox);
563 	if (li != NULL)
564 	{
565 		li->SetString(0, name);
566 	}
567 
568 	li = GetItem(NAME_Team);
569 	if (li != NULL)
570 	{
571 		li->SetString(0, "None");
572 		for(unsigned i=0;i<Teams.Size(); i++)
573 		{
574 			li->SetString(i+1, Teams[i].GetName());
575 		}
576 		li->SetValue(0, team == TEAM_NONE? 0 : team + 1);
577 	}
578 
579 	int mycolorset = players[consoleplayer].userinfo.GetColorSet();
580 	int color = players[consoleplayer].userinfo.GetColor();
581 
582 	UpdateColorsets();
583 
584 	li = GetItem(NAME_Red);
585 	if (li != NULL)
586 	{
587 		li->Enable(mycolorset == -1);
588 		li->SetValue(0, RPART(color));
589 	}
590 
591 	li = GetItem(NAME_Green);
592 	if (li != NULL)
593 	{
594 		li->Enable(mycolorset == -1);
595 		li->SetValue(0, GPART(color));
596 	}
597 
598 	li = GetItem(NAME_Blue);
599 	if (li != NULL)
600 	{
601 		li->Enable(mycolorset == -1);
602 		li->SetValue(0, BPART(color));
603 	}
604 
605 	li = GetItem(NAME_Class);
606 	if (li != NULL)
607 	{
608 		if (PlayerClasses.Size() == 1)
609 		{
610 			li->SetString(0, GetPrintableDisplayName(PlayerClasses[0].Type));
611 			li->SetValue(0, 0);
612 		}
613 		else
614 		{
615 			// [XA] Remove the "Random" option if the relevant gameinfo flag is set.
616 			if(!gameinfo.norandomplayerclass)
617 				li->SetString(0, "Random");
618 			for(unsigned i=0; i< PlayerClasses.Size(); i++)
619 			{
620 				const char *cls = GetPrintableDisplayName(PlayerClasses[i].Type);
621 				li->SetString(gameinfo.norandomplayerclass ? i : i+1, cls);
622 			}
623 			int pclass = players[consoleplayer].userinfo.GetPlayerClassNum();
624 			li->SetValue(0, gameinfo.norandomplayerclass && pclass >= 0 ? pclass : pclass + 1);
625 		}
626 	}
627 
628 	UpdateSkins();
629 
630 	li = GetItem(NAME_Gender);
631 	if (li != NULL)
632 	{
633 		li->SetValue(0, players[consoleplayer].userinfo.GetGender());
634 	}
635 
636 	li = GetItem(NAME_Autoaim);
637 	if (li != NULL)
638 	{
639 		li->SetValue(0, (int)autoaim);
640 	}
641 
642 	li = GetItem(NAME_Switch);
643 	if (li != NULL)
644 	{
645 		li->SetValue(0, neverswitchonpickup);
646 	}
647 
648 	li = GetItem(NAME_AlwaysRun);
649 	if (li != NULL)
650 	{
651 		li->SetValue(0, cl_run);
652 	}
653 
654 	if (mDesc->mSelectedItem < 0) mDesc->mSelectedItem = 1;
655 
656 }
657 
658 //=============================================================================
659 //
660 //
661 //
662 //=============================================================================
663 
Responder(event_t * ev)664 bool DPlayerMenu::Responder (event_t *ev)
665 {
666 	if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_Char && ev->data1 == ' ')
667 	{
668 		// turn the player sprite around
669 		mRotation = 8 - mRotation;
670 		FListMenuItem *li = GetItem(NAME_Playerdisplay);
671 		if (li != NULL)
672 		{
673 			li->SetValue(FListMenuItemPlayerDisplay::PDF_ROTATION, mRotation);
674 		}
675 		return true;
676 	}
677 	return Super::Responder(ev);
678 }
679 
680 //=============================================================================
681 //
682 //
683 //
684 //=============================================================================
685 
UpdateTranslation()686 void DPlayerMenu::UpdateTranslation()
687 {
688 	int PlayerColor = players[consoleplayer].userinfo.GetColor();
689 	int	PlayerSkin = players[consoleplayer].userinfo.GetSkin();
690 	int PlayerColorset = players[consoleplayer].userinfo.GetColorSet();
691 
692 	if (PlayerClass != NULL)
693 	{
694 		PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0]));
695 		R_GetPlayerTranslation(PlayerColor,
696 			P_GetPlayerColorSet(PlayerClass->Type->TypeName, PlayerColorset),
697 			&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
698 	}
699 }
700 
701 //=============================================================================
702 //
703 //
704 //
705 //=============================================================================
706 
PickPlayerClass()707 void DPlayerMenu::PickPlayerClass()
708 {
709 
710 	/*
711 	// What's the point of this? Aren't we supposed to edit the
712 	// userinfo?
713 	if (players[consoleplayer].mo != NULL)
714 	{
715 		PlayerClassIndex = players[consoleplayer].CurrentPlayerClass;
716 	}
717 	else
718 	*/
719 	{
720 		int pclass = 0;
721 		// [GRB] Pick a class from player class list
722 		if (PlayerClasses.Size () > 1)
723 		{
724 			pclass = players[consoleplayer].userinfo.GetPlayerClassNum();
725 
726 			if (pclass < 0)
727 			{
728 				pclass = (MenuTime>>7) % PlayerClasses.Size ();
729 			}
730 		}
731 		PlayerClassIndex = pclass;
732 	}
733 	PlayerClass = &PlayerClasses[PlayerClassIndex];
734 	UpdateTranslation();
735 }
736 
737 //=============================================================================
738 //
739 //
740 //
741 //=============================================================================
742 
SendNewColor(int red,int green,int blue)743 void DPlayerMenu::SendNewColor (int red, int green, int blue)
744 {
745 	char command[24];
746 
747 	players[consoleplayer].userinfo.ColorChanged(MAKERGB(red,green,blue));
748 	mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue);
749 	C_DoCommand (command);
750 	UpdateTranslation();
751 }
752 
753 //=============================================================================
754 //
755 //
756 //
757 //=============================================================================
758 
UpdateColorsets()759 void DPlayerMenu::UpdateColorsets()
760 {
761 	FListMenuItem *li = GetItem(NAME_Color);
762 	if (li != NULL)
763 	{
764 		int sel = 0;
765 		P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets);
766 		li->SetString(0, "Custom");
767 		for(unsigned i=0;i<PlayerColorSets.Size(); i++)
768 		{
769 			FPlayerColorSet *colorset = P_GetPlayerColorSet(PlayerClass->Type->TypeName, PlayerColorSets[i]);
770 			li->SetString(i+1, colorset->Name);
771 		}
772 		int mycolorset = players[consoleplayer].userinfo.GetColorSet();
773 		if (mycolorset != -1)
774 		{
775 			for(unsigned i=0;i<PlayerColorSets.Size(); i++)
776 			{
777 				if (PlayerColorSets[i] == mycolorset)
778 				{
779 					sel = i+1;
780 				}
781 			}
782 		}
783 		li->SetValue(0, sel);
784 	}
785 }
786 
787 //=============================================================================
788 //
789 //
790 //
791 //=============================================================================
792 
UpdateSkins()793 void DPlayerMenu::UpdateSkins()
794 {
795 	int sel = 0;
796 	int skin;
797 	FListMenuItem *li = GetItem(NAME_Skin);
798 	if (li != NULL)
799 	{
800 		if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN ||
801 			players[consoleplayer].userinfo.GetPlayerClassNum() == -1)
802 		{
803 			li->SetString(0, "Base");
804 			li->SetValue(0, 0);
805 			skin = 0;
806 		}
807 		else
808 		{
809 			PlayerSkins.Clear();
810 			for(int i=0;i<(int)numskins; i++)
811 			{
812 				if (PlayerClass->CheckSkin(i))
813 				{
814 					int j = PlayerSkins.Push(i);
815 					li->SetString(j, skins[i].name);
816 					if (players[consoleplayer].userinfo.GetSkin() == i)
817 					{
818 						sel = j;
819 					}
820 				}
821 			}
822 			li->SetValue(0, sel);
823 			skin = PlayerSkins[sel];
824 		}
825 		li = GetItem(NAME_Playerdisplay);
826 		if (li != NULL)
827 		{
828 			li->SetValue(FListMenuItemPlayerDisplay::PDF_SKIN, skin);
829 		}
830 	}
831 	UpdateTranslation();
832 }
833 
834 //=============================================================================
835 //
836 //
837 //
838 //=============================================================================
839 
PlayerNameChanged(FListMenuItem * li)840 void DPlayerMenu::PlayerNameChanged(FListMenuItem *li)
841 {
842 	char pp[MAXPLAYERNAME+1];
843 	const char *p;
844 	if (li->GetString(0, pp, MAXPLAYERNAME))
845 	{
846 		FString command("name \"");
847 
848 		// Escape any backslashes or quotation marks before sending the name to the console.
849 		for (p = pp; *p != '\0'; ++p)
850 		{
851 			if (*p == '"' || *p == '\\')
852 			{
853 				command << '\\';
854 			}
855 			command << *p;
856 		}
857 		command << '"';
858 		C_DoCommand (command);
859 	}
860 }
861 
862 //=============================================================================
863 //
864 //
865 //
866 //=============================================================================
867 
ColorSetChanged(FListMenuItem * li)868 void DPlayerMenu::ColorSetChanged (FListMenuItem *li)
869 {
870 	int	sel;
871 
872 	if (li->GetValue(0, &sel))
873 	{
874 		int mycolorset = -1;
875 
876 		if (sel > 0) mycolorset = PlayerColorSets[sel-1];
877 
878 		FListMenuItem *red   = GetItem(NAME_Red);
879 		FListMenuItem *green = GetItem(NAME_Green);
880 		FListMenuItem *blue  = GetItem(NAME_Blue);
881 
882 		// disable the sliders if a valid colorset is selected
883 		if (red != NULL) red->Enable(mycolorset == -1);
884 		if (green != NULL) green->Enable(mycolorset == -1);
885 		if (blue != NULL) blue->Enable(mycolorset == -1);
886 
887 		char command[24];
888 		players[consoleplayer].userinfo.ColorSetChanged(mycolorset);
889 		mysnprintf(command, countof(command), "colorset %d", mycolorset);
890 		C_DoCommand(command);
891 		UpdateTranslation();
892 	}
893 }
894 
895 //=============================================================================
896 //
897 //
898 //
899 //=============================================================================
900 
ClassChanged(FListMenuItem * li)901 void DPlayerMenu::ClassChanged (FListMenuItem *li)
902 {
903 	if (PlayerClasses.Size () == 1)
904 	{
905 		return;
906 	}
907 
908 	int	sel;
909 
910 	if (li->GetValue(0, &sel))
911 	{
912 		players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1);
913 		PickPlayerClass();
914 
915 		cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName));
916 
917 		UpdateSkins();
918 		UpdateColorsets();
919 		UpdateTranslation();
920 
921 		li = GetItem(NAME_Playerdisplay);
922 		if (li != NULL)
923 		{
924 			li->SetValue(FListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum());
925 		}
926 	}
927 }
928 
929 //=============================================================================
930 //
931 //
932 //
933 //=============================================================================
934 
SkinChanged(FListMenuItem * li)935 void DPlayerMenu::SkinChanged (FListMenuItem *li)
936 {
937 	if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN ||
938 		players[consoleplayer].userinfo.GetPlayerClassNum() == -1)
939 	{
940 		return;
941 	}
942 
943 	int	sel;
944 
945 	if (li->GetValue(0, &sel))
946 	{
947 		sel = PlayerSkins[sel];
948 		players[consoleplayer].userinfo.SkinNumChanged(sel);
949 		UpdateTranslation();
950 		cvar_set ("skin", skins[sel].name);
951 
952 		li = GetItem(NAME_Playerdisplay);
953 		if (li != NULL)
954 		{
955 			li->SetValue(FListMenuItemPlayerDisplay::PDF_SKIN, sel);
956 		}
957 	}
958 }
959 
960 //=============================================================================
961 //
962 //
963 //
964 //=============================================================================
965 
AutoaimChanged(FListMenuItem * li)966 void DPlayerMenu::AutoaimChanged (FListMenuItem *li)
967 {
968 	int	sel;
969 
970 	if (li->GetValue(0, &sel))
971 	{
972 		autoaim = (float)sel;
973 	}
974 }
975 
976 //=============================================================================
977 //
978 //
979 //
980 //=============================================================================
981 
MenuEvent(int mkey,bool fromcontroller)982 bool DPlayerMenu::MenuEvent (int mkey, bool fromcontroller)
983 {
984 	int v;
985 	if (mDesc->mSelectedItem >= 0)
986 	{
987 		FListMenuItem *li = mDesc->mItems[mDesc->mSelectedItem];
988 		if (li->MenuEvent(mkey, fromcontroller))
989 		{
990 			FName current = li->GetAction(NULL);
991 			switch(current)
992 			{
993 				// item specific handling comes here
994 
995 			case NAME_Playerbox:
996 				if (mkey == MKEY_Input)
997 				{
998 					PlayerNameChanged(li);
999 				}
1000 				break;
1001 
1002 			case NAME_Team:
1003 				if (li->GetValue(0, &v))
1004 				{
1005 					team = v==0? TEAM_NONE : v-1;
1006 				}
1007 				break;
1008 
1009 			case NAME_Color:
1010 					ColorSetChanged(li);
1011 					break;
1012 
1013 			case NAME_Red:
1014 				if (li->GetValue(0, &v))
1015 				{
1016 					uint32 color = players[consoleplayer].userinfo.GetColor();
1017 					SendNewColor (v, GPART(color), BPART(color));
1018 				}
1019 				break;
1020 
1021 			case NAME_Green:
1022 				if (li->GetValue(0, &v))
1023 				{
1024 					uint32 color = players[consoleplayer].userinfo.GetColor();
1025 					SendNewColor (RPART(color), v, BPART(color));
1026 				}
1027 				break;
1028 
1029 			case NAME_Blue:
1030 				if (li->GetValue(0, &v))
1031 				{
1032 					uint32 color = players[consoleplayer].userinfo.GetColor();
1033 					SendNewColor (RPART(color), GPART(color), v);
1034 				}
1035 				break;
1036 
1037 			case NAME_Class:
1038 				ClassChanged(li);
1039 				break;
1040 
1041 			case NAME_Skin:
1042 				SkinChanged(li);
1043 				break;
1044 
1045 			case NAME_Gender:
1046 				if (li->GetValue(0, &v))
1047 				{
1048 					cvar_set ("gender", v==0? "male" : v==1? "female" : "other");
1049 				}
1050 				break;
1051 
1052 			case NAME_Autoaim:
1053 				AutoaimChanged(li);
1054 				break;
1055 
1056 			case NAME_Switch:
1057 				if (li->GetValue(0, &v))
1058 				{
1059 					neverswitchonpickup = !!v;
1060 				}
1061 				break;
1062 
1063 			case NAME_AlwaysRun:
1064 				if (li->GetValue(0, &v))
1065 				{
1066 					cl_run = !!v;
1067 				}
1068 				break;
1069 
1070 			default:
1071 				break;
1072 			}
1073 			return true;
1074 		}
1075 	}
1076 	return Super::MenuEvent(mkey, fromcontroller);
1077 }
1078 
1079 
MouseEvent(int type,int x,int y)1080 bool DPlayerMenu::MouseEvent(int type, int x, int y)
1081 {
1082 	int v;
1083 	FListMenuItem *li = mFocusControl;
1084 	bool res = Super::MouseEvent(type, x, y);
1085 	if (li == NULL) li = mFocusControl;
1086 	if (li != NULL)
1087 	{
1088 		// Check if the colors have changed
1089 		FName current = li->GetAction(NULL);
1090 		switch(current)
1091 		{
1092 		case NAME_Red:
1093 			if (li->GetValue(0, &v))
1094 			{
1095 				uint32 color = players[consoleplayer].userinfo.GetColor();
1096 				SendNewColor (v, GPART(color), BPART(color));
1097 			}
1098 			break;
1099 
1100 		case NAME_Green:
1101 			if (li->GetValue(0, &v))
1102 			{
1103 				uint32 color = players[consoleplayer].userinfo.GetColor();
1104 				SendNewColor (RPART(color), v, BPART(color));
1105 			}
1106 			break;
1107 
1108 		case NAME_Blue:
1109 			if (li->GetValue(0, &v))
1110 			{
1111 				uint32 color = players[consoleplayer].userinfo.GetColor();
1112 				SendNewColor (RPART(color), GPART(color), v);
1113 			}
1114 			break;
1115 		}
1116 	}
1117 	return res;
1118 }
1119 
1120 //=============================================================================
1121 //
1122 //
1123 //
1124 //=============================================================================
1125 
Ticker()1126 void DPlayerMenu::Ticker ()
1127 {
1128 
1129 	Super::Ticker();
1130 }
1131 
1132 //=============================================================================
1133 //
1134 //
1135 //
1136 //=============================================================================
1137 
Drawer()1138 void DPlayerMenu::Drawer ()
1139 {
1140 
1141 	Super::Drawer();
1142 
1143 	const char *str = "PRESS " TEXTCOLOR_WHITE "SPACE";
1144 	screen->DrawText (SmallFont, CR_GOLD, 320 - 32 - 32 -
1145 		SmallFont->StringWidth (str)/2,
1146 		50 + 48 + 70, str,
1147 		DTA_Clean, true, TAG_DONE);
1148 	str = mRotation ? "TO SEE FRONT" : "TO SEE BACK";
1149 	screen->DrawText (SmallFont, CR_GOLD, 320 - 32 - 32 -
1150 		SmallFont->StringWidth (str)/2,
1151 		50 + 48 + 70 + SmallFont->GetHeight (), str,
1152 		DTA_Clean, true, TAG_DONE);
1153 
1154 }
1155