void comButtonClick() { bool markerEnabled = !CoM.activeInHierarchy; /* toggle com */ if (userEnable) { bool visible = !CoM.GetComponent <MarkerVisibility> ().GeneralToggle; CoM.GetComponent <MarkerVisibility> ().GeneralToggle = visible; DCoM.GetComponent <MarkerVisibility> ().GeneralToggle = visible; ACoM.GetComponent <MarkerVisibility> ().GeneralToggle = visible; /* we need the CoM to remain active, but we can't stop the editor from * deactivating it when the CoM toggle button is used, so we toggle it now so is * toggled again by the editor. That way it will remain active. */ CoM.SetActive(markerEnabled); } if (!userEnable && markerEnabled) { /* restore CoM visibility, so the regular CoM toggle button works. */ var markerVisibility = CoM.GetComponent <MarkerVisibility> (); if (markerVisibility != null) { markerVisibility.Show(); } } }
void activateMarkers(bool value) { Log.Info("activateMarkers, setting to: " + value); CoM.SetActive(value); DCoM.SetActive(value); ACoM.SetActive(value); }
void comButtonClick() { if (RCSBuildAid.Enabled) { /* plugin enabled, CoM button is for toggle marker visibility */ bool visible = !CoM.GetComponent <MarkerVisibility> ().GeneralToggle; CoM.GetComponent <MarkerVisibility> ().GeneralToggle = visible; DCoM.GetComponent <MarkerVisibility> ().GeneralToggle = visible; ACoM.GetComponent <MarkerVisibility> ().GeneralToggle = visible; /* we need the CoM to remain active, but we can't stop the editor from * deactivating it when the CoM toggle button is used, so we toggle it now so is * toggled again by the editor. That way it will remain active. */ Log.Info("comButtonClick, setting to: " + !CoM.activeInHierarchy); CoM.SetActive(!CoM.activeInHierarchy); } if (!RCSBuildAid.Enabled) { /* restore CoM visibility, so the regular CoM toggle button works. */ var markerVisibility = CoM.GetComponent <MarkerVisibility> (); if (markerVisibility != null) { markerVisibility.Show(); } } }
/** * Updates the infomation panel descripting the raising details for the selected character */ private void doUpdateRaiseInfo() { MDRCharacter character = deadCharactersList.Selected; raiseCost = GameRules.CostToRaise(character); if (character == null) { raiseInfo.Caption = ""; costLabel.Visible = false; return; } string notice = "{0} has died."; if (raiseCost == 0) { notice += "\n\nBecause {0} is less than level 10 the temple has agreed to raise him for free."; } else { notice += "\n\nThe cost to raise {0} is {1}"; if (raiseCost > CoM.Party.Gold) { notice += "\nHowever you only have {2}."; } } raiseInfo.Caption = string.Format(notice, CoM.Format(character), CoM.CoinsAmount(raiseCost), CoM.CoinsAmount(CoM.Party.Gold)); costLabel.Visible = true; costLabel.Value = raiseCost; }
public DebugMenuState() : base("DebugMenu") { GuiWindow window = new GuiWindow(400, 500, "DEBUG"); Add(window, 0, 0); int buttonIndex = 0; GuiButton testSerializationButton = new GuiButton("Serialization", -1); window.Add(testSerializationButton, 0, 50 + 40 * buttonIndex++); GuiButton ResetButton = new GuiButton("Reset", -1); ResetButton.ColorTransform = ColorTransform.BlackAndWhite; ResetButton.Color = new Color(1f, 0.4f, 0.3f); window.Add(ResetButton, 0, 50 + 40 * buttonIndex++); testSerializationButton.OnMouseClicked += delegate { testDataSerialization(); }; ResetButton.OnMouseClicked += delegate { CoM.ConfirmAction(performGameReset, "Are you sure you want to reset the game?"); }; window.Add(Util.CreateBackButton(), 0, -10); }
/** Purchase item, gives to currently selected party memeber. */ public bool PurchaseItem(MDRItem item) { MDRCharacter buyer = CoM.Party.Selected; if (buyer == null) { return(false); } if (CoM.Party.Gold < SellPrice(item)) { return(false); } // do the transaction if (buyer.GiveItem(MDRItemInstance.Create(item))) { CoM.Party.DebitGold(SellPrice(item), buyer); SubtractQuantity(item, 1); return(true); } else { CoM.PostMessage(buyer + " does not have enough space for " + item); return(false); } }
/** Override can send to notify player the item is cursed */ public override bool CanSend(IDragDrop destination) { if ((DataLink != null) && (!(destination is GuiInspectionSlot)) && DataLink.IsEquipSlot && containsCursedItem()) { CoM.PostMessage("This item is cursed!"); return(false); } return(true); }
/** Writes names of library entrys to log */ public void ListToLog(bool logToScreen = false) { foreach (T obj in DataList) { Trace.Log(obj.ToString()); if (logToScreen) { CoM.PostMessage(obj.ToString()); } } }
/** * Causes detials in the perceived tile to be copied across from the actual tile, will also log messages * decribing the new features discovered. Returns true if any update occured * * @returns if any changes where made. */ private bool detectSquare(FieldRecord perceivedTile, FieldRecord actualTile, string message, MDRCharacter character) { string detailName = ""; if (perceivedTile.FaceNorth != actualTile.FaceNorth) { detailName += "a face north, "; } if (perceivedTile.FaceEast != actualTile.FaceEast) { detailName += "a face east, "; } if (perceivedTile.FaceWest != actualTile.FaceWest) { detailName += "a face west, "; } if (perceivedTile.FaceSouth != actualTile.FaceSouth) { detailName += "a face south, "; } if (perceivedTile.Antimagic != actualTile.Antimagic) { detailName += "an anti-magic, "; } if (perceivedTile.Rotator != actualTile.Rotator) { detailName += "a rotator, "; } if (perceivedTile.Extinguisher != actualTile.Extinguisher) { detailName += "an extinguisher, "; } if (perceivedTile.Stud != actualTile.Stud) { detailName += "a stud, "; } if (detailName != "") { CoM.PostMessage(message, CoM.Format(character), detailName.TrimEnd(new char[] { ' ', ',' })); } perceivedTile.FaceNorth = actualTile.FaceNorth; perceivedTile.FaceEast = actualTile.FaceEast; perceivedTile.FaceWest = actualTile.FaceWest; perceivedTile.FaceSouth = actualTile.FaceSouth; perceivedTile.Antimagic = actualTile.Antimagic; perceivedTile.Rotator = actualTile.Rotator; perceivedTile.Extinguisher = actualTile.Extinguisher; perceivedTile.Stud = actualTile.Stud; return(detailName != ""); }
/** Resets the game and pops a window up stopping the application from continuing */ private void performGameReset() { CoM.FullReset(); var modalState = new ModalNotificaionState("Game Reset", "The game has been reset and must be restarted."); modalState.ConfirmationButton.Visible = false; Engine.PushState(modalState); CoM.SaveOnExit = false; }
/** Writes contents of library to log */ public void WriteToLog(bool logToScreen = false) { foreach (T obj in DataList) { Trace.Log(obj.LongDescription()); if (logToScreen) { CoM.PostMessage(obj.LongDescription()); } } }
/** * Attempts to use or equip the item stored in this container. * Equipable items will be equiped. Usable items will be used */ protected void UseOrEquipItem() { if (DataLink.IsEmpty) { return; } MDRItemInstance itemInstance = DataLink.ItemInstance; //stub: slots should know the character they're associated with */ MDRCharacter character = CoM.Party.Selected; if (!itemInstance.IDLevel.CanUse) { CoM.PostMessage("{0} must be more identified before it can be used.", CoM.Format(itemInstance)); return; } if (itemInstance.Item.Usable) { // first can this item be activated? string reason = itemInstance.GetCanNotUseReason(character); if (reason == "") { if (itemInstance.RemainingCharges <= 0) { CoM.PostMessage("Item is out of charges."); } else { itemInstance.Use(character); } } else { CoM.PostMessage(reason); } } else { // otherwise try equiping it string reason = itemInstance.GetCanNotEquipReason(character); if (reason == "") { character.EquipItem(DataLink); } else { CoM.PostMessage(reason); } } }
/** This is a temporary function to load a map file, later it will be configurable, but right now its hard coded to load via CoM. */ public void Initialize() { Trace.Log("Initializing dungeon creator."); if (!CoM.GameDataLoaded) { CoM.LoadGameData(); } Dungeon = CoM.Dungeon; setupNodes(); }
void activateMarkers(bool value) { CoM.SetActive(value); DCoM.SetActive(value); ACoM.SetActive(value); if (value && (RCSBuildAid.Mode == PluginMode.Parachutes)) { CoD.SetActive(true); } else { CoD.SetActive(false); } }
public static void SetActive(bool enabled) { userEnable = enabled; CoM.SetActive(enabled); DCoM.SetActive(enabled); ACoM.SetActive(enabled); if (enabled) { events.OnPluginEnabled(true); } else { events.OnPluginDisabled(true); } }
public static void SetActive(bool value) { userEnable = value; CoM.SetActive(value); DCoM.SetActive(value); ACoM.SetActive(value); if (value) { Events.OnPluginEnabled(true); } else { Events.OnPluginDisabled(true); } Events.OnPluginToggled(value, true); }
public override void Show() { base.Show(); UpdateBirdsEyeView(); // force a generate with no ceiling. CoM.GetDungeonBuilder().Initialize(); CoM.GetDungeonBuilder().GenerateCeiling = false; CoM.GetDungeonBuilder().SelectedMap = 1; CoM.GetDungeonBuilder().GenerateCeiling = true; CoM.GetDungeonBuilder().MarkAllMapsAsDirty(); CoM.GetDungeonBuilder().RebuildSelectedMap(); CoM.Culler.RemoveAllObjects(); CoM.Culler.Disable(); EnvironmentManager.StandardFog(); EnvironmentManager.NearView(); EnvironmentManager.Sync(); PartyController.Instance.EnableDoorOpener = false; }
void setSoftActive(bool enabled) { /* for disable the plugin temporally without changing what the user set */ softEnable = enabled; bool pluginEnabled = Enabled; CoM.SetActive(pluginEnabled); DCoM.SetActive(pluginEnabled); ACoM.SetActive(pluginEnabled); if (pluginEnabled) { events.OnPluginEnabled(false); } else { events.OnPluginDisabled(false); } }
public static void SetActive(bool value) { Log.Info("SetActive, setting to: " + value); userEnable = value; CoM.SetActive(value); DCoM.SetActive(value); ACoM.SetActive(value); if (value) { Events.OnPluginEnabled(true); } else { Events.OnPluginDisabled(true); } Events.OnPluginToggled(value, true); }
/** Checks if given value execeeds the current record for given stat. If it does it sets the new value */ private void CheckCharacterRecord(string recordName, int value, MDRCharacter character, string objectName = "", string notificationMessage = "{0} has set a new record for being the {1} with a value of {2}.") { if (Records.ByName(recordName) == null) { return; } var record = Records[recordName]; if (value > record.RecordValue) { if (record.RecordHolder != character.Name) { PostNotification(string.Format(notificationMessage, CoM.Format(character), recordName, CoM.Format(value)), character.Portrait); } record.Set(character.Name, value, objectName); } }
/** Applies healing. */ protected void ApplyHealing(SpellResult info) { Util.Assert(HealingSpell, "Tried casting a non healing spell as a healing spell."); Util.Assert(info.Target != null, "Target for healing spell must not be null."); if (info.Target.IsDead) { CoM.PostMessage("Can not cast {0} on {1}, they are dead.", info.Spell, info.Target); return; } int healing = CalculateSpellHealing(info.Caster, info.Target); // caclulate the amount of healing done info.HealingDone = info.Target.ReceiveHealing(healing); info.DidCast = true; }
void setSoftActive(bool value) { /* for disable the plugin temporally without changing what the user set */ softEnable = value; bool pluginEnabled = Enabled; CoM.SetActive(pluginEnabled); DCoM.SetActive(pluginEnabled); ACoM.SetActive(pluginEnabled); if (pluginEnabled) { Events.OnPluginEnabled(false); } else { Events.OnPluginDisabled(false); } Events.OnPluginToggled(value, false); }
/** Creates buttons for each party, allowing the user to select one of them. */ private void updatePartyList() { CoM.CleanParties(); partyList.Clear(); int yPos = 0; foreach (MDRParty party in CoM.PartyList) { var partyButton = new GuiPartySpan(party) { X = 0, Y = yPos }; partyButton.OnMouseClicked += delegate { selectParty(partyButton.Party); }; partyList.Add(partyButton); yPos += partyButton.Height; } if (AllowCreateParty) { //var createButton = new GuiButton("Create New Party", GuiPartySpan.WIDTH, GuiPartySpan.HEIGHT) { X = 0, Y = yPos }; var createButton = new GuiPartySpan(null) { X = 0, Y = yPos }; createButton.Editable = false; createButton.Caption = "Create New Party"; createButton.Color = Color.gray; createButton.OnMouseClicked += delegate { var party = MDRParty.Create(); CoM.PartyList.Add(party); var state = new EditPartyState(party, true); Engine.PushState(state); }; partyList.Add(createButton); yPos += createButton.Height; } partyList.FitToChildren(); }
/** * Raises the given character */ private void doRaiseCharacter(MDRCharacter character) { if (character == null) { throw new ArgumentNullException("character", "[character] is null."); } if (!character.IsDead) { throw new Exception("Character is not dead."); } if (CoM.Party.Gold < raiseCost) { Engine.ShowLargeModal("Not Enough Coin", string.Format( "The party does not have enough coin to raise {0}.\nYou need {1} but together only have {2}", CoM.Format(character), CoM.CoinsAmount(raiseCost), CoM.CoinsAmount(CoM.Party.Gold) )); return; } CoM.Party.DebitGold(raiseCost, character); string complicationsMessage = GameRules.RaiseCharacterFromDead(character); if (complicationsMessage == "") { SoundManager.Play("OLDFX_RAISE"); Engine.ShowModal("Success", string.Format("{0} was successfully raised back to life.", CoM.Format(character))); } else { SoundManager.Play("OLDFX_PARAL"); Engine.ShowModal("Complications", string.Format("\nThere where problems while raising {0}.\n{0} {1}\n", CoM.Format(character), complicationsMessage)); } PopulateDeadCharacterList(); }
/** Processes a list of objects, finding any that can be formated, and replacing them with their string formatted * representation. I.e. if the list contains a spell the spell will be replaced with the colorised name of the spell */ public static object[] FormatParameters(object[] args) { var list = new List <object>(); foreach (var obj in args) { object formattedObject = null; if (obj is MDRCharacter) { formattedObject = CoM.Format(obj as MDRCharacter); } if (obj is MDRSpell) { formattedObject = CoM.Format(obj as MDRSpell); } if (obj is MDRItemInstance) { formattedObject = CoM.Format(obj as MDRItemInstance); } list.Add(formattedObject ?? obj); } return(list.ToArray()); }
/** Removes all characters from party, and dispands it. */ public void Dispand() { RemoveAll(); CoM.CleanParties(); }
/** Checks if party is standing on any traps and applied changes. */ private void checkTraps() { if (CurrentTile.Pit) { int numberOfCharactersWhoFell = 0; foreach (MDRCharacter character in this) { if (character.IsDead) { continue; } if (GameRules.FallRoll(character)) { int damage = GameRules.CalculatePitDamage(character); character.ReceiveDamage(damage); string message = character.IsDead ? "{0} fell down a pit, receiving {1} damage, and died." : "{0} fell down a pit receiving {1} damage."; CoM.PostMessage(message, CoM.Format(character), CoM.Format(damage)); numberOfCharactersWhoFell++; } else { CoM.PostMessage("{0} avoided the pit.", CoM.Format(character)); } } if (numberOfCharactersWhoFell > 0) { SoundManager.Play("OLDFX_FALL"); } } if (CurrentTile.Rotator) { int turns = Util.Roll(4) + 4; DelayedDelegates.Add(delegate { for (int lp = 0; lp < turns; lp++) { TurnLeft(); } CoM.PostMessage("Party hit a rotator."); }, 0.1f); } if (CurrentTile.Water) { SoundManager.Play("OLDFX_WADE"); } else { foreach (MDRCharacter character in this) { character.TimeInWater = 0; } } if (CurrentTile.FaceEast) { Facing = Direction.EAST; } if (CurrentTile.FaceWest) { Facing = Direction.WEST; } if (CurrentTile.FaceSouth) { Facing = Direction.SOUTH; } if (CurrentTile.FaceNorth) { Facing = Direction.NORTH; } if (CurrentTile.Chute) { ChuteTrapInfo chute = Map.GetChutAt(LocationX, LocationY); if (chute == null) { Trace.LogWarning("No chute found at party's current location."); } else { if ((Depth + chute.DropDepth) > Dungeon.Floors) { CoM.PostMessage("This chute doesn't seem to go anywhere. You can't help but feel fortunate."); } else { int numberOfCharactersWhoFell = 0; foreach (MDRCharacter character in this) { if (character.IsDead) { continue; } if (GameRules.FallRoll(character)) { numberOfCharactersWhoFell++; } } if (numberOfCharactersWhoFell == LivingMembers) { Depth += chute.DropDepth; CoM.PostMessage("Party fell down a chute"); SoundManager.Play("OLDFX_FALL"); } else { CoM.PostMessage("Party avoided falling down a chute"); } } } } if (CurrentTile.Teleporter) { TeleportTrapInfo teleport = Map.GetTeleportAt(LocationX, LocationY); if (teleport == null) { Trace.LogWarning("No teleport found at party's current location."); } else { if (teleport.DestFloor > Dungeon.Floors) { CoM.PostMessage("The teleport trap fizzes, but doesn't seem to do anything."); return; } int destinationX = teleport.DestX; int destinationY = teleport.DestY; int destinationFloor = teleport.DestFloor == 0 ? Depth : teleport.DestFloor; if (teleport.IsRandom()) { int trys = 0; while (true) { destinationX = Util.Roll(30); destinationY = Util.Roll(30); if (!Map.GetField(destinationX, destinationY).Rock) { break; } trys++; if (trys > 999) { Trace.LogWarning("Could not find safe place to teleport character to."); return; } } } SoundManager.Play("OLDFX_TELEPORT"); SetLocation(destinationX, destinationY, destinationFloor, Facing); Trace.Log("Teleporting characters to " + destinationX + "," + destinationY); CoM.PostMessage("Party hit a teleporter"); } } }
/** Updates the explored map to reveal the tile the party is standing on. */ private void updateExploredMap() { var origionalValue = PerceivedTile.Value; bool secretDiscovered = false; if (PerceivedTile != null) { var character = PerceptionCharacter; PerceivedTile.Explored = true; PerceivedTile.Water = CurrentTile.Water; PerceivedTile.Pit = CurrentTile.Pit; PerceivedTile.StairsUp = CurrentTile.StairsUp; PerceivedTile.StairsDown = CurrentTile.StairsDown; PerceivedTile.Teleporter = CurrentTile.Teleporter; PerceivedTile.Dirt = CurrentTile.Dirt; PerceivedTile.Rock = CurrentTile.Rock; PerceivedTile.Chute = CurrentTile.Chute; PerceivedTile.Grass = CurrentTile.Grass; bool blind = false; if (!blind) { // copy walls, but leave secrets alone for (int lp = 0; lp < 4; lp++) { WallRecord wall = new WallRecord(); var actualWallRecord = CurrentTile.getWallRecord(lp); var perceivedWallRecord = PerceivedTile.getWallRecord(lp); if (actualWallRecord.Secret) { wall.Type = perceivedWallRecord.Secret ? WallType.Secret : WallType.Wall; } else { wall.Type = actualWallRecord.Type; } if (actualWallRecord.Secret && !perceivedWallRecord.Secret) { if (GameRules.PerceptionRoll(character, 15 + (Depth * 5))) { CoM.PostMessage("{0} discovered a secret door.", CoM.Format(character)); SoundManager.Play("OLDFX_FOUND"); wall.Type = WallType.Secret; secretDiscovered = true; } } PerceivedTile.setWallRecord(lp, wall); } } if (PerceivedTile.GroundValue != CurrentTile.GroundValue) { // roll to see if we detect the difference or not if (GameRules.PerceptionRoll(character, 10 + (Depth * 2))) { detectSquare(PerceivedTile, CurrentTile, "{0} detected that the party is standing on {1} square.", character); } else { if (GameRules.PerceptionRoll(character, (Depth))) { CoM.PostMessage("{0} detects something strange about this place.", CoM.Format(character)); } } } } bool tileChanged = origionalValue != PerceivedTile.Value || secretDiscovered; if (CoM.GraphicsLoaded && tileChanged) { CoM.Instance.RefreshMapTile(LocationX, LocationY); } }
/** Refreshs the guild info text as per the selected guild */ private void updateGuildInfo() { JoinButton.SelfEnabled = canJoinSelectedGuild(); LevelButton.SelfEnabled = canLevel(); JoinButton.Visible = !selectedGuildIsCurrent; LevelButton.Visible = selectedGuildIsCurrent; if ((SelectedGuild == null) || (Character == null)) { return; } JoinButton.Caption = (Character.Membership[SelectedGuild].IsMember) ? "Reacquaint" : "Join"; MDRGuildMembership membership = Character.Membership[SelectedGuild]; string requiredStatsString = ""; for (int lp = 0; lp <= MDRStats.SHORT_STAT_NAME.Length; lp++) { int requirement = SelectedGuild.RequiredStats[lp]; if (requirement != 0) { requiredStatsString += Util.Colorise(MDRStats.SHORT_STAT_NAME[lp] + ":" + requirement + " ", Character.Stats[lp] >= requirement ? Color.green : Color.red); } } GuildTitle.Caption = "<B>" + SelectedGuild.Name + "</B>"; string text = ""; if (requiredStatsString != "") { text += "Required Stats: \n " + requiredStatsString + "\n\n"; } if (membership.IsMember) { text += "You are a member of this guild. \n"; if (membership.ReqXP > 0) { text += "You require " + Util.Colorise(Util.Comma(membership.ReqXP), Color.green) + " more XP to obtain level " + Util.Colorise((membership.CurrentLevel + 1).ToString(), Color.green) + "\n"; } else { text += "You are ready for level " + Util.Colorise((membership.CurrentLevel + 1).ToString(), Color.green) + "\n"; } text += "\nGaining this level will cost " + CoM.CoinsAmount(membership.RequiredGold) + "."; } else { text += "You are not a member of this guild. \n"; if (Character.BaseStats >= SelectedGuild.RequiredStats) { text += "You " + Util.Colorise("meet the stats requirements", Color.green) + " for this guild. \n"; } else { text += "You do not meet stats requirements for this guild. \n\n"; } if (membership.Guild.RequiredGuild != null) { text += "You must obtain level " + Util.Colorise(membership.Guild.RequiredGuildRequiredLevel, Color.green) + " with " + Util.Colorise(membership.Guild.RequiredGuild.Name, Color.green) + " first before joining this guild.\n\n"; } if (Character.Membership.JoinedGuilds <= 1) { text += "As this is your second guild, you may join for free. \n\n"; } else { text += "You require " + Util.Colorise(Util.Comma(SelectedGuild.JoinCost), Color.yellow) + " gold to join. \n\n"; } } GuildInfo.Caption = text; }
public GuiPartyInfo(int x = 0, int y = 0) : base(x, y) { IgnoreClipping = true; const int INFOLABEL_HEIGHT = 24; Width = 300; Height = GuiCharacterFrame.HEIGHT * 2 + INFOLABEL_HEIGHT + 24; CharacterPanel = new GuiCharacterFrame[4]; for (int lp = 0; lp < 4; lp++) { CharacterPanel[lp] = new GuiCharacterFrame() { X = (lp % 2) * (GuiCharacterFrame.WIDTH), Y = (int)(lp / 2) * (GuiCharacterFrame.HEIGHT) }; Add(CharacterPanel[lp]); } GuiButton RemoveButton = new GuiButton("Remove", 80, 20); Add(RemoveButton, 10, Height - 25); GuiButton AddButton = new GuiButton("Add", 80, 20); Add(AddButton, 100, Height - 25); menuButton = new GuiButton("Menu", 80, 20); Add(menuButton, 190, Height - 25); InfoLabel = new GuiLabel(0, 0, "") { Height = INFOLABEL_HEIGHT, TextAlign = TextAnchor.MiddleCenter, Align = GuiAlignment.Bottom }; Add(InfoLabel); RemoveButton.OnMouseClicked += delegate { if (Party.Selected != null) { Party.RemoveCharacter(Party.Selected); Sync(); } }; menuButton.OnMouseClicked += delegate { Engine.PushState(new InGameMenuState()); }; AddButton.OnMouseClicked += delegate { if (Party.MemberCount == 4) { return; } ModalOptionListState <MDRCharacter> chooseCharacterState = new ModalOptionListState <MDRCharacter>("Select a character to add", CoM.GetCharactersInCurrentArea()); chooseCharacterState.OnStateClose += delegate { if (chooseCharacterState.Result != null) { Party.AddCharacter(chooseCharacterState.Result); } Sync(); }; Engine.PushState(chooseCharacterState); }; }