1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: p_player.cpp 4316 2010-07-01 12:36:28Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "gamedefs.h"
29 #include "network.h"
30 #include "sv_local.h"
31 #include "cl_local.h"
32 
33 // MACROS ------------------------------------------------------------------
34 
35 // TYPES -------------------------------------------------------------------
36 
37 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
38 
39 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
40 
41 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
42 
43 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
44 
45 // PUBLIC DATA DEFINITIONS -------------------------------------------------
46 
47 // PRIVATE DATA DEFINITIONS ------------------------------------------------
48 
49 IMPLEMENT_CLASS(V, BasePlayer)
50 
51 static VCvarF			notify_time("notify_time", "5", CVAR_Archive);
52 static VCvarF			centre_msg_time("centre_message_time", "7", CVAR_Archive);
53 static VCvarI			msg_echo("msg_echo", "1", CVAR_Archive);
54 static VCvarI			font_colour("font_colour", "11", CVAR_Archive);
55 static VCvarI			font_colour2("font_colour2", "11", CVAR_Archive);
56 
57 // CODE --------------------------------------------------------------------
58 
59 //==========================================================================
60 //
61 //	VBasePlayer::ExecuteNetMethod
62 //
63 //==========================================================================
64 
ExecuteNetMethod(VMethod * Func)65 bool VBasePlayer::ExecuteNetMethod(VMethod* Func)
66 {
67 	guard(VBasePlayer::ExecuteNetMethod);
68 	if (GDemoRecordingContext)
69 	{
70 		//	Find initial version of the method.
71 		VMethod* Base = Func;
72 		while (Base->SuperMethod)
73 		{
74 			Base = Base->SuperMethod;
75 		}
76 		//	Execute it's replication condition method.
77 		check(Base->ReplCond);
78 		P_PASS_REF(this);
79 		vuint32 SavedFlags = PlayerFlags;
80 		PlayerFlags &= ~VBasePlayer::PF_IsClient;
81 		bool ShouldSend = false;
82 		if (VObject::ExecuteFunction(Base->ReplCond).i)
83 		{
84 			ShouldSend = true;
85 		}
86 		PlayerFlags = SavedFlags;
87 
88 		if (ShouldSend)
89 		{
90 			//	Replication condition is true, the method must be replicated.
91 			GDemoRecordingContext->ClientConnections[0]->Channels[
92 				CHANIDX_Player]->SendRpc(Func, this);
93 		}
94 	}
95 
96 #ifdef CLIENT
97 	if (GGameInfo->NetMode == NM_TitleMap ||
98 		GGameInfo->NetMode == NM_Standalone ||
99 		(GGameInfo->NetMode == NM_ListenServer && this == cl))
100 	{
101 		return false;
102 	}
103 #endif
104 
105 	//	Find initial version of the method.
106 	VMethod* Base = Func;
107 	while (Base->SuperMethod)
108 	{
109 		Base = Base->SuperMethod;
110 	}
111 	//	Execute it's replication condition method.
112 	check(Base->ReplCond);
113 	P_PASS_REF(this);
114 	if (!VObject::ExecuteFunction(Base->ReplCond).i)
115 	{
116 		return false;
117 	}
118 
119 	if (Net)
120 	{
121 		//	Replication condition is true, the method must be replicated.
122 		Net->Channels[CHANIDX_Player]->SendRpc(Func, this);
123 	}
124 
125 	//	Clean up parameters
126 	guard(CleanUp);
127 	VStack* Param = pr_stackPtr - Func->ParamsSize + 1;	//	Skip self
128 	for (int i = 0; i < Func->NumParams; i++)
129 	{
130 		switch (Func->ParamTypes[i].Type)
131 		{
132 		case TYPE_Int:
133 		case TYPE_Byte:
134 		case TYPE_Bool:
135 		case TYPE_Float:
136 		case TYPE_Name:
137 		case TYPE_Pointer:
138 		case TYPE_Reference:
139 		case TYPE_Class:
140 		case TYPE_State:
141 			Param++;
142 			break;
143 		case TYPE_String:
144 			((VStr*)&Param->p)->Clean();
145 			Param++;
146 			break;
147 		case TYPE_Vector:
148 			Param += 3;
149 			break;
150 		default:
151 			Sys_Error("Bad method argument type %d", Func->ParamTypes[i].Type);
152 		}
153 		if (Func->ParamFlags[i] & FPARM_Optional)
154 		{
155 			Param++;
156 		}
157 	}
158 	pr_stackPtr -= Func->ParamsSize;
159 	unguard;
160 
161 	//	Push null return value
162 	guard(RetVal);
163 	switch (Func->ReturnType.Type)
164 	{
165 	case TYPE_Void:
166 		break;
167 	case TYPE_Int:
168 	case TYPE_Byte:
169 	case TYPE_Bool:
170 	case TYPE_Name:
171 		PR_Push(0);
172 		break;
173 	case TYPE_Float:
174 		PR_Pushf(0);
175 		break;
176 	case TYPE_String:
177 		PR_PushStr(VStr());
178 		break;
179 	case TYPE_Pointer:
180 	case TYPE_Reference:
181 	case TYPE_Class:
182 	case TYPE_State:
183 		PR_PushPtr(NULL);
184 		break;
185 	case TYPE_Vector:
186 		PR_Pushf(0);
187 		PR_Pushf(0);
188 		PR_Pushf(0);
189 		break;
190 	default:
191 		Sys_Error("Bad return value type");
192 	}
193 	unguard;
194 
195 	//	It's been handled here.
196 	return true;
197 	unguard;
198 }
199 
200 //==========================================================================
201 //
202 //	VBasePlayer::SpawnClient
203 //
204 //==========================================================================
205 
SpawnClient()206 void VBasePlayer::SpawnClient()
207 {
208 	guard(VBasePlayer::SpawnClient);
209 	if (!sv_loading)
210 	{
211 		if (PlayerFlags & PF_Spawned)
212 		{
213 			GCon->Log(NAME_Dev, "Already spawned");
214 		}
215 		if (MO)
216 		{
217 			GCon->Log(NAME_Dev, "Mobj already spawned");
218 		}
219 		eventSpawnClient();
220 		for (int i = 0; i < Level->XLevel->ActiveSequences.Num(); i++)
221 		{
222 			eventClientStartSequence(
223 				Level->XLevel->ActiveSequences[i].Origin,
224 				Level->XLevel->ActiveSequences[i].OriginId,
225 				Level->XLevel->ActiveSequences[i].Name,
226 				Level->XLevel->ActiveSequences[i].ModeNum);
227 			for (int j = 0; j < Level->XLevel->ActiveSequences[i].Choices.Num(); j++)
228 			{
229 				eventClientAddSequenceChoice(
230 					Level->XLevel->ActiveSequences[i].OriginId,
231 					Level->XLevel->ActiveSequences[i].Choices[j]);
232 			}
233 		}
234 	}
235 	else
236 	{
237 		if (!MO)
238 		{
239 			Host_Error("Player without Mobj\n");
240 		}
241 	}
242 
243 	ViewAngles.roll = 0;
244 	eventClientSetAngles(ViewAngles);
245 	PlayerFlags &= ~PF_FixAngle;
246 
247 	PlayerFlags |= PF_Spawned;
248 
249 	if ((GGameInfo->NetMode == NM_TitleMap ||
250 		GGameInfo->NetMode == NM_Standalone) && run_open_scripts)
251 	{
252 		//	Start open scripts.
253 		Level->XLevel->Acs->StartTypedACScripts(SCRIPT_Open, 0, 0, 0, NULL,
254 			false, false);
255 	}
256 
257 	if (!sv_loading)
258 	{
259 		Level->XLevel->Acs->StartTypedACScripts(SCRIPT_Enter, 0, 0, 0, MO,
260 			true, false);
261 	}
262 	else if (sv_map_travel)
263 	{
264 		Level->XLevel->Acs->StartTypedACScripts(SCRIPT_Return, 0, 0, 0, MO,
265 			true, false);
266 	}
267 
268 	if (GGameInfo->NetMode < NM_DedicatedServer ||
269 		svs.num_connected == sv_load_num_players)
270 	{
271 		sv_loading = false;
272 		sv_map_travel = false;
273 	}
274 
275 	// For single play, save immediately into the reborn slot
276 	if (GGameInfo->NetMode < NM_DedicatedServer)
277 	{
278 		SV_SaveGame(SV_GetRebornSlot(), REBORN_DESCRIPTION);
279 	}
280 	unguard;
281 }
282 
283 //==========================================================================
284 //
285 //	VBasePlayer::Printf
286 //
287 //==========================================================================
288 
Printf(const char * s,...)289 void VBasePlayer::Printf(const char *s, ...)
290 {
291 	guard(VBasePlayer::Printf);
292 	va_list	v;
293 	char	buf[1024];
294 
295 	va_start(v, s);
296 	vsprintf(buf, s, v);
297 	va_end(v);
298 
299 	eventClientPrint(buf);
300 	unguard;
301 }
302 
303 //==========================================================================
304 //
305 //	VBasePlayer::CentrePrintf
306 //
307 //==========================================================================
308 
CentrePrintf(const char * s,...)309 void VBasePlayer::CentrePrintf(const char *s, ...)
310 {
311 	guard(VBasePlayer::CentrePrintf);
312 	va_list	v;
313 	char	buf[1024];
314 
315 	va_start(v, s);
316 	vsprintf(buf, s, v);
317 	va_end(v);
318 
319 	eventClientCentrePrint(buf);
320 	unguard;
321 }
322 
323 //===========================================================================
324 //
325 //  VBasePlayer::SetViewState
326 //
327 //===========================================================================
328 
SetViewState(int position,VState * stnum)329 void VBasePlayer::SetViewState(int position, VState* stnum)
330 {
331 	guard(VBasePlayer::SetViewState);
332 	VViewState& VSt = ViewStates[position];
333 	VState *state = stnum;
334 	do
335 	{
336 		if (!state)
337 		{
338 			// Object removed itself.
339 			VSt.State = NULL;
340 			VSt.StateTime = -1;
341 			break;
342 		}
343 		VSt.State = state;
344 		VSt.StateTime = state->Time;	// could be 0
345 		if (state->Misc1)
346 		{
347 			VSt.SX = state->Misc1;
348 		}
349 		if (state->Misc2)
350 		{
351 			VSt.SY = state->Misc2;
352 		}
353 		// Call action routine.
354 		if (state->Function)
355 		{
356 			Level->XLevel->CallingState = state;
357 			P_PASS_REF(MO);
358 			ExecuteFunction(state->Function);
359 			if (!VSt.State)
360 			{
361 				break;
362 			}
363 		}
364 		state = VSt.State->NextState;
365 	}
366 	while (!VSt.StateTime);	// An initial state of 0 could cycle through.
367 	unguard;
368 }
369 
370 //==========================================================================
371 //
372 //	VBasePlayer::AdvanceViewStates
373 //
374 //==========================================================================
375 
AdvanceViewStates(float deltaTime)376 void VBasePlayer::AdvanceViewStates(float deltaTime)
377 {
378 	for (int i = 0; i < NUMPSPRITES; i++)
379 	{
380 		VViewState& St = ViewStates[i];
381 		// a null state means not active
382 		if (St.State)
383 		{
384 			// drop tic count and possibly change state
385 			// a -1 tic count never changes
386 			if (St.StateTime != -1.0)
387 			{
388 				St.StateTime -= deltaTime;
389 				if (St.StateTime <= 0.0)
390 				{
391 					St.StateTime = 0.0;
392 					SetViewState(i, St.State->NextState);
393 				}
394 			}
395 		}
396 	}
397 }
398 
399 //==========================================================================
400 //
401 //	VBasePlayer::SetUserInfo
402 //
403 //==========================================================================
404 
SetUserInfo(const VStr & info)405 void VBasePlayer::SetUserInfo(const VStr& info)
406 {
407 	guard(VBasePlayer::SetUserInfo);
408 	if (!sv_loading)
409 	{
410 		UserInfo = info;
411 		ReadFromUserInfo();
412 	}
413 	unguard;
414 }
415 
416 //==========================================================================
417 //
418 //	VBasePlayer::ReadFromUserInfo
419 //
420 //==========================================================================
421 
ReadFromUserInfo()422 void VBasePlayer::ReadFromUserInfo()
423 {
424 	guard(VBasePlayer::ReadFromUserInfo);
425 	if (!sv_loading)
426 	{
427 		BaseClass = atoi(*Info_ValueForKey(UserInfo, "class"));
428 	}
429 	PlayerName = Info_ValueForKey(UserInfo, "name");
430 	Colour = M_ParseColour(Info_ValueForKey(UserInfo, "colour"));
431 	eventUserinfoChanged();
432 	unguard;
433 }
434 
435 //==========================================================================
436 //
437 //	VBasePlayer::DoClientStartSound
438 //
439 //==========================================================================
440 
DoClientStartSound(int SoundId,TVec Org,int OriginId,int Channel,float Volume,float Attenuation,bool Loop)441 void VBasePlayer::DoClientStartSound(int SoundId, TVec Org, int OriginId,
442 	int Channel, float Volume, float Attenuation, bool Loop)
443 {
444 #ifdef CLIENT
445 	guard(VBasePlayer::DoClientStartSound);
446 	GAudio->PlaySound(SoundId, Org, TVec(0, 0, 0), OriginId, Channel, Volume,
447 		Attenuation, Loop);
448 	unguard;
449 #endif
450 }
451 
452 //==========================================================================
453 //
454 //	VBasePlayer::DoClientStopSound
455 //
456 //==========================================================================
457 
DoClientStopSound(int OriginId,int Channel)458 void VBasePlayer::DoClientStopSound(int OriginId, int Channel)
459 {
460 #ifdef CLIENT
461 	guard(VBasePlayer::DoClientStopSound);
462 	GAudio->StopSound(OriginId, Channel);
463 	unguard;
464 #endif
465 }
466 
467 //==========================================================================
468 //
469 //	VBasePlayer::DoClientStartSequence
470 //
471 //==========================================================================
472 
DoClientStartSequence(TVec Origin,int OriginId,VName Name,int ModeNum)473 void VBasePlayer::DoClientStartSequence(TVec Origin, int OriginId, VName Name,
474 	int ModeNum)
475 {
476 #ifdef CLIENT
477 	guard(VBasePlayer::DoClientStartSequence);
478 	GAudio->StartSequence(OriginId, Origin, Name, ModeNum);
479 	unguard;
480 #endif
481 }
482 
483 //==========================================================================
484 //
485 //	VBasePlayer::DoClientAddSequenceChoice
486 //
487 //==========================================================================
488 
DoClientAddSequenceChoice(int OriginId,VName Choice)489 void VBasePlayer::DoClientAddSequenceChoice(int OriginId, VName Choice)
490 {
491 #ifdef CLIENT
492 	guard(VBasePlayer::DoClientAddSequenceChoice);
493 	GAudio->AddSeqChoice(OriginId, Choice);
494 	unguard;
495 #endif
496 }
497 
498 //==========================================================================
499 //
500 //	VBasePlayer::DoClientStopSequence
501 //
502 //==========================================================================
503 
DoClientStopSequence(int OriginId)504 void VBasePlayer::DoClientStopSequence(int OriginId)
505 {
506 #ifdef CLIENT
507 	guard(VBasePlayer::DoClientStopSequence);
508 	GAudio->StopSequence(OriginId);
509 	unguard;
510 #endif
511 }
512 
513 //==========================================================================
514 //
515 //	VBasePlayer::DoClientPrint
516 //
517 //==========================================================================
518 
DoClientPrint(VStr AStr)519 void VBasePlayer::DoClientPrint(VStr AStr)
520 {
521 	guard(VBasePlayer::DoClientPrint);
522 	VStr Str(AStr);
523 
524 	if (Str.IsEmpty())
525 	{
526 		return;
527 	}
528 
529 	if (Str[0] == '$')
530 	{
531 		Str = GLanguage[*VStr(Str.ToLower(), 1, Str.Length() - 1)];
532 	}
533 
534 	if (msg_echo)
535 	{
536 		GCon->Log(Str);
537 	}
538 
539 	ClGame->eventAddNotifyMessage(Str);
540 	unguard;
541 }
542 
543 //==========================================================================
544 //
545 //	VBasePlayer::DoClientCentrePrint
546 //
547 //==========================================================================
548 
DoClientCentrePrint(VStr Str)549 void VBasePlayer::DoClientCentrePrint(VStr Str)
550 {
551 	guard(VBasePlayer::DoClientCentrePrint);
552 	VStr Msg(Str);
553 
554 	if (Msg.IsEmpty())
555 	{
556 		return;
557 	}
558 
559 	if (Msg[0] == '$')
560 	{
561 		Msg = GLanguage[*VStr(Msg.ToLower(), 1, Msg.Length() - 1)];
562 	}
563 
564 	if (msg_echo)
565 	{
566 		GCon->Log("<-------------------------------->");
567 		GCon->Log(Msg);
568 		GCon->Log("<-------------------------------->");
569 	}
570 
571 	ClGame->eventAddCentreMessage(Msg);
572 	unguard;
573 }
574 
575 //==========================================================================
576 //
577 //	VBasePlayer::DoClientSetAngles
578 //
579 //==========================================================================
580 
DoClientSetAngles(TAVec Angles)581 void VBasePlayer::DoClientSetAngles(TAVec Angles)
582 {
583 	guard(VBasePlayer::DoClientSetAngles);
584 	ViewAngles = Angles;
585 	ViewAngles.pitch = AngleMod180(ViewAngles.pitch);
586 	unguard;
587 }
588 
589 //==========================================================================
590 //
591 //	VBasePlayer::DoClientIntermission
592 //
593 //==========================================================================
594 
DoClientIntermission(VName NextMap)595 void VBasePlayer::DoClientIntermission(VName NextMap)
596 {
597 	guard(VBasePlayer::DoClientIntermission);
598 	im_t& im = ClGame->im;
599 
600 	im.Text.Clean();
601 	im.IMFlags = 0;
602 
603 	const mapInfo_t& linfo = P_GetMapInfo(Level->XLevel->MapName);
604 	im.LeaveMap = Level->XLevel->MapName;
605 	im.LeaveCluster = linfo.Cluster;
606 	im.LeaveName = linfo.GetName();
607 	im.LeaveTitlePatch = linfo.TitlePatch;
608 	im.ExitPic = linfo.ExitPic;
609 	im.InterMusic = linfo.InterMusic;
610 
611 	const mapInfo_t& einfo = P_GetMapInfo(NextMap);
612 	im.EnterMap = NextMap;
613 	im.EnterCluster = einfo.Cluster;
614 	im.EnterName = einfo.GetName();
615 	im.EnterTitlePatch = einfo.TitlePatch;
616 	im.EnterPic = einfo.EnterPic;
617 
618 	if (linfo.Cluster != einfo.Cluster)
619 	{
620 		if (einfo.Cluster)
621 		{
622 			const VClusterDef* CDef = P_GetClusterDef(einfo.Cluster);
623 			if (CDef->EnterText.Length())
624 			{
625 				if (CDef->Flags & CLUSTERF_LookupEnterText)
626 				{
627 					im.Text = GLanguage[*CDef->EnterText];
628 				}
629 				else
630 				{
631 					im.Text = CDef->EnterText;
632 				}
633 				if (CDef->Flags & CLUSTERF_EnterTextIsLump)
634 				{
635 					im.IMFlags |= im_t::IMF_TextIsLump;
636 				}
637 				if (CDef->Flags & CLUSTERF_FinalePic)
638 				{
639 					im.TextFlat = NAME_None;
640 					im.TextPic = CDef->Flat;
641 				}
642 				else
643 				{
644 					im.TextFlat = CDef->Flat;
645 					im.TextPic = NAME_None;
646 				}
647 				im.TextMusic = CDef->Music;
648 				im.TextCDTrack = CDef->CDTrack;
649 				im.TextCDId = CDef->CDId;
650 			}
651 		}
652 		if (im.Text.Length() == 0 && linfo.Cluster)
653 		{
654 			const VClusterDef* CDef = P_GetClusterDef(linfo.Cluster);
655 			if (CDef->ExitText.Length())
656 			{
657 				if (CDef->Flags & CLUSTERF_LookupExitText)
658 				{
659 					im.Text = GLanguage[*CDef->ExitText];
660 				}
661 				else
662 				{
663 					im.Text = CDef->ExitText;
664 				}
665 				if (CDef->Flags & CLUSTERF_ExitTextIsLump)
666 				{
667 					im.IMFlags |= im_t::IMF_TextIsLump;
668 				}
669 				if (CDef->Flags & CLUSTERF_FinalePic)
670 				{
671 					im.TextFlat = NAME_None;
672 					im.TextPic = CDef->Flat;
673 				}
674 				else
675 				{
676 					im.TextFlat = CDef->Flat;
677 					im.TextPic = NAME_None;
678 				}
679 				im.TextMusic = CDef->Music;
680 				im.TextCDTrack = CDef->CDTrack;
681 				im.TextCDId = CDef->CDId;
682 			}
683 		}
684 	}
685 
686 	ClGame->intermission = 1;
687 #ifdef CLIENT
688 	AM_Stop();
689 	GAudio->StopAllSequences();
690 #endif
691 
692 	ClGame->eventIintermissionStart();
693 	unguard;
694 }
695 
696 //==========================================================================
697 //
698 //	VBasePlayer::DoClientPause
699 //
700 //==========================================================================
701 
DoClientPause(bool Paused)702 void VBasePlayer::DoClientPause(bool Paused)
703 {
704 #ifdef CLIENT
705 	guard(VBasePlayer::DoClientPause);
706 	if (Paused)
707 	{
708 		GGameInfo->Flags |= VGameInfo::GIF_Paused;
709 		GAudio->PauseSound();
710 	}
711 	else
712 	{
713 		GGameInfo->Flags &= ~VGameInfo::GIF_Paused;
714 		GAudio->ResumeSound();
715 	}
716 	unguard;
717 #endif
718 }
719 
720 //==========================================================================
721 //
722 //	VBasePlayer::DoClientSkipIntermission
723 //
724 //==========================================================================
725 
DoClientSkipIntermission()726 void VBasePlayer::DoClientSkipIntermission()
727 {
728 	guard(VBasePlayer::DoClientSkipIntermission);
729 	ClGame->ClientFlags |= VClientGameBase::CF_SkipIntermission;
730 	unguard;
731 }
732 
733 //==========================================================================
734 //
735 //	VBasePlayer::DoClientFinale
736 //
737 //==========================================================================
738 
DoClientFinale(VStr Type)739 void VBasePlayer::DoClientFinale(VStr Type)
740 {
741 	guard(VBasePlayer::DoClientFinale);
742 	ClGame->intermission = 2;
743 #ifdef CLIENT
744 	AM_Stop();
745 #endif
746 
747 	ClGame->eventStartFinale(*Type);
748 	unguard;
749 }
750 
751 //==========================================================================
752 //
753 //	VBasePlayer::DoClientChangeMusic
754 //
755 //==========================================================================
756 
DoClientChangeMusic(VName Song,int CDTrack)757 void VBasePlayer::DoClientChangeMusic(VName Song, int CDTrack)
758 {
759 	guard(VBasePlayer::DoClientChangeMusic);
760 	Level->SongLump = Song;
761 	Level->CDTrack = CDTrack;
762 #ifdef CLIENT
763 	GAudio->MusicChanged();
764 #endif
765 	unguard;
766 }
767 
768 //==========================================================================
769 //
770 //	VBasePlayer::DoClientSetServerInfo
771 //
772 //==========================================================================
773 
DoClientSetServerInfo(VStr Key,VStr Value)774 void VBasePlayer::DoClientSetServerInfo(VStr Key, VStr Value)
775 {
776 	guard(VBasePlayer::DoClientSetServerInfo);
777 	Info_SetValueForKey(ClGame->serverinfo, Key, Value);
778 #ifdef CLIENT
779 	CL_ReadFromServerInfo();
780 #endif
781 	unguard;
782 }
783 
784 //==========================================================================
785 //
786 //	VBasePlayer::DoClientHudMessage
787 //
788 //==========================================================================
789 
DoClientHudMessage(const VStr & Message,VName Font,int Type,int Id,int Colour,const VStr & ColourName,float x,float y,int HudWidth,int HudHeight,float HoldTime,float Time1,float Time2)790 void VBasePlayer::DoClientHudMessage(const VStr& Message, VName Font, int Type,
791 	int Id, int Colour, const VStr& ColourName, float x, float y,
792 	int HudWidth, int HudHeight, float HoldTime, float Time1, float Time2)
793 {
794 	guard(VBasePlayer::DoClientHudMessage);
795 	ClGame->eventAddHudMessage(Message, Font, Type, Id, Colour, ColourName,
796 		x, y, HudWidth, HudHeight, HoldTime, Time1, Time2);
797 	unguard;
798 }
799 
800 //==========================================================================
801 //
802 //	VBasePlayer::WriteViewData
803 //
804 //==========================================================================
805 
WriteViewData()806 void VBasePlayer::WriteViewData()
807 {
808 	guard(VBasePlayer::WriteViewData);
809 	//	Update bam_angles (after teleportation)
810 	if (PlayerFlags & PF_FixAngle)
811 	{
812 		PlayerFlags &= ~PF_FixAngle;
813 		eventClientSetAngles(ViewAngles);
814 	}
815 	unguard;
816 }
817 
818 //==========================================================================
819 //
820 //	COMMAND SetInfo
821 //
822 //==========================================================================
823 
COMMAND(SetInfo)824 COMMAND(SetInfo)
825 {
826 	guard(COMMAND SetInfo);
827 	if (Source != SRC_Client)
828 	{
829 		GCon->Log("SetInfo is not valid from console");
830 		return;
831 	}
832 
833 	if (Args.Num() != 3)
834 	{
835 		return;
836 	}
837 
838 	Info_SetValueForKey(Player->UserInfo, *Args[1], *Args[2]);
839 	Player->ReadFromUserInfo();
840 	unguard;
841 }
842 
843 //==========================================================================
844 //
845 //	Natives
846 //
847 //==========================================================================
848 
IMPLEMENT_FUNCTION(VBasePlayer,cprint)849 IMPLEMENT_FUNCTION(VBasePlayer, cprint)
850 {
851 	VStr msg = PF_FormatString();
852 	P_GET_SELF;
853 	Self->eventClientPrint(*msg);
854 }
855 
IMPLEMENT_FUNCTION(VBasePlayer,centreprint)856 IMPLEMENT_FUNCTION(VBasePlayer, centreprint)
857 {
858 	VStr msg = PF_FormatString();
859 	P_GET_SELF;
860 	Self->eventClientCentrePrint(*msg);
861 }
862 
IMPLEMENT_FUNCTION(VBasePlayer,GetPlayerNum)863 IMPLEMENT_FUNCTION(VBasePlayer, GetPlayerNum)
864 {
865 	P_GET_SELF;
866 	RET_INT(SV_GetPlayerNum(Self));
867 }
868 
IMPLEMENT_FUNCTION(VBasePlayer,ClearPlayer)869 IMPLEMENT_FUNCTION(VBasePlayer, ClearPlayer)
870 {
871 	P_GET_SELF;
872 
873 	Self->PClass = 0;
874 	Self->ForwardMove = 0;
875 	Self->SideMove = 0;
876 	Self->FlyMove = 0;
877 	Self->Buttons = 0;
878 	Self->Impulse = 0;
879 	Self->MO = NULL;
880 	Self->PlayerState = 0;
881 	Self->ViewOrg = TVec(0, 0, 0);
882 	Self->PlayerFlags &= ~VBasePlayer::PF_FixAngle;
883 	Self->Health = 0;
884 	Self->PlayerFlags &= ~VBasePlayer::PF_AttackDown;
885 	Self->PlayerFlags &= ~VBasePlayer::PF_UseDown;
886 	Self->PlayerFlags &= ~VBasePlayer::PF_AutomapRevealed;
887 	Self->PlayerFlags &= ~VBasePlayer::PF_AutomapShowThings;
888 	Self->ExtraLight = 0;
889 	Self->FixedColourmap = 0;
890 	Self->CShift = 0;
891 	Self->PSpriteSY = 0;
892 
893 	vuint8* Def = Self->GetClass()->Defaults;
894 	for (VField* F = Self->GetClass()->Fields; F; F = F->Next)
895 	{
896 		VField::CopyFieldValue(Def + F->Ofs, (vuint8*)Self + F->Ofs, F->Type);
897 	}
898 }
899 
IMPLEMENT_FUNCTION(VBasePlayer,SetViewState)900 IMPLEMENT_FUNCTION(VBasePlayer, SetViewState)
901 {
902 	P_GET_PTR(VState, stnum);
903 	P_GET_INT(position);
904 	P_GET_SELF;
905 	Self->SetViewState(position, stnum);
906 }
907 
IMPLEMENT_FUNCTION(VBasePlayer,AdvanceViewStates)908 IMPLEMENT_FUNCTION(VBasePlayer, AdvanceViewStates)
909 {
910 	P_GET_FLOAT(deltaTime);
911 	P_GET_SELF;
912 	Self->AdvanceViewStates(deltaTime);
913 }
914 
IMPLEMENT_FUNCTION(VBasePlayer,DisconnectBot)915 IMPLEMENT_FUNCTION(VBasePlayer, DisconnectBot)
916 {
917 	P_GET_SELF;
918 	check(Self->PlayerFlags & PF_IsBot);
919 	SV_DropClient(Self, false);
920 }
921 
IMPLEMENT_FUNCTION(VBasePlayer,ClientStartSound)922 IMPLEMENT_FUNCTION(VBasePlayer, ClientStartSound)
923 {
924 	P_GET_BOOL(Loop);
925 	P_GET_FLOAT(Attenuation);
926 	P_GET_FLOAT(Volume);
927 	P_GET_INT(Channel);
928 	P_GET_INT(OriginId);
929 	P_GET_VEC(Org);
930 	P_GET_INT(SoundId);
931 	P_GET_SELF;
932 	Self->DoClientStartSound(SoundId, Org, OriginId, Channel, Volume,
933 		Attenuation, Loop);
934 }
935 
IMPLEMENT_FUNCTION(VBasePlayer,ClientStopSound)936 IMPLEMENT_FUNCTION(VBasePlayer, ClientStopSound)
937 {
938 	P_GET_INT(Channel);
939 	P_GET_INT(OriginId);
940 	P_GET_SELF;
941 	Self->DoClientStopSound(OriginId, Channel);
942 }
943 
IMPLEMENT_FUNCTION(VBasePlayer,ClientStartSequence)944 IMPLEMENT_FUNCTION(VBasePlayer, ClientStartSequence)
945 {
946 	P_GET_INT(ModeNum);
947 	P_GET_NAME(Name);
948 	P_GET_INT(OriginId);
949 	P_GET_VEC(Origin);
950 	P_GET_SELF;
951 	Self->DoClientStartSequence(Origin, OriginId, Name, ModeNum);
952 }
953 
IMPLEMENT_FUNCTION(VBasePlayer,ClientAddSequenceChoice)954 IMPLEMENT_FUNCTION(VBasePlayer, ClientAddSequenceChoice)
955 {
956 	P_GET_NAME(Choice);
957 	P_GET_INT(OriginId);
958 	P_GET_SELF;
959 	Self->DoClientAddSequenceChoice(OriginId, Choice);
960 }
961 
IMPLEMENT_FUNCTION(VBasePlayer,ClientStopSequence)962 IMPLEMENT_FUNCTION(VBasePlayer, ClientStopSequence)
963 {
964 	P_GET_INT(OriginId);
965 	P_GET_SELF;
966 	Self->DoClientStopSequence(OriginId);
967 }
968 
IMPLEMENT_FUNCTION(VBasePlayer,ClientPrint)969 IMPLEMENT_FUNCTION(VBasePlayer, ClientPrint)
970 {
971 	P_GET_STR(Str);
972 	P_GET_SELF;
973 	Self->DoClientPrint(Str);
974 }
975 
IMPLEMENT_FUNCTION(VBasePlayer,ClientCentrePrint)976 IMPLEMENT_FUNCTION(VBasePlayer, ClientCentrePrint)
977 {
978 	P_GET_STR(Str);
979 	P_GET_SELF;
980 	Self->DoClientCentrePrint(Str);
981 }
982 
IMPLEMENT_FUNCTION(VBasePlayer,ClientSetAngles)983 IMPLEMENT_FUNCTION(VBasePlayer, ClientSetAngles)
984 {
985 	P_GET_AVEC(Angles);
986 	P_GET_SELF;
987 	Self->DoClientSetAngles(Angles);
988 }
989 
IMPLEMENT_FUNCTION(VBasePlayer,ClientIntermission)990 IMPLEMENT_FUNCTION(VBasePlayer, ClientIntermission)
991 {
992 	P_GET_NAME(NextMap);
993 	P_GET_SELF;
994 	Self->DoClientIntermission(NextMap);
995 }
996 
IMPLEMENT_FUNCTION(VBasePlayer,ClientPause)997 IMPLEMENT_FUNCTION(VBasePlayer, ClientPause)
998 {
999 	P_GET_BOOL(Paused);
1000 	P_GET_SELF;
1001 	Self->DoClientPause(Paused);
1002 }
1003 
IMPLEMENT_FUNCTION(VBasePlayer,ClientSkipIntermission)1004 IMPLEMENT_FUNCTION(VBasePlayer, ClientSkipIntermission)
1005 {
1006 	P_GET_SELF;
1007 	Self->DoClientSkipIntermission();
1008 }
1009 
IMPLEMENT_FUNCTION(VBasePlayer,ClientFinale)1010 IMPLEMENT_FUNCTION(VBasePlayer, ClientFinale)
1011 {
1012 	P_GET_STR(Type);
1013 	P_GET_SELF;
1014 	Self->DoClientFinale(Type);
1015 }
1016 
IMPLEMENT_FUNCTION(VBasePlayer,ClientChangeMusic)1017 IMPLEMENT_FUNCTION(VBasePlayer, ClientChangeMusic)
1018 {
1019 	P_GET_INT(CDTrack);
1020 	P_GET_NAME(Song);
1021 	P_GET_SELF;
1022 	Self->DoClientChangeMusic(Song, CDTrack);
1023 }
1024 
IMPLEMENT_FUNCTION(VBasePlayer,ClientSetServerInfo)1025 IMPLEMENT_FUNCTION(VBasePlayer, ClientSetServerInfo)
1026 {
1027 	P_GET_STR(Value);
1028 	P_GET_STR(Key);
1029 	P_GET_SELF;
1030 	Self->DoClientSetServerInfo(Key, Value);
1031 }
1032 
IMPLEMENT_FUNCTION(VBasePlayer,ClientHudMessage)1033 IMPLEMENT_FUNCTION(VBasePlayer, ClientHudMessage)
1034 {
1035 	P_GET_FLOAT(Time2);
1036 	P_GET_FLOAT(Time1);
1037 	P_GET_FLOAT(HoldTime);
1038 	P_GET_INT(HudHeight);
1039 	P_GET_INT(HudWidth);
1040 	P_GET_FLOAT(y);
1041 	P_GET_FLOAT(x);
1042 	P_GET_STR(ColourName);
1043 	P_GET_INT(Colour);
1044 	P_GET_INT(Id);
1045 	P_GET_INT(Type);
1046 	P_GET_NAME(Font);
1047 	P_GET_STR(Message);
1048 	P_GET_SELF;
1049 	Self->DoClientHudMessage(Message, Font, Type, Id, Colour, ColourName,
1050 		x, y, HudWidth, HudHeight, HoldTime, Time1, Time2);
1051 }
1052 
IMPLEMENT_FUNCTION(VBasePlayer,ServerSetUserInfo)1053 IMPLEMENT_FUNCTION(VBasePlayer, ServerSetUserInfo)
1054 {
1055 	P_GET_STR(Info);
1056 	P_GET_SELF;
1057 	Self->SetUserInfo(Info);
1058 }
1059