protected virtual IEnumerator MoveToCoroutine(List <Vector3> targets, SpringAction action, IInteractable source) { // Can we continue already started move animation? if (skeletonAnim.AnimationName != "walk") { skeletonAnim.AnimationState.SetAnimation(0, "walk", true).timeScale = AnimationSpeed; } while (targets.Count > 0) { if (transform.position.x < targets[0].x) // Going right { skeletonAnim.skeleton.FlipX = false; } else // Going left { skeletonAnim.skeleton.FlipX = true; } while (Vector3.Distance(transform.position, targets[0]) > 0.05f) { transform.position = Vector3.MoveTowards(transform.position, targets[0], Speed * Time.deltaTime); ScaleCharacter(); yield return(null); } //update current area while moving int diff = SceneController.Instance.targetAreaIndex - SceneController.Instance.currentAreaIndex; if (diff != 0) { if (diff > 0) { SceneController.Instance.currentAreaIndex++; } else { SceneController.Instance.currentAreaIndex--; } } targets.RemoveAt(0); } if (source != null && source.orientation != Orientation.UNSPECIFIED) { if (source.orientation == Orientation.LEFT) { skeletonAnim.skeleton.FlipX = true; } else { skeletonAnim.skeleton.FlipX = false; } } skeletonAnim.AnimationState.SetAnimation(0, "idle", true); //calls action after reaching the destination if (action != null) { StateManager.Instance.DispatchAction(action, source); } }
void Awake() { if (LeftPages.Length != RightPages.Length) { throw new System.Exception("Number of left and right pages must be equal."); } TotalPages = LeftPages.Length; StopReading = new SpringAction(StopReadingAction, null, null); FadeIn = new List <Coroutine>(); }
/// <summary> /// Changes game state depending on dispatched action. /// Notifies subscribed changables about these changes. /// </summary> /// <param name="action">Dispatched action</param> /// <param name="actionSource">Interactable that dispatched action</param> public void DispatchAction(SpringAction action, IInteractable actionSource = null) { var newState = State; foreach (var reducer in reducers) { newState = reducer.Reduce(newState, action, actionSource); } var differences = newState.CompareChanges(State); var changed = differences.Count != 0; if (DebugLog) { Debug.Log("Action " + action.Type); if (changed) { foreach (var d in differences) { Debug.Log(d.Value.Count + " changes in " + d.Key); foreach (var change in d.Value) { Debug.Log(change); } } } else { Debug.Log("No changes."); } } if (!changed) { return; } foreach (var changable in Changables) { changable.OnStateChanged(newState, State); } State = newState; if (!Debug.isDebugBuild) { File.Delete(SaveDirectory + stateNumToFile(StateNum)); } StateNum++; saveStateToFile(); }
public void MoveTo(List <Vector3> targets, SpringAction action, IInteractable source) { if (!Busy) { if (move != null) { StopCoroutine(move); } move = StartCoroutine(MoveToCoroutine(targets, action, source)); } }
public override GameState Reduce(GameState state, SpringAction action, IInteractable source = null) { switch (action.Type) { case ActionType.GIVE_MONEY_TO_SHRINE: { var used = new HashSet <int>(state.HubaForest.UsedItems); used.Add((int)HubaForestInventory.ItemIds.Coin); GameState s = state.Set(state.HubaForest.SetUsedItems(used)); return(s.Set(s.HubaForest.SetIsHubaBlessed(true))); } case ActionType.BUY_IN_FOREST: { InventoryAnimator.Instance.Animate(); // Pickup whatever was bought int item = (int)action.Data; var pickedUp = new HashSet <int>(state.HubaForest.PickedUpItems); pickedUp.Add(item); // Pay with coin var used = new HashSet <int>(state.HubaForest.UsedItems); used.Add((int)HubaForestInventory.ItemIds.Coin); GameState s = state.Set(state.HubaForest.SetPickedUpItems(pickedUp)); return(s.Set(s.HubaForest.SetUsedItems(used))); } case ActionType.START_READING_MAP: return(state.Set(state.HubaForest.SetIsReadingMap(true))); case ActionType.STOP_READING_MAP: return(state.Set(state.HubaForest.SetIsReadingMap(false))); case ActionType.GO_TO_FOREST: return(state.Set(state.HubaForest.SetIsInForest(true))); case ActionType.GO_FOREST_LEFT: return(GoForestCrossroads(state, ForestSSC.Direction.Left)); case ActionType.GO_FOREST_RIGHT: return(GoForestCrossroads(state, ForestSSC.Direction.Right)); case ActionType.START_FOREST_SCENE: return(state.Set(state.HubaForest.SetIsSceneStarted(true))); } return(state); }
public bool MoveCharToObject(GameObject obj, SpringAction action = null, IInteractable interactable = null) { if (!CanCharacterMove) { if (action != null) { StateManager.Instance.DispatchAction(action, interactable); if (interactable != null && interactable.orientation != Orientation.UNSPECIFIED) { GameObject.FindGameObjectWithTag("Character") .GetComponent <SkeletonAnimation>() .skeleton.FlipX = interactable.orientation == Orientation.LEFT; } return(true); } else { return(false); } } RaycastHit2D hit = Physics2D.Raycast(obj.transform.position, -Vector2.up, Mathf.Infinity, 0 | (1 << LayerMask.NameToLayer("WalkableArea"))); Vector2 destination; //Debug.Log(hit.point); if (hit.collider == null) { hit = Physics2D.Raycast(obj.transform.position, Vector2.up, Mathf.Infinity, 0 | (1 << LayerMask.NameToLayer("WalkableArea"))); //Debug.Log(hit.point); destination = hit.point; destination.y += 0.001f; } else { destination = hit.point; destination.y -= 0.001f; } if (hit.collider != null) { //Debug.Log(hit.collider.name); CharacterInput walkableArea = hit.collider.gameObject.GetComponent <CharacterInput>(); if (walkableArea != null) { walkableArea.MoveToPoint(destination, action, interactable); return(true); } } return(false); }
protected override void Awake() { base.Awake(); TakeFlower = new SpringAction(ActionType.TAKE, "Take flower", icons[1], (int)AnnanaInventory.ItemIds.Flower); TakeBerry = new SpringAction(ActionType.TAKE, "Take berry", icons[0], (int)AnnanaInventory.ItemIds.Berry); TakeLeaf = new SpringAction(ActionType.TAKE, "Take leaf", icons[2], (int)AnnanaInventory.ItemIds.Leaf); Actions = new List <SpringAction> { TakeFlower, TakeBerry, TakeLeaf }; }
// Calculates path for character to move along to reach destination public void MoveToPoint(Vector2 destination, SpringAction action = null, IInteractable source = null) { if (WalkableArea.OverlapPoint(destination)) //checks whether mouse is in the walkable area { int i; int target = -1; targets.Clear(); for (i = 0; i < areas.Length; i++) //checks which area is the destination in { if (areas[i].OverlapPoint(destination)) { target = i; break; } } Vector3 tmp; i = SceneController.Instance.currentAreaIndex; if (target < i) //path through areas with decreasing numbers { while (i > target) { tmp = new Vector3(transPoints[i].position.x, transPoints[i].position.y); targets.Add(tmp); i--; } } else //path through areas with increasing numbers { while (i < target) { tmp = new Vector3(transPoints[i + 1].position.x, transPoints[i + 1].position.y); targets.Add(tmp); i++; } } tmp = new Vector3(destination.x, destination.y); targets.Add(tmp); SceneController.Instance.targetAreaIndex = target; Character.MoveTo(targets, action, source); } }
public override GameState Reduce(GameState state, SpringAction action, IInteractable source = null) { switch (action.Type) { case ActionType.GET_ELIXIR: { InventoryAnimator.Instance.Animate(); // Pickup whatever was delivered var pickedUp = new HashSet <int>(state.HubaBus.PickedUpItems); var elixir = state.AnnanaHouse.OwlPackage; if (elixir == (int)AnnanaInventory.ItemIds.Antidote) { pickedUp.Add((int)HubaBusInventory.ItemIds.Antidote); } else if (elixir == (int)AnnanaInventory.ItemIds.Shrink) { pickedUp.Add((int)HubaBusInventory.ItemIds.Shrink); } else if (elixir == (int)AnnanaInventory.ItemIds.Invis) { pickedUp.Add((int)HubaBusInventory.ItemIds.Invis); } else if (elixir == (int)AnnanaInventory.ItemIds.Soup) { pickedUp.Add((int)HubaBusInventory.ItemIds.Soup); } else { Debug.Log("opened weird elixir"); } source.gameObject.GetComponent <PackagedElixir>().TogglePackage(false); GameState s = state.Set(state.HubaBus.SetPickedUpItems(pickedUp)); return(s.Set(s.HubaBus.SetisOpened(true))); } case ActionType.DELIVERY: { return(state.Set(state.HubaBus.SetisDelivered(true))); } case ActionType.ARRIVAL: { return(state.Set(state.HubaBus.SetisBusWaiting(true))); } case ActionType.DEPARTURE: { return(state.Set(state.HubaBus.SethasBusLeft(true))); } case ActionType.EXIT_HOUSE: { return(state.Set(state.HubaBus.SetisOutOfTheHouse(true))); } case ActionType.DRINK: { var used = new HashSet <int>(state.HubaBus.UsedItems); var elixir = state.AnnanaHouse.OwlPackage; if (elixir == (int)AnnanaInventory.ItemIds.Antidote) { used.Add((int)HubaBusInventory.ItemIds.Antidote); } else if (elixir == (int)AnnanaInventory.ItemIds.Shrink) { used.Add((int)HubaBusInventory.ItemIds.Shrink); } else if (elixir == (int)AnnanaInventory.ItemIds.Invis) { used.Add((int)HubaBusInventory.ItemIds.Invis); } else if (elixir == (int)AnnanaInventory.ItemIds.Soup) { used.Add((int)HubaBusInventory.ItemIds.Soup); } GameState s = state.Set(state.HubaBus.SetUsedItems(used)); return(s.Set(s.HubaBus.SetisDrunk(true))); } case ActionType.GET_TICKET: { var elixir = state.AnnanaHouse.OwlPackage; if (elixir == (int)AnnanaInventory.ItemIds.Antidote) { DialogManager.Instance.SetDialogue((int)HubaBusDialogManager.DialogueTypes.Edible); DialogManager.Instance.Next(); } else { DialogManager.Instance.SetDialogue((int)HubaBusDialogManager.DialogueTypes.Poisonous); DialogManager.Instance.Next(); } //source.gameObject.SetActive(false); return(state.Set(state.HubaBus.SetaskedForTicket(true))); } case ActionType.BUY_TICKET: { var used = new HashSet <int>(state.HubaBus.UsedItems); used.Add((int)HubaBusInventory.ItemIds.GoldCoins); GameState s = state.Set(state.HubaBus.SetUsedItems(used)); return(s.Set(s.HubaBus.SetgetOnTheBus(true))); } case ActionType.IN_THE_BUS: { return(state.Set(state.HubaBus.SetisInTheBus(true))); } } return(state); }
/// <summary> /// Processes dispatched action. Describes how state should change /// based on dispatched action and current state. /// </summary> /// <param name="action">Dispatched action</param> /// <param name="state">Current state</param> /// <param name="source">Interactable that dispatched action</param> /// <returns>Updated state</returns> abstract public GameState Reduce(GameState state, SpringAction action, IInteractable source = null);
void OnMouseDown() { SpringAction action = new SpringAction(ExitAction, null, null); GameController.Instance.MoveCharToObject(gameObject, action); }
public override GameState Reduce(GameState state, SpringAction action, IInteractable source = null) { switch (action.Type) { case ActionType.TURN_ALARM_OFF: Bed.MoveHandAnimation(); return(state.Set(state.AnnanaHouse.SetAlarmTurnedOff(true))); case ActionType.POSTPONE_ALARM: Bed.MoveHandAnimation(); return(state.Set(state.AnnanaHouse.SetAlarmPostponed(true))); case ActionType.RESET_ALARM: return(state.Set(state.AnnanaHouse.SetAlarmPostponed(false))); case ActionType.CHANGE_CLOTHES: { string dress = (string)action.Data; return(state.Set(state.AnnanaHouse.SetAnnanaDress(dress))); } case ActionType.START_READING_VEGAN_BOOK: return(state.Set(state.AnnanaHouse.SetReadingVeganBook(true).SetReadVeganBook(true))); case ActionType.STOP_READING_VEGAN_BOOK: return(state.Set(state.AnnanaHouse.SetReadingVeganBook(false))); case ActionType.GO_OUTSIDE: { GameState s = state.Set(state.AnnanaHouse.SetIsOutside(true)); return(s.Set(s.AnnanaHouse.SetIsInside(false))); } case ActionType.GO_INSIDE: { GameState s = state.Set(state.AnnanaHouse.SetIsInside(true)); return(s.Set(s.AnnanaHouse.SetIsOutside(false))); } case ActionType.FLY_AWAY: return(state.Set(state.AnnanaHouse.SetFlyAway(true))); case ActionType.TAKE: { InventoryAnimator.Instance.Animate(); int itemId = (int)action.Data; switch ((AnnanaInventory.ItemIds)itemId) { case AnnanaInventory.ItemIds.Flower: return(state.Set(state.AnnanaHouse.SetIsFlowerPickedUp(true))); case AnnanaInventory.ItemIds.CrystalBall: return(state.Set(state.AnnanaHouse.SetIsCrystalBallPickedUp(true))); case AnnanaInventory.ItemIds.EmptyVial: return(state.Set(state.AnnanaHouse.SetIsEmptyVialPickedUp(true))); case AnnanaInventory.ItemIds.Berry: return(state.Set(state.AnnanaHouse.SetIsBerryPickedUp(true))); case AnnanaInventory.ItemIds.Leaf: return(state.Set(state.AnnanaHouse.SetIsLeafPickedUp(true))); case AnnanaInventory.ItemIds.NoteAddress: return(state.Set(state.AnnanaHouse.SetIsAddressPickedUp(true))); } break; } case ActionType.THROW_TO_BOILER: { int itemId = (int)action.Data; // Throw in new item HashSet <int> contents = new HashSet <int>(state.AnnanaHouse.BoilerContents); contents.Add(itemId); GameState s = null; switch ((AnnanaInventory.ItemIds)itemId) { case AnnanaInventory.ItemIds.Flower: s = state.Set(state.AnnanaHouse.SetIsFlowerUsed(true)); break; case AnnanaInventory.ItemIds.EmptyVial: s = state.Set(state.AnnanaHouse.SetIsEmptyVialUsed(true)); break; case AnnanaInventory.ItemIds.Berry: s = state.Set(state.AnnanaHouse.SetIsBerryUsed(true)); break; case AnnanaInventory.ItemIds.Leaf: s = state.Set(state.AnnanaHouse.SetIsLeafUsed(true)); break; default: break; } return(s.Set(s.AnnanaHouse.SetBoilerContents(contents))); } case ActionType.EMPTY_BOILER: return(state.Set(state.AnnanaHouse.SetBoilerContents(new HashSet <int>()))); case ActionType.FILL_ELIXIR: { InventoryAnimator.Instance.Animate(); GameState s = state.Set(state.AnnanaHouse.SetIsEmptyVialUsed(true)); HashSet <int> ingredients = state.AnnanaHouse.BoilerContents; var inv = Inventory.Instance as AnnanaInventory; var e = inv.Elixirs .Where(x => x.Value.Ingredients.SetEquals(ingredients)) .FirstOrDefault(); if (e.Value == null) // Unknown elixir = soup { return(s.Set(s.AnnanaHouse.SetElixirId((int)AnnanaInventory.ElixirTypes.Soup))); } // Known elixir set it return(s.Set(s.AnnanaHouse.SetElixirId(e.Key))); } case ActionType.GIVE_ADDRESS_TO_OWL: { GameState s = state.Set(state.AnnanaHouse.SetIsAddressUsed(true)); return(s.Set(s.AnnanaHouse.SetOwlHasAddress(true))); } case ActionType.GIVE_PACKAGE_TO_OWL: { // Assume only elixirs can be sent GameState s = state.Set(state.AnnanaHouse.SetIsElixirUsed(true)); return(s.Set(s.AnnanaHouse.SetOwlPackage((int)action.Data))); } case ActionType.START_READING_FRIDGE_NOTE: return(state.Set(state.AnnanaHouse.SetIsReadingFridgeNote(true).SetDidReadFridgeNote(true))); case ActionType.STOP_READING_FRIDGE_NOTE: return(state.Set(state.AnnanaHouse.SetIsReadingFridgeNote(false))); } return(state); }
public bool ComeCloser(SpringAction action = null) { return(GameController.Instance.MoveCharToObject(gameObject, action, this)); }
public override GameState Reduce(GameState state, SpringAction action, IInteractable source = null) { HashSet <int> newItems; switch (action.Type) { case ActionType.GO_OUTSIDE: { GameState s = state.Set(state.AnnanaTeaParty.SetIsOutside(true)); return(s.Set(s.AnnanaTeaParty.SetIsInside(false))); } case ActionType.GO_INSIDE: { GameState s = state.Set(state.AnnanaTeaParty.SetIsInside(true)); return(s.Set(s.AnnanaTeaParty.SetIsOutside(false))); } case ActionType.TAKE: int itemId = (int)action.Data; var oldItems = state.AnnanaTeaParty.PickedUpItems; if (Enum.IsDefined(typeof(Item), itemId)) { newItems = new HashSet <int>(oldItems); newItems.Add(itemId); if (newItems.Equals(oldItems)) { return(state); } switch ((Item)itemId) { case Item.PotEmpty: case Item.PotColdWater: case Item.PotHotWater: state = state.Set(state.AnnanaTeaParty.SetTeapotOnTheTable(false).SetTeapotOnTheStove(-1)); break; } InventoryAnimator.Instance.Animate(); return(state.Set(state.AnnanaTeaParty.SetPickedUpItems(newItems))); } break; case ActionType.FILL_TEAPOT: { InventoryAnimator.Instance.Animate(); return(state.Set(state.AnnanaTeaParty.SetPickedUpItems( swap(state, Item.PotColdWater, Item.PotEmpty )))); } case ActionType.PUT_TEAPON_ON_THE_STOVE: var inventory = state.AnnanaTeaParty.PickedUpItems; var pots = new Item[] { Item.PotEmpty, Item.PotColdWater, Item.PotHotWater }; var heldPod = Item.None; int potId = -1; foreach (var pot in pots) { potId++; if (inventory.Contains((int)pot)) { heldPod = pot; break; } } return(state.Set( state.AnnanaTeaParty.SetPickedUpItems( remove(state, heldPod) ).SetTeapotOnTheStove(potId))); case ActionType.WATER_BOILED: return(state.Set(state.AnnanaTeaParty.SetTeapotOnTheStove(2))); case ActionType.FILL_CUP: return(state.Set( state.AnnanaTeaParty.SetPickedUpItems( remove(state, (Item)action.Data )).SetWaterInTheCup((int)action.Data))); case ActionType.USE_TEA_BAG: return(state.Set( state.AnnanaTeaParty.SetPickedUpItems( remove(state, Item.TeaBag )).SetTeaBagInTheCup(true))); case ActionType.STEEP_TEA: return(state.Set(state.AnnanaTeaParty.SetWaterInTheCup(0))); case ActionType.OVERSTEEP_TEA: return(state.Set(state.AnnanaTeaParty.SetWaterInTheCup(3))); case ActionType.DRINK_TEA: var happy = state.AnnanaTeaParty.WaterInTheCup == 0; return(state.Set( state.AnnanaTeaParty .SetPickedUpItems(add(state, Item.Cup)) .SetWaterInTheCup(-1) .SetDrankTea(true).SetIsHappy(happy) )); case ActionType.WALKED_OUT: return(state.Set(state.AnnanaTeaParty.SetInTheKitchen(false))); case ActionType.TAKE_FINE: return(state.Set(state.AnnanaTeaParty.SetIsReadingTheFine(true).SetTookTheFine(true))); case ActionType.FINISH_READING_FINE: return(state.Set(state.AnnanaTeaParty.SetIsReadingTheFine(false))); case ActionType.FLY_AWAY: return(state.Set(state.AnnanaTeaParty.SetOwlFlownAway(true))); case ActionType.THROW_CUP: return(state.Set(state.AnnanaTeaParty.SetThrewCup(true))); case ActionType.UNLOCK_FRIDGE: LockManager.Instance.Open(); break; case ActionType.FRIDGE_UNLOCKED: return(state.Set(state.AnnanaTeaParty.SetIsLockOpen(true))); } return(state); }