public override void Update(float deltaTime) { if (isFinished) { return; } affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList(); foreach (var npc in affectedNpcs) { CharacterTeamType newTeam = (CharacterTeamType)TeamTag; // characters will still remain on friendlyNPC team for rest of the tick npc.SetOriginalTeam(newTeam); if (AddToCrew && (newTeam == CharacterTeamType.Team1 || newTeam == CharacterTeamType.Team2)) { npc.Info.StartItemsGiven = true; GameMain.GameSession.CrewManager.AddCharacter(npc); foreach (Item item in npc.Inventory.AllItems) { item.AllowStealing = true; var wifiComponent = item.GetComponent<Items.Components.WifiComponent>(); if (wifiComponent != null) { wifiComponent.TeamID = newTeam; } } #if SERVER GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AddToCrew, newTeam, npc.Inventory.AllItems.Select(it => it.ID).ToArray() }); #endif } } isFinished = true; }
public bool Start(GameServer server, TraitorManager traitorManager, CharacterTeamType team) { var assignedCandidates = AssignTraitors(server, traitorManager, team); if (assignedCandidates == null) { return(false); } foreach (Client client in server.ConnectedClients) { client.RoundsSincePlayedAsTraitor++; } Traitors.Clear(); foreach (var candidate in assignedCandidates) { var traitor = new Traitor(this, candidate.Item1, candidate.Item2.Item1.Character); Traitors.Add(candidate.Item1, traitor); candidate.Item2.Item1.RoundsSincePlayedAsTraitor = 0; } CodeWords = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt); CodeResponse = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt); if (pendingObjectives.Count <= 0 || !pendingObjectives[0].CanBeStarted(Traitors.Values)) { Traitors.Clear(); return(false); } var pendingMessages = new Dictionary <Traitor, List <string> >(); pendingMessages.Clear(); foreach (var traitor in Traitors.Values) { pendingMessages.Add(traitor, new List <string>()); } foreach (var traitor in Traitors.Values) { traitor.Greet(server, CodeWords, CodeResponse, message => pendingMessages[traitor].Add(message)); } pendingMessages.ForEach(traitor => traitor.Value.ForEach(message => traitor.Key.SendChatMessage(message, Identifier))); pendingMessages.ForEach(traitor => traitor.Value.ForEach(message => traitor.Key.SendChatMessageBox(message, Identifier))); Update(0.0f, () => { GameMain.Server.TraitorManager.ShouldEndRound = true; }); #if SERVER foreach (var traitor in Traitors.Values) { GameServer.Log($"{GameServer.CharacterLogName(traitor.Character)} is a traitor and the current goals are:\n{(traitor.CurrentObjective?.GoalInfos != null ? TextManager.GetServerMessage(traitor.CurrentObjective?.GoalInfos) : "(empty)")}", ServerLog.MessageType.ServerMessage); } #endif return(true); }
public static string GetTeamName(CharacterTeamType teamID) { if (teamID == CharacterTeamType.Team1) { return(teamNames.Length > 0 ? teamNames[0] : "Team 1"); } else if (teamID == CharacterTeamType.Team2) { return(teamNames.Length > 1 ? teamNames[1] : "Team 2"); } return("Invalid Team"); }
protected Character CreateHuman(HumanPrefab humanPrefab, List <Character> characters, Dictionary <Character, List <Item> > characterItems, Submarine submarine, CharacterTeamType teamType, ISpatialEntity positionToStayIn = null, Rand.RandSync humanPrefabRandSync = Rand.RandSync.Server, bool giveTags = true) { var characterInfo = humanPrefab.GetCharacterInfo(Rand.RandSync.Server) ?? new CharacterInfo(CharacterPrefab.HumanSpeciesName, npcIdentifier: humanPrefab.Identifier, jobPrefab: humanPrefab.GetJobPrefab(humanPrefabRandSync), randSync: humanPrefabRandSync); characterInfo.TeamID = teamType; if (positionToStayIn == null) { positionToStayIn = WayPoint.GetRandom(SpawnType.Human, characterInfo.Job?.Prefab, submarine) ?? WayPoint.GetRandom(SpawnType.Human, null, submarine); } Character spawnedCharacter = Character.Create(characterInfo.SpeciesName, positionToStayIn.WorldPosition, ToolBox.RandomSeed(8), characterInfo, createNetworkEvent: false); spawnedCharacter.Prefab = humanPrefab; humanPrefab.InitializeCharacter(spawnedCharacter, positionToStayIn); humanPrefab.GiveItems(spawnedCharacter, submarine, Rand.RandSync.Server, createNetworkEvents: false); characters.Add(spawnedCharacter); characterItems.Add(spawnedCharacter, spawnedCharacter.Inventory.FindAllItems(recursive: true)); return(spawnedCharacter); }
public void Update(float deltaTime) { if (ShouldEndRound) { return; } #if DISABLE_MISSIONS return; #endif if (Missions.Any()) { bool missionCompleted = false; bool gameShouldEnd = false; CharacterTeamType winningTeam = CharacterTeamType.None; foreach (var mission in Missions) { mission.Value.Update(deltaTime, () => { switch (mission.Key) { case CharacterTeamType.Team1: winningTeam = (winningTeam == CharacterTeamType.None) ? CharacterTeamType.Team2 : CharacterTeamType.None; break; case CharacterTeamType.Team2: winningTeam = (winningTeam == CharacterTeamType.None) ? CharacterTeamType.Team1 : CharacterTeamType.None; break; default: break; } gameShouldEnd = true; }); if (!gameShouldEnd && mission.Value.IsCompleted) { missionCompleted = true; foreach (var traitor in mission.Value.Traitors.Values) { traitor.UpdateCurrentObjective("", mission.Value.Identifier); } } } if (gameShouldEnd) { GameMain.GameSession.WinningTeam = winningTeam; ShouldEndRound = true; return; } if (missionCompleted) { Missions.Clear(); startCountdown = MathHelper.Lerp(server.ServerSettings.TraitorsMinRestartDelay, server.ServerSettings.TraitorsMaxRestartDelay, (float)RandomDouble()); } } else if (startCountdown > 0.0f && server.GameStarted) { startCountdown -= deltaTime; if (startCountdown <= 0.0f) { int playerCharactersCount = server.ConnectedClients.Sum(client => client.Character != null && !client.Character.IsDead ? 1 : 0); if (playerCharactersCount < server.ServerSettings.TraitorsMinPlayerCount) { startCountdown = MathHelper.Lerp(server.ServerSettings.TraitorsMinRestartDelay, server.ServerSettings.TraitorsMaxRestartDelay, (float)RandomDouble()); return; } if (Character.CharacterList.Count(c => !c.IsDead && c.TeamID == CharacterTeamType.Team1 || c.TeamID == CharacterTeamType.Team2) <= 1) { return; } if (GameMain.GameSession.Missions.Any(m => m is CombatMission)) { var teamIds = new[] { CharacterTeamType.Team1, CharacterTeamType.Team2 }; foreach (var teamId in teamIds) { if (server.ConnectedClients.Count(c => c.Character != null && !c.Character.IsDead && c.TeamID == teamId) < 2) { continue; } var mission = TraitorMissionPrefab.RandomPrefab()?.Instantiate(); if (mission != null) { Missions.Add(teamId, mission); } } var canBeStartedCount = Missions.Sum(mission => mission.Value.CanBeStarted(server, this, mission.Key) ? 1 : 0); if (canBeStartedCount >= Missions.Count) { var startSuccessCount = Missions.Sum(mission => mission.Value.Start(server, this, mission.Key) ? 1 : 0); if (startSuccessCount >= Missions.Count) { return; } } } else { var mission = TraitorMissionPrefab.RandomPrefab()?.Instantiate(); if (mission != null) { if (mission.CanBeStarted(server, this, CharacterTeamType.None)) { if (mission.Start(server, this, CharacterTeamType.None)) { Missions.Add(CharacterTeamType.None, mission); return; } } } } Missions.Clear(); startCountdown = MathHelper.Lerp(server.ServerSettings.TraitorsMinRestartDelay, server.ServerSettings.TraitorsMaxRestartDelay, (float)RandomDouble()); } } }
public string GetCodeResponse(CharacterTeamType team) => Missions.TryGetValue(team, out var mission) ? mission.CodeResponse : "";
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { switch (type) { case ServerNetObject.ENTITY_POSITION: bool facingRight = AnimController.Dir > 0.0f; lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now; AnimController.Frozen = false; Enabled = true; UInt16 networkUpdateID = 0; if (msg.ReadBoolean()) { networkUpdateID = msg.ReadUInt16(); } else { bool aimInput = msg.ReadBoolean(); keys[(int)InputType.Aim].Held = aimInput; keys[(int)InputType.Aim].SetState(false, aimInput); bool shootInput = msg.ReadBoolean(); keys[(int)InputType.Shoot].Held = shootInput; keys[(int)InputType.Shoot].SetState(false, shootInput); bool useInput = msg.ReadBoolean(); keys[(int)InputType.Use].Held = useInput; keys[(int)InputType.Use].SetState(false, useInput); if (AnimController is HumanoidAnimController) { bool crouching = msg.ReadBoolean(); keys[(int)InputType.Crouch].Held = crouching; keys[(int)InputType.Crouch].SetState(false, crouching); } bool attackInput = msg.ReadBoolean(); keys[(int)InputType.Attack].Held = attackInput; keys[(int)InputType.Attack].SetState(false, attackInput); double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI; cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f; TransformCursorPos(); bool ragdollInput = msg.ReadBoolean(); keys[(int)InputType.Ragdoll].Held = ragdollInput; keys[(int)InputType.Ragdoll].SetState(false, ragdollInput); facingRight = msg.ReadBoolean(); } bool entitySelected = msg.ReadBoolean(); Character selectedCharacter = null; Item selectedItem = null; AnimController.Animation animation = AnimController.Animation.None; if (entitySelected) { ushort characterID = msg.ReadUInt16(); ushort itemID = msg.ReadUInt16(); selectedCharacter = FindEntityByID(characterID) as Character; selectedItem = FindEntityByID(itemID) as Item; if (characterID != NullEntityID) { bool doingCpr = msg.ReadBoolean(); if (doingCpr && SelectedCharacter != null) { animation = AnimController.Animation.CPR; } } } Vector2 pos = new Vector2( msg.ReadSingle(), msg.ReadSingle()); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; Vector2 linearVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12); bool fixedRotation = msg.ReadBoolean(); float?rotation = null; float?angularVelocity = null; if (!fixedRotation) { rotation = msg.ReadSingle(); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } bool readStatus = msg.ReadBoolean(); if (readStatus) { ReadStatus(msg); (AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg); } msg.ReadPadBits(); int index = 0; if (GameMain.Client.Character == this && CanMove) { var posInfo = new CharacterStateInfo( pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) { index++; } memState.Insert(index, posInfo); } else { var posInfo = new CharacterStateInfo( pos, rotation, linearVelocity, angularVelocity, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) { index++; } memState.Insert(index, posInfo); } break; case ServerNetObject.ENTITY_EVENT: int eventType = msg.ReadRangedInteger(0, 9); switch (eventType) { case 0: //NetEntityEvent.Type.InventoryState if (Inventory == null) { string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); //read anyway to prevent messing up reading the rest of the message _ = msg.ReadUInt16(); byte inventoryItemCount = msg.ReadByte(); for (int i = 0; i < inventoryItemCount; i++) { msg.ReadUInt16(); } } else { Inventory.ClientRead(type, msg, sendingTime); } break; case 1: //NetEntityEvent.Type.Control byte ownerID = msg.ReadByte(); ResetNetState(); if (ownerID == GameMain.Client.ID) { if (controlled != null) { LastNetworkUpdateID = controlled.LastNetworkUpdateID; } if (!IsDead) { Controlled = this; } IsRemotePlayer = false; GameMain.Client.HasSpawned = true; GameMain.Client.Character = this; GameMain.LightManager.LosEnabled = true; GameMain.LightManager.LosAlpha = 1f; GameMain.Client.WaitForNextRoundRespawn = null; } else { if (controlled == this) { Controlled = null; IsRemotePlayer = ownerID > 0; } } break; case 2: //NetEntityEvent.Type.Status ReadStatus(msg); break; case 3: //NetEntityEvent.Type.UpdateSkills int skillCount = msg.ReadByte(); for (int i = 0; i < skillCount; i++) { string skillIdentifier = msg.ReadString(); float skillLevel = msg.ReadSingle(); info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f); } break; case 4: // NetEntityEvent.Type.SetAttackTarget case 5: //NetEntityEvent.Type.ExecuteAttack int attackLimbIndex = msg.ReadByte(); UInt16 targetEntityID = msg.ReadUInt16(); int targetLimbIndex = msg.ReadByte(); Vector2 targetSimPos = new Vector2(msg.ReadSingle(), msg.ReadSingle()); //255 = entity already removed, no need to do anything if (attackLimbIndex == 255 || Removed) { break; } if (attackLimbIndex >= AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})"); break; } Limb attackLimb = AnimController.Limbs[attackLimbIndex]; Limb targetLimb = null; if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity)) { DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target entity not found (ID {targetEntityID})"); break; } if (targetEntity is Character targetCharacter) { if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})"); break; } targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex]; } if (attackLimb?.attack != null) { if (eventType == 4) { SetAttackTarget(attackLimb, targetEntity, targetSimPos); } else { attackLimb.ExecuteAttack(targetEntity, targetLimb, out _); } } break; case 6: //NetEntityEvent.Type.AssignCampaignInteraction byte campaignInteractionType = msg.ReadByte(); bool requireConsciousness = msg.ReadBoolean(); (GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType); RequireConsciousnessForCustomInteract = requireConsciousness; break; case 7: //NetEntityEvent.Type.ObjectiveManagerState // 1 = order, 2 = objective int msgType = msg.ReadRangedInteger(0, 2); if (msgType == 0) { break; } bool validData = msg.ReadBoolean(); if (!validData) { break; } if (msgType == 1) { int orderIndex = msg.ReadRangedInteger(0, Order.PrefabList.Count); var orderPrefab = Order.PrefabList[orderIndex]; string option = null; if (orderPrefab.HasOptions) { int optionIndex = msg.ReadRangedInteger(-1, orderPrefab.AllOptions.Length); if (optionIndex > -1) { option = orderPrefab.AllOptions[optionIndex]; } } GameMain.GameSession?.CrewManager?.SetOrderHighlight(this, orderPrefab.Identifier, option); } else if (msgType == 2) { string identifier = msg.ReadString(); string option = msg.ReadString(); ushort objectiveTargetEntityId = msg.ReadUInt16(); var objectiveTargetEntity = FindEntityByID(objectiveTargetEntityId); GameMain.GameSession?.CrewManager?.CreateObjectiveIcon(this, identifier, option, objectiveTargetEntity); } break; case 8: //NetEntityEvent.Type.TeamChange byte newTeamId = msg.ReadByte(); ChangeTeam((CharacterTeamType)newTeamId); break; case 9: //NetEntityEvent.Type.AddToCrew GameMain.GameSession.CrewManager.AddCharacter(this); CharacterTeamType teamID = (CharacterTeamType)msg.ReadByte(); ushort itemCount = msg.ReadUInt16(); for (int i = 0; i < itemCount; i++) { ushort itemID = msg.ReadUInt16(); if (!(Entity.FindEntityByID(itemID) is Item item)) { continue; } item.AllowStealing = true; var wifiComponent = item.GetComponent <Items.Components.WifiComponent>(); if (wifiComponent != null) { wifiComponent.TeamID = teamID; } } break; } msg.ReadPadBits(); break; } }
public bool CanBeStarted(GameServer server, TraitorManager traitorManager, CharacterTeamType team) { foreach (var role in Roles) { var candidates = FindTraitorCandidates(server, team, role.Value); if (candidates.Count <= 0) { return(false); } } return(AssignTraitors(server, traitorManager, team) != null); }
protected List <Tuple <string, Tuple <Client, Character> > > AssignTraitors(GameServer server, TraitorManager traitorManager, CharacterTeamType team) { List <Character> characters = FindCharacters(); #if !ALLOW_SOLO_TRAITOR if (characters.Count < 2) { return(null); } #endif var roleCandidates = new Dictionary <string, HashSet <Tuple <Client, Character> > >(); foreach (var role in Roles) { roleCandidates.Add(role.Key, new HashSet <Tuple <Client, Character> >(FindTraitorCandidates(server, team, role.Value))); if (roleCandidates[role.Key].Count <= 0) { return(null); } } var candidateRoleCounts = new Dictionary <Tuple <Client, Character>, int>(); foreach (var candidateEntry in roleCandidates) { foreach (var candidate in candidateEntry.Value) { candidateRoleCounts[candidate] = candidateRoleCounts.TryGetValue(candidate, out var count) ? count + 1 : 1; } } var unassignedRoles = new List <string>(roleCandidates.Keys); unassignedRoles.Sort((a, b) => roleCandidates[a].Count - roleCandidates[b].Count); var assignedCandidates = new List <Tuple <string, Tuple <Client, Character> > >(); while (unassignedRoles.Count > 0) { var currentRole = unassignedRoles[0]; var availableCandidates = roleCandidates[currentRole].ToList(); if (availableCandidates.Count <= 0) { break; } unassignedRoles.RemoveAt(0); availableCandidates.Sort((a, b) => candidateRoleCounts[b] - candidateRoleCounts[a]); unassignedRoles.Sort((a, b) => roleCandidates[a].Count - roleCandidates[b].Count); int numCandidates = 1; for (int i = 1; i < availableCandidates.Count && candidateRoleCounts[availableCandidates[i]] == candidateRoleCounts[availableCandidates[0]]; ++i) { ++numCandidates; } var selected = ToolBox.SelectWeightedRandom(availableCandidates, availableCandidates.Select(c => Math.Max(c.Item1.RoundsSincePlayedAsTraitor, 0.1f)).ToList(), TraitorManager.Random); assignedCandidates.Add(Tuple.Create(currentRole, selected)); foreach (var candidate in roleCandidates.Values) { candidate.Remove(selected); } } if (unassignedRoles.Count > 0) { return(null); } return(assignedCandidates); }
protected List <Tuple <Client, Character> > FindTraitorCandidates(GameServer server, CharacterTeamType team, RoleFilter traitorRoleFilter) { var traitorCandidates = new List <Tuple <Client, Character> >(); foreach (Client c in server.ConnectedClients) { if (c.Character == null || c.Character.IsDead || c.Character.Removed || !traitorRoleFilter(c.Character) || (team != CharacterTeamType.None && c.Character.TeamID != team)) { continue; } #if !ALLOW_NONHUMANOID_TRAITOR if (!c.Character.IsHumanoid) { continue; } #endif traitorCandidates.Add(Tuple.Create(c, c.Character)); } return(traitorCandidates); }