Player Class Depending on Mode/Chapter

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
AshHouswares
Posts: 145
Joined: Fri Jun 03, 2022 11:31 am
Graphics Processor: Not Listed

Player Class Depending on Mode/Chapter

Post by AshHouswares »

I asked somehting similar a while back. But I never got any real results, most thought this was impossible but I find that hard to believe.

I have a player class (unarmed player). This is the default in my game and represents your character in the main story.
However, I have another "chapter" you can select from the main menu when you start a new game which stars a different character. A different "class".

How can I make it so that the game chooses the right class/character for each chapter/mode? For the main story it must always pick "unarmed player". But for the extra chapter on the new game menu, I want it too instead choose "armed player". This character has different sprites and begins with a weapon. They also have different behaviour, being far more agile. How can I do this depending on what chapter is selected? There must be a way, surely??
Jarewill
 
 
Posts: 1855
Joined: Sun Jul 21, 2019 8:54 am

Re: Player Class Depending on Mode/Chapter

Post by Jarewill »

The closest thing I've found to replicate what you need is to not use chapters at all.
Instead of having different episodes, just have one episode that goes into a dummy map with this script loaded in:

Code: Select all

Script 1 ENTER
{
	int class = PlayerClass(PlayerNumber());
	If(class==0){ChangeLevel("MAP05",0,CHANGELEVEL_NOINTERMISSION,-1);}
	Else If(class==1){ChangeLevel("MAP12",0,CHANGELEVEL_NOINTERMISSION,-1);}
}
This script will run at the map's start up and check the player's class.
If it's the first class, it will switch the map to MAP05, if it's the second class, then it will go to MAP12 instead.
User avatar
22alpha22
Posts: 308
Joined: Fri Feb 21, 2014 5:04 pm
Graphics Processor: nVidia with Vulkan support
Location: Montana, USA

Re: Player Class Depending on Mode/Chapter

Post by 22alpha22 »

I've dealt with a similar issue in the past with my own project. I managed to switch player classes on different episodes by using an event handler to check what map was being entered and change the player class if necessary. This was achieved by spawning a new player pawn of the desired class, switching all relevant player info to the new pawn, and finally destroying the old one. When done right upon entering a map or re spawning, the player won't even notice the change.

Code: Select all

Class AlphaPlayerEventHandler : EventHandler
{
	Override Void PlayerEntered(PlayerEvent E)
	{
		PlayerInfo Player = Players[E.PlayerNumber];
		Let Plr = AlphaPlayerBaseClass(Player.MO);
		String MapName = Level.MapName;

		If (MapName.Left(5) ~== "BONUS")		//Check the map name, if the map is part of the bonus episode, execute the following block
		{
			ACS_NamedExecuteWithResult('Bonus_Episode_Sector_Colors',0,0,0,0);

			If (Plr)	//Only change the player class if they are still the default class
			{
				Plr.A_SetHealth(100,AAPTR_DEFAULT);	//reset their health just in case
				Plr.MaxHealth = 100;

				Let NewPlayer = Actor.Spawn("AlphaOldPlayer",Plr.Pos,NO_REPLACE);	//spawn the new player pawn

				NewPlayer.Angle = Plr.Angle;	//match the new player pawn's angle, pitch and translation to the old one's
				NewPlayer.Pitch = Plr.Pitch;
				NewPlayer.Translation = Plr.Translation;

				If (Plr.TID != 0)
				{
					NewPlayer.ChangeTID(Plr.TID);	//give the new pawn the old one's TID and remove the TID from the old one
					Plr.ChangeTID(0);
					Plr.RemoveFromHash();
				}

				NewPlayer.Target = Plr.Target;	//copy over pointers and player info from the old pawn to the new one
				NewPlayer.Tracer = Plr.Tracer;
				NewPlayer.FriendPlayer = Plr.FriendPlayer;
				NewPlayer.DesignatedTeam = Plr.DesignatedTeam;
				NewPlayer.Score = Plr.Score;
				PlayerPawn(NewPlayer).Player = PlayerPawn(Plr).Player;
				PlayerPawn(Plr).Player.Mo = PlayerPawn(NewPlayer);
				PlayerPawn(Plr).Player.Camera = PlayerPawn(NewPlayer);
				Plr.Player = Null;	//remove player info from the old pawb
				Plr.Destroy();		//destroy the old pawn
				NewPlayer.Player.Cls = "AlphaOldPlayer";

				NewPlayer.A_GiveInventory("AlphaOldFist",1,AAPTR_DEFAULT);		//give the desired starting equipment to the new pawn
				NewPlayer.A_GiveInventory("AlphaOldPistol",1,AAPTR_DEFAULT);
				NewPlayer.A_GiveInventory("Clip",30,AAPTR_DEFAULT);
			}
		}
	}

	Override Void PlayerRespawned(PlayerEvent E)		//if the player dies and is able to respawn, they will respawn as the default class, therefore we must perform the map check and potential pawn switch again
	{
		PlayerInfo Player = Players[E.PlayerNumber];
		Let Plr = AlphaPlayerBaseClass(Player.MO);
		String MapName = Level.MapName;

		If (MapName.Left(5) ~== "BONUS")
		{
			If (Plr)
			{
				Plr.A_SetHealth(100,AAPTR_DEFAULT);
				Plr.MaxHealth = 100;

				Let NewPlayer = Actor.Spawn("AlphaOldPlayer",Plr.Pos,NO_REPLACE);

				NewPlayer.Angle = Plr.Angle;
				NewPlayer.Pitch = Plr.Pitch;
				NewPlayer.Translation = Plr.Translation;

				If (Plr.TID != 0)
				{
					NewPlayer.ChangeTID(Plr.TID);
					Plr.ChangeTID(0);
					Plr.RemoveFromHash();
				}

				NewPlayer.Target = Plr.Target;
				NewPlayer.Tracer = Plr.Tracer;
				NewPlayer.FriendPlayer = Plr.FriendPlayer;
				NewPlayer.DesignatedTeam = Plr.DesignatedTeam;
				NewPlayer.Score = Plr.Score;
				PlayerPawn(NewPlayer).Player = PlayerPawn(Plr).Player;
				PlayerPawn(Plr).Player.Mo = PlayerPawn(NewPlayer);
				PlayerPawn(Plr).Player.Camera = PlayerPawn(NewPlayer);
				Plr.Player = Null;
				Plr.Destroy();

				NewPlayer.A_GiveInventory("AlphaOldFist",1,AAPTR_DEFAULT);
				NewPlayer.A_GiveInventory("AlphaOldPistol",1,AAPTR_DEFAULT);
				NewPlayer.A_GiveInventory("Clip",30,AAPTR_DEFAULT);
			}
		}
	}
}
Post Reply

Return to “Scripting”