private static bool ResolveAutopilotBeginTravel(AutopilotBeginAction action, EncounterState state) { var playerPosition = state.Player.GetComponent <PositionComponent>().EncounterPosition; EncounterZone zone = state.GetZoneById(action.ZoneId); var foundPath = Pathfinder.AStarWithNewGrid(playerPosition, zone.Center, state, 9000); int autopilotTries = 0; while (foundPath == null && autopilotTries < 5) { foundPath = Pathfinder.AStarWithNewGrid(playerPosition, zone.RandomEmptyPosition(state.EncounterRand, state), state, 9000); autopilotTries++; } if (foundPath != null && autopilotTries > 0) { state.LogMessage(String.Format("Autopilot could not find path to center of [b]{0}[/b]; autopiloting to randomly chosen position in [b]{0}[/b].", zone.ZoneName)); state.Player.GetComponent <PlayerComponent>().LayInAutopilotPathForTravel(new EncounterPath(foundPath)); return(true); } else if (foundPath != null) { state.LogMessage(String.Format("Autopiloting to [b]{0}[/b]", zone.ZoneName)); state.Player.GetComponent <PlayerComponent>().LayInAutopilotPathForTravel(new EncounterPath(foundPath)); return(true); } else { state.LogMessage(String.Format("Autopilot failed to plot course to to [b]{0}[/b]", zone.ZoneName), failed: true); return(false); } }
private static void LogAttack(DefenderComponent defenderComponent, string message, EncounterState state) { if (defenderComponent.ShouldLogDamage) { state.LogMessage(message); } }
private static void LogAttack(Entity attacker, Entity defender, DefenderComponent defenderComponent, string message, EncounterState state) { if (defenderComponent.ShouldLogDamage && (attacker == state.Player || defender == state.Player)) { state.LogMessage(message); } }
// Currently, each use effect is its own component. If we run into a case where we have too many effects, we can push the // effects into the usable component itself, similarly to status effects (though status effects are their own mess right now) // which would probably be better for building on. private static bool ResolveUse(UseAction action, EncounterState state) { var user = state.GetEntityById(action.ActorId); // This is another issue that'd be solved with a global Entity lookup - though not the removal part. Entity usable = null; if (action.FromInventory) { var userInventory = user.GetComponent <InventoryComponent>(); usable = userInventory.StoredEntityById(action.UsableId); if (usable.GetComponent <UsableComponent>() == null) { state.LogMessage(string.Format("{0} is not usable!", usable.EntityName), failed: true); return(false); } else { userInventory.RemoveEntity(usable); } } else { usable = state.GetEntityById(action.UsableId); if (usable.GetComponent <UsableComponent>() == null) { state.LogMessage(string.Format("{0} is not usable!", usable.EntityName), failed: true); return(false); } else { state.RemoveEntity(usable); } } state.LogMessage(string.Format("{0} used {1}!", user.EntityName, usable.EntityName)); ResolveUseEffects(user, usable, state); // We assume all items are single-use; this will change if I deviate from the reference implementation! usable.QueueFree(); return(true); }
private static bool ResolveGetItem(GetItemAction action, EncounterState state) { var actor = state.GetEntityById(action.ActorId); var inventoryComponent = actor.GetComponent <InventoryComponent>(); var actorPosition = actor.GetComponent <PositionComponent>().EncounterPosition; var item = state.EntitiesAtPosition(actorPosition.X, actorPosition.Y) .FirstOrDefault(e => e.GetComponent <StorableComponent>() != null); if (item == null) { state.LogMessage("No item found!", failed: true); return(false); } else if (item.GetComponent <UsableComponent>() != null && item.GetComponent <UsableComponent>().UseOnGet) { // The responsibility for removing/not removing the usable from the EncounterState is in the usage code. bool successfulUsage = ResolveUse(new UseAction(actor.EntityId, item.EntityId, false), state); if (!successfulUsage) { GD.PrintErr(string.Format("Item {0} was not successfully used after being picked up!", item.EntityName)); } return(true); } else if (!inventoryComponent.CanFit(item)) { state.LogMessage(string.Format("[b]{0}[/b] can't fit the [b]{1}[/b] in its inventory!", actor.EntityName, item.EntityName), failed: true); return(false); } else { state.RemoveEntity(item); actor.GetComponent <InventoryComponent>().AddEntity(item); var logMessage = string.Format("[b]{0}[/b] has taken the [b]{1}[/b]", actor.EntityName, item.EntityName); state.LogMessage(logMessage); return(true); } }
private static bool ResolveUseStairs(UseStairsAction action, EncounterState state) { var actorPosition = state.GetEntityById(action.ActorId).GetComponent <PositionComponent>().EncounterPosition; var stairs = state.EntitiesAtPosition(actorPosition.X, actorPosition.Y) .FirstOrDefault(e => e.GetComponent <StairsComponent>() != null); if (stairs != null) { state.ResetStateForNewLevel(state.Player, state.DungeonLevel + 1); state.WriteToFile(); return(true); } else { state.LogMessage("No jump point found!", failed: true); return(false); } }
private static bool ResolveAutopilotEnd(AutopilotEndAction action, EncounterState state) { var playerComponent = state.Player.GetComponent <PlayerComponent>(); if (action.Reason == AutopilotEndReason.PLAYER_INPUT) { state.LogMessage(String.Format("Autopilot ending - [b]overridden by pilot[/b]")); } else if (action.Reason == AutopilotEndReason.ENEMY_DETECTED) { state.LogMessage(String.Format("Autopilot ending - [b]enemy detected[/b]")); } else if (action.Reason == AutopilotEndReason.TASK_COMPLETED) { if (playerComponent.ActiveAutopilotMode == AutopilotMode.TRAVEL) { state.LogMessage(String.Format("Autopilot ending - [b]travel completed[/b]")); } else if (playerComponent.ActiveAutopilotMode == AutopilotMode.EXPLORE) { state.LogMessage(String.Format("Autopilot ending - [b]exploration completed[/b]")); } else { throw new NotImplementedException("no such explore mode known"); } } else if (action.Reason == AutopilotEndReason.INVENTORY_FULL) { state.LogMessage(String.Format("Autopilot ending - [b]inventory was full[/b]")); } else if (action.Reason == AutopilotEndReason.NO_PATH) { state.LogMessage(String.Format("Autopilot ending - [b]path to next location blocked[/b]")); } else { throw new NotImplementedException("no such matching clause for enum"); } state.Player.GetComponent <PlayerComponent>().StopAutopiloting(); return(true); }
public void AddPrestige(int dPrestige, EncounterState state, string message, PrestigeSource source) { this._PrestigeBySource[source] += dPrestige; state.LogMessage(message); }
private static void ResolveUseEffects(Entity user, Entity usable, EncounterState state) { // We keep this logic here instead of in the component itself because the component should have only state data. That said // we shouldn't keep it, like, *here* here, 'least not indefinitely. var useEffectHeal = usable.GetComponent <UseEffectHealComponent>(); if (useEffectHeal != null) { var restored = user.GetComponent <DefenderComponent>().RestoreHP(useEffectHeal.Healpower); state.LogMessage(string.Format("{0} restored {1} HP to {2}!", usable.EntityName, restored, user.EntityName)); } var useEffectAddIntel = usable.GetComponent <UseEffectAddIntelComponent>(); if (useEffectAddIntel != null) { // Kinda funny because player's the only one for which this effect is meaningful so we just grab player it's fiiiiiine state.Player.GetComponent <PlayerComponent>().RegisterIntel(useEffectAddIntel.TargetDungeonLevel); state.LogMessage(string.Format("Discovered intel for [b]sector {0}[/b]!", useEffectAddIntel.TargetDungeonLevel)); } var useEffectBoostPower = usable.GetComponent <UseEffectBoostPowerComponent>(); if (useEffectBoostPower != null) { state.LogMessage(String.Format("Attack power boosted by {0} for duration {1}!", useEffectBoostPower.BoostPower, useEffectBoostPower.Duration)); var statusEffectTracker = user.GetComponent <StatusEffectTrackerComponent>(); statusEffectTracker.AddEffect(new StatusEffectTimedPowerBoost( boostPower: useEffectBoostPower.BoostPower, startTick: state.CurrentTick, endTick: state.CurrentTick + useEffectBoostPower.Duration )); } var useEffectBoostSpeed = usable.GetComponent <UseEffectBoostSpeedComponent>(); if (useEffectBoostSpeed != null) { state.LogMessage(String.Format("Speed boosted by {0} for duration {1}!", useEffectBoostSpeed.BoostPower, useEffectBoostSpeed.Duration)); var statusEffectTracker = user.GetComponent <StatusEffectTrackerComponent>(); statusEffectTracker.AddEffect(new StatusEffectTimedSpeedBoost( boostPower: useEffectBoostSpeed.BoostPower, startTick: state.CurrentTick, endTick: state.CurrentTick + useEffectBoostSpeed.Duration )); } var useEffectEMP = usable.GetComponent <UseEffectEMPComponent>(); if (useEffectEMP != null) { state.LogMessage(String.Format("EMP detonated in radius {0} - disables {1} turns!", useEffectEMP.Radius, useEffectEMP.DisableTurns)); var userPosition = user.GetComponent <PositionComponent>().EncounterPosition; for (int x = userPosition.X - useEffectEMP.Radius; x <= userPosition.X + useEffectEMP.Radius; x++) { for (int y = userPosition.Y - useEffectEMP.Radius; y <= userPosition.Y + useEffectEMP.Radius; y++) { var distance = userPosition.DistanceTo(x, y); if (distance <= useEffectEMP.Radius && state.IsInBounds(x, y)) { var entitiesAtPosition = state.EntitiesAtPosition(x, y); foreach (var entity in entitiesAtPosition) { var speedComponent = entity.GetComponent <SpeedComponent>(); var statusTracker = entity.GetComponent <StatusEffectTrackerComponent>(); if (entity != user && speedComponent != null && statusTracker != null) { var disableTicks = speedComponent.Speed * useEffectEMP.DisableTurns; statusTracker.AddEffect(new StatusEffectTimedDisable(state.CurrentTick, state.CurrentTick + disableTicks)); state.LogMessage(String.Format("{0} was disabled for {1} ticks!", entity.EntityName, disableTicks)); } } } } } } }