Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions addons/HotelPvP/Missions/AFM_CastlePvP.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
SCR_MissionHeader {
World "{45620F6086F3F8CE}worlds/AF_PvP_Castle.ent"
m_sName "Castle PvP"
m_sAuthor "nielu"
m_sPath "Missions/AFM_CastlePvP.conf"
m_sGameMode "HotelPvP"
m_iPlayerCount 32
m_bRandomStartingDaytime 1
m_bRandomStartingWeather 1
m_bRandomWeatherChanges 1
m_ACE_Settings ACE_MissionHeaderSettings "{6532C72CAE76101C}" {
}
}
17 changes: 17 additions & 0 deletions addons/HotelPvP/Missions/AFM_CastlePvP.conf.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
MetaFileClass {
Name "{6417B9D078A9A0DF}Missions/AFM_CastlePvP.conf"
Configurations {
CONFResourceClass PC {
}
CONFResourceClass XBOX_ONE : PC {
}
CONFResourceClass XBOX_SERIES : PC {
}
CONFResourceClass PS4 : PC {
}
CONFResourceClass PS5 : PC {
}
CONFResourceClass HEADLESS : PC {
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MetaFileClass {
Name "{1ED1D1195A34B82C}Prefabs/Characters/Factions/CIV/ConstructionWorker/AFM_SpectatorLoadout.et"
Name "{8F36955EBE79FE95}Prefabs/Characters/AFM_SpectatorLoadout.et"
Configurations {
EntityTemplateResourceClass PC {
}
Expand Down
89 changes: 85 additions & 4 deletions addons/HotelPvP/Prefabs/MP/Modes/AFM_FactoryPvPGameMode.et
Original file line number Diff line number Diff line change
@@ -1,11 +1,50 @@
AFM_FactoryPvPGameMode : "{0F307326459A1395}Prefabs/MP/Modes/GameMode_Base.et" {
ID "56B2B479C6B96951"
components {
AFM_ScenarioTimeAndWeatherManager "{64E69CD1F1F8FEAE}" {
m_bUseCustomWeather 1
m_aWeatherTemplates {
"Clear" "Foggy" "Overcast" "Cloudy"
}
m_bUseCustomTime 1
m_aTimeOfDayTemplates {
20.125 12 6.5 17.25 9.1 7.1 19.5
}
}
SCR_CustomAreaMeshComponent "{64B2AC457E72AFFD}" {
Enabled 0
m_fHeight 25
m_vResolution 32
m_Material "{E65E61D1541003E2}Assets/Editor/VirtualArea/VirtualArea.emat"
m_fRadius 80
m_fRadius 65
}
SCR_DebriefingScreenComponent "{609C96D6715AA822}" {
m_sHeaderTitle "Castle PvP"
m_BaseLayout SCR_DebriefingScreenUnevenFourTiles "{609C96D6A2B38690}" {
m_TopLeftTile SCR_DebriefingScreenBigImageContent "{5D349E27CFE0247B}" {
m_sContentImage "{EC0B73DC1409A326}UI/Textures/MissionLoadingScreens/CAH_Castle_UI.edds"
}
m_BottomLeftTile SCR_DebriefingScreenSummaryContent "{5D349E27FA750E5E}" {
m_sTitleText "#AR-DebriefingScreen_Debriefing"
m_sSubtitleText "#AR-DebriefingScreen_Subtitle"
m_sSubtitleLostText "#AR-DebriefingScreen_Subtitle_Lost"
}
m_BottomRightTile SCR_DebriefingScreenStatisticsContent "{5D349E27FB89309F}" {
m_sTitleText "#AR-DebriefingScreen_Statistics"
m_aStatistics {
SCR_DebriefingScreenStatisticShotsFired "{5D4272AF9F27F9ED}" {
}
SCR_DebriefingScreenStatisticKills "{5D4272AF9DC59980}" {
}
SCR_DebriefingScreenStatisticDeaths "{5D4272AF9043F083}" {
}
SCR_DebriefingScreenStatisticDistanceWalked "{5D4272AF91FE0EB2}" {
}
SCR_DebriefingScreenStatisticDistanceDriven "{5D4272AF97A47B7E}" {
}
}
}
}
}
SCR_NametagConfigComponent "{571AA9E54FC9210D}" {
m_sConfigPath "{09F7AAA14A642683}Configs/NameTags/NametagFriendlies.conf"
Expand All @@ -15,6 +54,7 @@ AFM_FactoryPvPGameMode : "{0F307326459A1395}Prefabs/MP/Modes/GameMode_Base.et" {
}
}
SCR_RespawnTimerComponent "{64B12EE9157C9AA4}" {
m_fRespawnTime 1
}
SCR_ScoringSystemComponent "{64B12EE9157C9AA2}" {
m_aActions {
Expand All @@ -23,13 +63,54 @@ AFM_FactoryPvPGameMode : "{0F307326459A1395}Prefabs/MP/Modes/GameMode_Base.et" {
}
}
}
SCR_WelcomeScreenComponent "{5D34CBCAF837769A}" {
m_sHeaderTitle "Lorem ipsum "
m_sHeaderSubtitle "dolor sit amet"
m_BaseLayout SCR_WelcomeScreenThreeHorizontalColumns "{5D34CBCBB2A8004F}" {
m_LeftColumn SCR_WelcomeScreenFactionContent "{64E69CD09374290F}" {
m_sTitleText "#AR-DeployScreen_AvailableFactionsTitle"
}
m_MiddleColumn SCR_WelcomeScreenMissionObjectivesContent "{64E69CD086330254}" {
m_sTitleText "#AR-DebriefingScreen_Objectives"
m_aMissionObjectives {
SCR_WelcomeScreenMissionObjectives "{64E69CD0B287904B}" {
m_sObjectiveQuadName "Seize"
m_sDescription "Rescue Donald Trump from the brits"
}
SCR_WelcomeScreenMissionObjectives "{64E69CD2F0D08132}" {
m_sObjectiveQuadName "Defend"
m_sDescription "Prevent yanks from rescuing our hostage"
}
}
}
m_RightColumn SCR_WelcomeScreenIntroductionContent "{5D3684175D904147}" {
m_sTitleText "Lorem ipsum"
m_aIntroduction {
SCR_WelcomeScreenIntroduction "{5D36841751E1D099}" {
m_sContentImage "{EC0B73DC1409A326}UI/Textures/MissionLoadingScreens/CAH_Castle_UI.edds"
m_sContentTitleText "Lorem ipsum"
m_sContentDescriptionText "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
}
SCR_WelcomeScreenIntroduction "{5D36841756EB2304}" {
m_sContentImage "{EC0B73DC1409A326}UI/Textures/MissionLoadingScreens/CAH_Castle_UI.edds"
m_sContentTitleText "Lorem ipsum"
m_sContentDescriptionText "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
}
}
}
}
}
}
PlayerControllerPrefab "{4B7AF7F3DA06BCCE}Prefabs/Characters/Core/AFM_PlayerControllerMP.et"
m_aDisabledResourceTypes {
0
}
m_RedforFactionKey "USSR"
m_sDefenderFactionKey "UK"
m_iGameStartDelaySeconds 180
m_iGameAreaRadius 80
m_pPrisonerPrefab "{1ED1D1195A34B82C}Prefabs/Characters/AFM_SpectatorLoadout.et"
m_TimeoutWinnerFactionKey "UK"
m_iGameAreaRadius 65
m_pPrisonerPrefab "{8F36955EBE79FE95}Prefabs/Characters/Core/AFM_SpectatorLoadout.et"
m_aRestrictionZoneNames {
"attackers_zone" "defenders_zone"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class AFM_FactoryPvPGameMode : SCR_BaseGameMode
[Attribute(uiwidget: UIWidgets.ResourceNamePicker, desc: "Spectator loadout prefab", params: "et", category: "Prefabs")]
ResourceName m_pPrisonerPrefab;

[Attribute(desc: "Array of restriction zone names to be disabled at game start")]
ref array<string> m_aRestrictionZoneNames;

protected SCR_FactionManager m_FactionManager;

protected ref ScriptInvoker m_OnMatchSituationChanged;
Expand All @@ -41,6 +44,9 @@ class AFM_FactoryPvPGameMode : SCR_BaseGameMode
[RplProp(onRplName: "OnMatchSituationChanged")]
protected bool m_bHasGameStarted = false;

[RplProp(onRplName: "OnMatchSituationChanged")]
protected bool m_bHasPreGameStarted = false;

[RplProp(onRplName: "OnMatchSituationChanged")]
protected int m_iDefendersRemaining = 0;

Expand Down Expand Up @@ -101,6 +107,35 @@ class AFM_FactoryPvPGameMode : SCR_BaseGameMode
Print("Faction manager component is missing!", LogLevel.ERROR);
}

GetOnPlayerSpawned().Insert(OnPlayerSpawn);
}

//------------------------------------------------------------------------------------------------
//! Server-side method to handle player spawns
//! This will launch the scenario into pregame state when first player connects
//! and update scoring table on every player joining game
protected void OnPlayerSpawn(int playerId, IEntity player)
{
if (!IsMaster()) return;

PrintFormat("Player %1 has spawned", playerId, level: LogLevel.DEBUG);
if (!m_bHasPreGameStarted)
PreGameStart();

GameEndCheck();
OnMatchSituationChanged();
Replication.BumpMe();
}

//------------------------------------------------------------------------------------------------
//! Server-side method to handle pre game start, eg. when at least 1 player has joined
//! This will set up timers and call queue for game start later
protected void PreGameStart()
{
if (m_bHasPreGameStarted) return;
m_bHasPreGameStarted = true;
Print("PreGame starting");

ChimeraWorld world = GetGame().GetWorld();
m_fStartTimestamp = world.GetServerTimestamp().PlusSeconds(m_iGameStartDelaySeconds);
m_fVictoryTimestamp = m_fStartTimestamp.PlusSeconds(m_iGameOverTimeMinutes * 60);
Expand Down Expand Up @@ -148,12 +183,12 @@ class AFM_FactoryPvPGameMode : SCR_BaseGameMode
//------------------------------------------------------------------------------------------------
protected void GameEndCheck()
{
if (!m_bHasGameStarted)
return;

m_iAttackersRemaining = GetFactionRemainingPlayersCount(m_sAttackerFactionKey);
m_iDefendersRemaining = GetFactionRemainingPlayersCount(m_sDefenderFactionKey);

if (!m_bHasGameStarted)
return;

bool attackersDead = m_iAttackersRemaining == 0;
bool defendersDead = m_iDefendersRemaining == 0;
bool hostageStatus = AreAllHostagesFree();
Expand Down Expand Up @@ -302,7 +337,9 @@ class AFM_FactoryPvPGameMode : SCR_BaseGameMode
PlayerController pc = GetGame().GetPlayerManager().GetPlayerController(id);
if (pc)
{
SCR_ChimeraCharacter ent = SCR_ChimeraCharacter.Cast(pc.GetControlledEntity());
SCR_ChimeraCharacter ent = SCR_ChimeraCharacter.Cast(pc.GetControlledEntity());
if (!ent)
continue; //player is not spawned yet
AFM_SpectatorComponent spectator = AFM_SpectatorComponent.Cast(pc.FindComponent(AFM_SpectatorComponent));
SCR_DamageManagerComponent damageManager = ent.GetDamageManager();
if (!damageManager.IsDestroyed() && !spectator.IsSpectatorActive()) {
Expand Down Expand Up @@ -372,18 +409,17 @@ class AFM_FactoryPvPGameMode : SCR_BaseGameMode
if (!restrictionZoneManager)
return;

SCR_EditorRestrictionZoneEntity attackersZone = SCR_EditorRestrictionZoneEntity.Cast(GetWorld().FindEntityByName("attackers_zone"));
if (attackersZone)
{
Print("Removing attacker restiction zone");
restrictionZoneManager.RemoveRestrictionZone(attackersZone);
}

SCR_EditorRestrictionZoneEntity defendersZone = SCR_EditorRestrictionZoneEntity.Cast(GetWorld().FindEntityByName("defenders_zone"));
if (defendersZone)
foreach(string zoneName: m_aRestrictionZoneNames)
{
Print("Removing defender restiction zone");
restrictionZoneManager.RemoveRestrictionZone(defendersZone);
SCR_EditorRestrictionZoneEntity zone = SCR_EditorRestrictionZoneEntity.Cast(GetWorld().FindEntityByName(zoneName));
if (!zone)
{
PrintFormat("Could not cast %1 zone to restriction zone entity - please verify list of restriction zones", zone, level: LogLevel.WARNING);
continue;
}

PrintFormat("Removing %1 restiction zone", zone, level: LogLevel.DEBUG);
restrictionZoneManager.RemoveRestrictionZone(zone);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
class AFM_ScenarioTimeAndWeatherManagerClass : SCR_BaseGameModeComponentClass
{}

class AFM_ScenarioTimeAndWeatherManager : SCR_BaseGameModeComponent
{
//! If enabled custom weather Id will be used on session start. Authority only.
[Attribute(defvalue: "0", desc: "If enabled, random weather Id will be used. Authority only.", category: "Environment")]
bool m_bUseCustomWeather;

[Attribute(desc: "Array of weather ids to choose from on game start")]
ref array<string> m_aWeatherTemplates;

//! If enabled custom time of the day will be used on session start. Authority only.
[Attribute(defvalue: "0", desc: "If enabled, custom time of the day will be used. Authority only.", category: "Environment")]
bool m_bUseCustomTime;

//! Time of the day set on game start. Authority only.
[Attribute(desc: "Time of the day set on game start. Authority only.", category: "Environment", params: "0 24 0.01")]
ref array<float> m_aTimeOfDayTemplates;


//------------------------------------------------------------------------------------------------
//! Initialize the manager.
override void EOnInit(IEntity owner)
{
super.EOnInit(owner);

if(SCR_Global.IsEditMode())
return;

if (m_bUseCustomTime)
SetTimeOfTheDay(m_aTimeOfDayTemplates.GetRandomElement());

if (m_bUseCustomWeather)
SetWeather(m_aWeatherTemplates.GetRandomElement());
}

//------------------------------------------------------------------------------------------------
//! Initializes this manager component and hooks up events.
protected override void OnPostInit(IEntity owner)
{
super.OnPostInit(owner);
SetEventMask(owner, EntityEvent.INIT);
}

//------------------------------------------------------------------------------------------------
//! Forcefully sets weather to provided weatherId. Authority only.
protected void SetWeather(string weatherId)
{
if (!m_pGameMode.IsMaster())
return;

if (weatherId.IsEmpty())
return;

ChimeraWorld world = GetOwner().GetWorld();
if (!world)
return;

TimeAndWeatherManagerEntity weatherManager = world.GetTimeAndWeatherManager();
if (!weatherManager)
{
Print("Cannot initialize weather: TimeAndWeatherManagerEntity not found!", LogLevel.WARNING);
return;
}

Print("AFM_ScenarioTimeAndWeatherManager: Setting weather to " + weatherId);
weatherManager.ForceWeatherTo(true, weatherId, 0.0);
}

//------------------------------------------------------------------------------------------------
//! Forcefully sets time of the day to provided value. Authority only.
protected void SetTimeOfTheDay(float timeOfDay)
{
if (!m_pGameMode.IsMaster())
return;

ChimeraWorld world = GetOwner().GetWorld();
if (!world)
return;

TimeAndWeatherManagerEntity weatherManager = world.GetTimeAndWeatherManager();
if (!weatherManager)
{
Print("Cannot initialize TimeOfTheDay: TimeAndWeatherManagerEntity not found!", LogLevel.WARNING);
return;
}

Print("AFM_ScenarioTimeAndWeatherManager: Setting time to " + timeOfDay);
weatherManager.SetTimeOfTheDay(timeOfDay, true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ class AFM_CarryHostageAction: ACE_Carrying_CarryUserAction

return true;
}

//------------------------------------------------------------------------------------------------
override bool CanBePerformedScript(IEntity user)
{
return true;
}
}
3 changes: 3 additions & 0 deletions addons/HotelPvP/worlds/AF_PvP_Castle.ent
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SubScene {
Parent "{DCC7D0197F92014C}worlds/CaptureAndHold/CAH_BaseWorld.ent"
}
Loading