I am trying to edit the practice arena a bit to see what can be done with it. The code that I have crashes the game at startup. It includes everything from the ArenaPracticeFightMissionController, as it has some values that I thought about starting with. Here is the code:
With my little understanding, I can't see the issue. Any help is appreciated. Thanks!
Code:
using SandBox;
using SandBox.Conversation.MissionLogics;
using SandBox.Missions.MissionLogics;
using SandBox.Missions.MissionLogics.Arena;
using System.Reflection;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.AgentOrigins;
using TaleWorlds.CampaignSystem.CharacterDevelopment;
using TaleWorlds.CampaignSystem.ComponentInterfaces;
using TaleWorlds.CampaignSystem.Encounters;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.Core;
using TaleWorlds.Engine;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.MountAndBlade;
namespace BannerlordRentTheArena
{
public class SubModule : MBSubModuleBase
{
public override void OnMissionBehaviorInitialize(Mission mission)
{
base.OnMissionBehaviorInitialize(mission);
string missionType = mission.GetType().ToString();
//Needs a check if we are in an arena?
//mission.AddMissionBehavior(new LessFightersInPracticeFight());
}
}
internal class LessFightersInPracticeFight : ArenaPracticeFightMissionController
{
private int AISpawnIndex
{
get
{
return _spawnedOpponentAgentCount;
}
}
public new int RemainingOpponentCountFromLastPractice { get; private set; }
public new bool IsPlayerPracticing { get; private set; }
public new int OpponentCountBeatenByPlayer { get; private set; }
public new int RemainingOpponentCount
{
get
{
return 30 - _spawnedOpponentAgentCount + _aliveOpponentCount;
}
}
public new bool IsPlayerSurvived { get; private set; }
public new bool AfterPractice { get; set; }
public override void AfterStart()
{
_settlement = PlayerEncounter.LocationEncounter.Settlement;
InitializeTeams();
GameEntity item = base.Mission.Scene.FindEntityWithTag("tournament_practice") ?? base.Mission.Scene.FindEntityWithTag("tournament_fight");
List<GameEntity> list = Mission.Current.Scene.FindEntitiesWithTag("arena_set").ToList<GameEntity>();
list.Remove(item);
foreach (GameEntity gameEntity in list)
{
gameEntity.Remove(88);
}
_initialSpawnFrames = (from e in base.Mission.Scene.FindEntitiesWithTag("sp_arena")
select e.GetGlobalFrame()).ToList<MatrixFrame>();
_spawnFrames = (from e in base.Mission.Scene.FindEntitiesWithTag("sp_arena_respawn")
select e.GetGlobalFrame()).ToList<MatrixFrame>();
for (int i = 0; i < _initialSpawnFrames.Count; i++)
{
MatrixFrame value = _initialSpawnFrames[i];
value.rotation.OrthonormalizeAccordingToForwardAndKeepUpAsZAxis();
_initialSpawnFrames[i] = value;
}
for (int j = 0; j < _spawnFrames.Count; j++)
{
MatrixFrame value2 = _spawnFrames[j];
value2.rotation.OrthonormalizeAccordingToForwardAndKeepUpAsZAxis();
_spawnFrames[j] = value2;
}
IsPlayerPracticing = false;
_participantAgents = new List<Agent>();
StartPractice();
MissionAgentHandler missionBehavior = base.Mission.GetMissionBehavior<MissionAgentHandler>();
missionBehavior.SpawnPlayer(true, true, false, false, false, "");
missionBehavior.SpawnLocationCharacters(null);
}
private void SpawnPlayerNearTournamentMaster()
{
GameEntity entity = base.Mission.Scene.FindEntityWithTag("sp_player_near_arena_master");
base.Mission.SpawnAgent(new AgentBuildData(CharacterObject.PlayerCharacter).Team(base.Mission.PlayerTeam).InitialFrameFromSpawnPointEntity(entity).NoHorses(true).CivilianEquipment(true).TroopOrigin(new SimpleAgentOrigin(CharacterObject.PlayerCharacter, -1, null, default(UniqueTroopDescriptor))).Controller(Agent.ControllerType.Player), false);
Mission.Current.SetMissionMode(MissionMode.StartUp, false);
}
private Agent SpawnArenaAgent(Team team, MatrixFrame frame)
{
CharacterObject characterObject;
int spawnIndex;
if (team == base.Mission.PlayerTeam)
{
characterObject = CharacterObject.PlayerCharacter;
spawnIndex = 0;
}
else
{
characterObject = _participantCharacters[AISpawnIndex];
spawnIndex = AISpawnIndex;
}
Equipment equipment = new Equipment();
AddRandomWeapons(equipment, spawnIndex);
AddRandomClothes(characterObject, equipment);
Mission mission = base.Mission;
AgentBuildData agentBuildData = new AgentBuildData(characterObject).Team(team).InitialPosition(frame.origin);
Vec2 vec = frame.rotation.f.AsVec2;
vec = vec.Normalized();
Agent agent = mission.SpawnAgent(agentBuildData.InitialDirection(vec).NoHorses(true).Equipment(equipment).TroopOrigin(new SimpleAgentOrigin(characterObject, -1, null, default(UniqueTroopDescriptor))).Controller((characterObject == CharacterObject.PlayerCharacter) ? Agent.ControllerType.Player : Agent.ControllerType.AI), false);
agent.FadeIn();
if (characterObject != CharacterObject.PlayerCharacter)
{
_aliveOpponentCount++;
_spawnedOpponentAgentCount++;
}
if (agent.IsAIControlled)
{
agent.SetWatchState(Agent.WatchState.Alarmed);
}
return agent;
}
public override void OnScoreHit(Agent affectedAgent, Agent affectorAgent, WeaponComponentData attackerWeapon, bool isBlocked, bool isSiegeEngineHit, in Blow blow, in AttackCollisionData collisionData, float damagedHp, float hitDistance, float shotDifficulty)
{
if (affectorAgent == null)
{
return;
}
if (affectorAgent.IsMount && affectorAgent.RiderAgent != null)
{
affectorAgent = affectorAgent.RiderAgent;
}
if (affectorAgent.Character == null || affectedAgent.Character == null)
{
return;
}
float num = (float)blow.InflictedDamage;
if (num > affectedAgent.HealthLimit)
{
num = affectedAgent.HealthLimit;
}
float num2 = num / affectedAgent.HealthLimit;
EnemyHitReward(affectedAgent, affectorAgent, blow.MovementSpeedDamageModifier, shotDifficulty, attackerWeapon, blow.AttackType, 0.5f * num2, num);
}
private void EnemyHitReward(Agent affectedAgent, Agent affectorAgent, float lastSpeedBonus, float lastShotDifficulty, WeaponComponentData attackerWeapon, AgentAttackType attackType, float hitpointRatio, float damageAmount)
{
CharacterObject affectedCharacter = (CharacterObject)affectedAgent.Character;
CharacterObject affectorCharacter = (CharacterObject)affectorAgent.Character;
if (affectedAgent.Origin != null && affectorAgent != null && affectorAgent.Origin != null)
{
bool flag = affectorAgent.MountAgent != null;
bool isHorseCharge = flag && attackType == AgentAttackType.Collision;
SkillLevelingManager.OnCombatHit(affectorCharacter, affectedCharacter, null, null, lastSpeedBonus, lastShotDifficulty, attackerWeapon, hitpointRatio, CombatXpModel.MissionTypeEnum.PracticeFight, flag, affectorAgent.Team == affectedAgent.Team, false, damageAmount, affectedAgent.Health < 1f, false, isHorseCharge);
}
}
public override void OnMissionTick(float dt)
{
base.OnMissionTick(dt);
if (_aliveOpponentCount < 2 && _spawnedOpponentAgentCount < 15 && (_aliveOpponentCount == 1 || _nextSpawnTime < base.Mission.CurrentTime))
{
Team team = SelectRandomAiTeam();
Agent item = SpawnArenaAgent(team, GetSpawnFrame(true, false));
_participantAgents.Add(item);
_nextSpawnTime = base.Mission.CurrentTime + 14f - (float)_spawnedOpponentAgentCount / 3f;
if (_spawnedOpponentAgentCount == 30 && !IsPlayerPracticing)
{
_spawnedOpponentAgentCount = 0;
}
}
if (_teleportTimer == null && IsPlayerPracticing && CheckPracticeEndedForPlayer())
{
_teleportTimer = new BasicMissionTimer();
IsPlayerSurvived = (base.Mission.MainAgent != null && base.Mission.MainAgent.IsActive());
if (IsPlayerSurvived)
{
MBInformationManager.AddQuickInformation(new TextObject("{=seyti8xR}Victory!", null), 0, null, "event:/ui/mission/arena_victory");
}
AfterPractice = true;
}
if (_teleportTimer != null && _teleportTimer.ElapsedTime > (float)TeleportTime)
{
_teleportTimer = null;
RemainingOpponentCountFromLastPractice = RemainingOpponentCount;
IsPlayerPracticing = false;
StartPractice();
SpawnPlayerNearTournamentMaster();
Agent? agent = base.Mission.Agents.FirstOrDefault((Agent x) => x.Character != null && ((CharacterObject)x.Character).Occupation == Occupation.ArenaMaster);
MissionConversationLogic.Current.StartConversation(agent, true, false);
}
}
private Team SelectRandomAiTeam()
{
Team? team = null;
foreach (Team team2 in _AIParticipantTeams)
{
if (!team2.HasBots)
{
team = team2;
break;
}
}
if (team == null)
{
team = _AIParticipantTeams[MBRandom.RandomInt(_AIParticipantTeams.Count - 1) + 1];
}
return team;
}
public override void OnAgentRemoved(Agent affectedAgent, Agent affectorAgent, AgentState agentState, KillingBlow killingBlow)
{
if (affectedAgent != null && affectedAgent.IsHuman)
{
if (affectedAgent != Agent.Main)
{
_aliveOpponentCount--;
}
if (affectorAgent != null && affectorAgent.IsHuman && affectorAgent == Agent.Main && affectedAgent != Agent.Main)
{
int opponentCountBeatenByPlayer = OpponentCountBeatenByPlayer;
OpponentCountBeatenByPlayer = opponentCountBeatenByPlayer + 1;
}
}
if (_participantAgents.Contains(affectedAgent))
{
_participantAgents.Remove(affectedAgent);
}
}
public override bool MissionEnded(ref MissionResult missionResult)
{
return false;
}
public override InquiryData OnEndMissionRequest(out bool canPlayerLeave)
{
canPlayerLeave = true;
if (!IsPlayerPracticing)
{
return null;
}
return new InquiryData(new TextObject("{=zv49qE35}Practice Fight", null).ToString(), GameTexts.FindText("str_give_up_fight", null).ToString(), true, true, GameTexts.FindText("str_ok", null).ToString(), GameTexts.FindText("str_cancel", null).ToString(), new Action(base.Mission.OnEndMissionResult), null, "", 0f, null, null, null);
}
public new void StartPlayerPractice()
{
IsPlayerPracticing = true;
AfterPractice = false;
StartPractice();
}
private void StartPractice()
{
InitializeParticipantCharacters();
SandBoxHelpers.MissionHelper.FadeOutAgents(from agent in base.Mission.Agents
where _participantAgents.Contains(agent) || agent.IsMount || agent.IsPlayerControlled
select agent, true, false);
_spawnedOpponentAgentCount = 0;
_aliveOpponentCount = 0;
_participantAgents.Clear();
Mission.Current.ClearCorpses(false);
base.Mission.RemoveSpawnedItemsAndMissiles();
ArrangePlayerTeamEnmity();
if (IsPlayerPracticing)
{
Agent agent2 = SpawnArenaAgent(base.Mission.PlayerTeam, GetSpawnFrame(false, true));
agent2.WieldInitialWeapons(Agent.WeaponWieldActionType.InstantAfterPickUp, Equipment.InitialWeaponEquipPreference.Any);
OpponentCountBeatenByPlayer = 0;
_participantAgents.Add(agent2);
}
int count = _AIParticipantTeams.Count;
int num = 0;
while (_spawnedOpponentAgentCount < 6)
{
_participantAgents.Add(SpawnArenaAgent(_AIParticipantTeams[num % count], GetSpawnFrame(false, true)));
num++;
}
_nextSpawnTime = base.Mission.CurrentTime + 14f;
}
private bool CheckPracticeEndedForPlayer()
{
return base.Mission.MainAgent == null || !base.Mission.MainAgent.IsActive() || RemainingOpponentCount == 0;
}
private void AddRandomWeapons(Equipment equipment, int spawnIndex)
{
int num = 1 + spawnIndex * 3 / 30;
List<Equipment> list = (Game.Current.ObjectManager.GetObject<CharacterObject>(string.Concat(new object[]
{
"weapon_practice_stage_",
num,
"_",
_settlement.MapFaction.Culture.StringId
})) ?? Game.Current.ObjectManager.GetObject<CharacterObject>("weapon_practice_stage_" + num + "_empire")).BattleEquipments.ToList<Equipment>();
int index = MBRandom.RandomInt(list.Count);
for (int i = 0; i <= 3; i++)
{
EquipmentElement equipmentFromSlot = list[index].GetEquipmentFromSlot((EquipmentIndex)i);
if (equipmentFromSlot.Item != null)
{
equipment.AddEquipmentToSlotWithoutAgent((EquipmentIndex)i, equipmentFromSlot);
}
}
}
private void AddRandomClothes(CharacterObject troop, Equipment equipment)
{
Equipment participantArmor = Campaign.Current.Models.TournamentModel.GetParticipantArmor(troop);
for (int i = 0; i < 12; i++)
{
if (i > 4 && i != 10 && i != 11)
{
EquipmentElement equipmentFromSlot = participantArmor.GetEquipmentFromSlot((EquipmentIndex)i);
if (equipmentFromSlot.Item != null)
{
equipment.AddEquipmentToSlotWithoutAgent((EquipmentIndex)i, equipmentFromSlot);
}
}
}
}
private void InitializeTeams()
{
_AIParticipantTeams = new List<Team>();
base.Mission.Teams.Add(BattleSideEnum.Defender, Hero.MainHero.MapFaction.Color, Hero.MainHero.MapFaction.Color2, null, true, false, true);
base.Mission.PlayerTeam = base.Mission.DefenderTeam;
_tournamentMasterTeam = base.Mission.Teams.Add(BattleSideEnum.None, _settlement.MapFaction.Color, _settlement.MapFaction.Color2, null, true, false, true);
while (_AIParticipantTeams.Count < 6)
{
_AIParticipantTeams.Add(base.Mission.Teams.Add(BattleSideEnum.Attacker, uint.MaxValue, uint.MaxValue, null, true, false, true));
}
for (int i = 0; i < _AIParticipantTeams.Count; i++)
{
_AIParticipantTeams[i].SetIsEnemyOf(_tournamentMasterTeam, false);
for (int j = i + 1; j < _AIParticipantTeams.Count; j++)
{
_AIParticipantTeams[i].SetIsEnemyOf(_AIParticipantTeams[j], true);
}
}
}
private void InitializeParticipantCharacters()
{
List<CharacterObject> participantCharacters = GetParticipantCharacters(_settlement);
_participantCharacters = (from x in participantCharacters
orderby x.Level
select x).ToList<CharacterObject>();
}
public new static List<CharacterObject> GetParticipantCharacters(Settlement settlement)
{
int num = 30;
List<CharacterObject> list = new List<CharacterObject>();
int num2 = 0;
int num3 = 0;
int num4 = 0;
if (list.Count < num && settlement.Town.GarrisonParty != null)
{
foreach (TroopRosterElement troopRosterElement in settlement.Town.GarrisonParty.MemberRoster.GetTroopRoster())
{
int num5 = num - list.Count;
if (!list.Contains(troopRosterElement.Character) && troopRosterElement.Character.Tier == 3 && (float)num5 * 0.4f > (float)num2)
{
list.Add(troopRosterElement.Character);
num2++;
}
else if (!list.Contains(troopRosterElement.Character) && troopRosterElement.Character.Tier == 4 && (float)num5 * 0.4f > (float)num3)
{
list.Add(troopRosterElement.Character);
num3++;
}
else if (!list.Contains(troopRosterElement.Character) && troopRosterElement.Character.Tier == 5 && (float)num5 * 0.2f > (float)num4)
{
list.Add(troopRosterElement.Character);
num4++;
}
if (list.Count >= num)
{
break;
}
}
}
if (list.Count < num)
{
List<CharacterObject> list2 = new List<CharacterObject>();
GetUpgradeTargets(((settlement != null) ? settlement.Culture : Game.Current.ObjectManager.GetObject<CultureObject>("empire")).BasicTroop, ref list2);
int num6 = num - list.Count;
using (List<CharacterObject>.Enumerator enumerator2 = list2.GetEnumerator())
{
while (enumerator2.MoveNext())
{
CharacterObject characterObject = enumerator2.Current;
if (!list.Contains(characterObject) && characterObject.Tier == 3 && (float)num6 * 0.4f > (float)num2)
{
list.Add(characterObject);
num2++;
}
else if (!list.Contains(characterObject) && characterObject.Tier == 4 && (float)num6 * 0.4f > (float)num3)
{
list.Add(characterObject);
num3++;
}
else if (!list.Contains(characterObject) && characterObject.Tier == 5 && (float)num6 * 0.2f > (float)num4)
{
list.Add(characterObject);
num4++;
}
if (list.Count >= num)
{
break;
}
}
goto IL_284;
}
IL_256:
int num7 = 0;
while (num7 < list2.Count && list.Count < num)
{
list.Add(list2[num7]);
num7++;
}
IL_284:
if (list.Count < num)
{
goto IL_256;
}
}
return list;
}
private static void GetUpgradeTargets(CharacterObject troop, ref List<CharacterObject> list)
{
if (!list.Contains(troop) && troop.Tier >= 3)
{
list.Add(troop);
}
CharacterObject[] upgradeTargets = troop.UpgradeTargets;
for (int i = 0; i < upgradeTargets.Length; i++)
{
GetUpgradeTargets(upgradeTargets[i], ref list);
}
}
private void ArrangePlayerTeamEnmity()
{
foreach (Team team in _AIParticipantTeams)
{
team.SetIsEnemyOf(base.Mission.PlayerTeam, IsPlayerPracticing);
}
}
private Team GetStrongestTeamExceptPlayerTeam()
{
Team? result = null;
int num = -1;
foreach (Team team in _AIParticipantTeams)
{
int num2 = CalculateTeamPower(team);
if (num2 > num)
{
result = team;
num = num2;
}
}
return result;
}
private int CalculateTeamPower(Team team)
{
int num = 0;
foreach (Agent agent in team.ActiveAgents)
{
num += agent.Character.Level * agent.KillCount + (int)TaleWorlds.Library.MathF.Sqrt(agent.Health);
}
return num;
}
private MatrixFrame GetSpawnFrame(bool considerPlayerDistance, bool isInitialSpawn)
{
List<MatrixFrame> list = (isInitialSpawn || _spawnFrames.IsEmpty<MatrixFrame>()) ? _initialSpawnFrames : _spawnFrames;
if (list.Count == 1)
{
Debug.FailedAssert("Spawn point count is wrong! Arena practice spawn point set should be used in arena scenes.", "C:\\Develop\\MB3\\Source\\Bannerlord\\SandBox\\Missions\\MissionLogics\\Arena\\cs", "GetSpawnFrame", 615);
return list[0];
}
MatrixFrame result;
if (considerPlayerDistance && Agent.Main != null && Agent.Main.IsActive())
{
int num = MBRandom.RandomInt(list.Count);
result = list[num];
float num2 = float.MinValue;
for (int i = num + 1; i < num + list.Count; i++)
{
MatrixFrame matrixFrame = list[i % list.Count];
float num3 = CalculateLocationScore(matrixFrame);
if (num3 >= 100f)
{
result = matrixFrame;
break;
}
if (num3 > num2)
{
result = matrixFrame;
num2 = num3;
}
}
}
else
{
int num4 = _spawnedOpponentAgentCount;
if (IsPlayerPracticing && Agent.Main != null)
{
num4++;
}
result = list[num4 % list.Count];
}
return result;
}
private float CalculateLocationScore(MatrixFrame matrixFrame)
{
float num = 100f;
float num2 = 0.25f;
float num3 = 0.75f;
if (matrixFrame.origin.DistanceSquared(Agent.Main.Position) < 144f)
{
num *= num2;
}
for (int i = 0; i < _participantAgents.Count; i++)
{
if (_participantAgents[i].Position.DistanceSquared(matrixFrame.origin) < 144f)
{
num *= num3;
}
}
return num;
}
private const int AIParticipantCount = 30;
private const int MaxAliveAgentCount = 6;
private const int MaxSpawnInterval = 14;
private const int MinSpawnDistanceSquared = 144;
private const int TotalStageCount = 3;
private const int PracticeFightTroopTierLimit = 3;
public new int TeleportTime = 5;
private Settlement? _settlement;
private int _spawnedOpponentAgentCount;
private int _aliveOpponentCount;
private float _nextSpawnTime;
private List<MatrixFrame>? _initialSpawnFrames;
private List<MatrixFrame>? _spawnFrames;
private List<Team>? _AIParticipantTeams;
private List<Agent>? _participantAgents;
private Team? _tournamentMasterTeam;
private BasicMissionTimer? _teleportTimer;
private List<CharacterObject>? _participantCharacters;
private const float XpShareForKill = 0.5f;
private const float XpShareForDamage = 0.5f;
//*/
}
}