예제 #1
0
        /// <summary>
        /// Opens an outlet at a given position on a settlement (or a random one).
        /// </summary>
        public void OpenOutlet(Vector2 position = null)
        {
            //Need to generate a random position?
            if (position == null)
            {
                position = settlement.GetFreeRandomPosition();
            }
            else
            {
                //Check if the position is occupied.
                if (settlement.IsOccupied(position))
                {
                    throw new Exception("Cannot open an outlet there, the space is occupied.");
                }
            }

            //Sufficient balance?
            if (Balance < OutletCost)
            {
                throw new Exception("Cannot open an outlet, insufficient company balance.");
            }

            //Open the outlet.
            Balance -= Math.Round(OutletCost, 2);
            outlets.Add(new Outlet(settlement, this, position, OutletCapacity, DailyCost));

            //Log in the event chain.
            EventChain.AddEvent(new OutletCreateEvent()
            {
                Position = position,
                Capacity = OutletCapacity
            });
        }
예제 #2
0
        /// <summary>
        /// Visit the outlet (increments visits for today).
        /// </summary>
        public void Visit(Vector2 origin)
        {
            visitsToday++;

            //Log event.
            EventChain.AddEvent(new VisitOutletEvent()
            {
                Company   = ParentCompany.Name,
                Household = origin,
                OutletPos = Position
            });
        }
예제 #3
0
        /// <summary>
        /// Processes the end of the day for this company.
        /// </summary>
        public void ProcessDayEnd()
        {
            //Set up locals.
            double deliveryCosts = 0, profitLossFromOutlets = 0;

            //Move all the food trucks first.
            foreach (var outlet in outlets)
            {
                if (outlet is FoodTruck)
                {
                    //Move it.
                    ((FoodTruck)outlet).Move();
                }
            }

            //Calculate delivery costs.
            deliveryCosts += BaseDeliveryCost + CalculateDeliveryCost();
            Balance       -= Math.Round(deliveryCosts, 2);
            EventChain.AddEvent(new DeliveryEvent()
            {
                CompanyName = Name,
                Cost        = Math.Round(deliveryCosts, 2),
                Type        = EventType.Delivery
            });

            //Calculate outlet profit and loss.
            foreach (var outlet in outlets)
            {
                double thisOutletProfit = outlet.GetDailyProfit(avgCostPerMeal, avgPricePerMeal);
                profitLossFromOutlets += thisOutletProfit;

                //Log an outlet's profits/losses.
                EventChain.AddEvent(new OutletProfitEvent()
                {
                    ProfitLoss = Math.Round(thisOutletProfit, 2),
                    Company    = Name
                });

                outlet.ProcessDayEnd();
            }

            //Update balance.
            Balance += Math.Round(profitLossFromOutlets, 2);

            //Close the company?
            if (Balance <= 0)
            {
                CloseAllOutlets();
            }
        }
예제 #4
0
        /// <summary>
        /// Adds a random number of households (default 1-5) to the settlement.
        /// </summary>
        private void ProcessAddHouseholdsEvent()
        {
            int newHouseholds = Random.Next(Settings.Get.MinNewHouseholds, Settings.Get.MaxNewHouseholds);
            int stored        = newHouseholds;

            while (newHouseholds > 0)
            {
                Settlement.AddHousehold();
                newHouseholds--;
            }

            //Log to the event chain.
            EventChain.AddEvent(new AddHouseholdsEvent()
            {
                NumHouses = stored
            });
        }
예제 #5
0
파일: FoodTruck.cs 프로젝트: c272/skeletron
        /// <summary>
        /// Moves one square in a random direction.
        /// </summary>
        public void Move()
        {
            //Calculate a random direction.
            int x    = base.Position.x;
            int y    = base.Position.y;
            int rand = Simulation.Random.Next(0, 3);

            switch (rand)
            {
            case 0: x--; break;

            case 1: x++; break;

            case 2: y--; break;

            case 3: y++; break;
            }

            //Clamp inside the settlement.
            x.Clamp(0, base.settlement.Width - 1);
            y.Clamp(0, base.settlement.Height - 1);

            //Is the position occupied? Don't move.
            if (settlement.IsOccupied(new Vector2(x, y)))
            {
                return;
            }

            //Set position, update on settlement too.
            Vector2 old = Position;

            Position = new Vector2(x, y);
            settlement.Unoccupy(old);
            settlement.Occupy(Position);

            //Log the event.
            EventChain.AddEvent(new FoodTruckMoveEvent()
            {
                From    = old,
                To      = Position,
                Company = base.ParentCompany.Name
            });
        }
예제 #6
0
        /// <summary>
        /// Process all of the leavers from the settlement.
        /// </summary>
        public void ProcessLeavers()
        {
            int removed = 0;

            for (int i = 0; i < Households.Count; i++)
            {
                //2% chance for a household to leave by default.
                if (Simulation.Random.NextDouble() < Settings.Get.ChanceOfHouseholdLeaving)
                {
                    Households.RemoveAt(i);
                    i--;
                    removed++;
                }
            }

            //Log to event chain.
            EventChain.AddEvent(new HouseholdLeavingEvent()
            {
                NumHouseholds = removed
            });
        }
예제 #7
0
        /// <summary>
        /// Changes the price of fuel randomly.
        /// </summary>
        protected virtual void ProcessChangeFuelCostEvent()
        {
            //Check if fuel price increases or decreases, get by how much.
            bool   increases = (Random.NextDouble() < Settings.Get.ChanceOfFuelPriceIncrease);
            double amt       = Random.Next(1, 10) / 10.0;

            //Which company is it for?
            int companyIndex = Random.Next(0, Companies.Count - 1);

            //Complete the change, log.
            if (!increases)
            {
                amt = -amt;
            }
            Companies[companyIndex].ChangeFuelCostBy(amt);

            EventChain.AddEvent(new FuelCostChangeEvent()
            {
                AmountBy = amt,
                Company  = Companies[companyIndex].Name,
            });
        }
예제 #8
0
        /// <summary>
        /// Changes a random cost for a single company by a random amount.
        /// </summary>
        private void ProcessCostChangeEvent()
        {
            //How much to change by, should it go up or down, and which company should it be applied to?
            bool   increases = (Random.NextDouble() < Settings.Get.ChanceOfCostIncrease);
            double amt       = Random.NextDouble() * 10.0;

            if (!increases)
            {
                amt = -amt;
            }
            int companyIndex = Random.Next(0, Companies.Count - 1);

            //Figured it out, determine which cost to increase/decrease.
            int    costType = Random.Next(0, 1);
            string costTypeStr;

            if (costType == 0)
            {
                //Change the daily cost for the company.
                costTypeStr = "daily cost";
                amt        *= 2;
                Companies[companyIndex].ChangeDailyCostBy(amt);
            }
            else
            {
                //Change the average meal costs for a company.
                costTypeStr = "average meal cost";
                Companies[companyIndex].ChangeAvgMealCostBy(amt);
            }

            //Log as an event.
            EventChain.AddEvent(new CostChangeEvent()
            {
                AmountBy = amt,
                Company  = Companies[companyIndex].Name,
                CostType = costTypeStr
            });
        }
예제 #9
0
        /// <summary>
        /// Changes a single company's reputation randomly.
        /// </summary>
        private void ProcessChangeReputationEvent()
        {
            //Calculate the amount, and whether it's increasing or decreasing.
            bool   increases = (Random.NextDouble() < Settings.Get.ChanceOfReputationIncrease);
            double amt       = Random.Next(1, 10) / 10.0;

            if (!increases)
            {
                amt = -amt;
            }

            //Which company is this for?
            int companyIndex = Random.Next(0, Companies.Count - 1);

            //Apply and log.
            Companies[companyIndex].ChangeReputationBy(amt);

            EventChain.AddEvent(new ReputationChangeEvent()
            {
                Company  = Companies[companyIndex].Name,
                AmountBy = amt
            });
        }
예제 #10
0
        /// <summary>
        /// Ends the current day, and moves onto the next one.
        /// </summary>
        public void ProcessDayEnd()
        {
            //Gather the cumulative reputation for all companies.
            double        totalReputation      = 0;
            List <double> cumulativeReputation = new List <double>();

            CompaniesClosedYesterday = new List <Company>();
            foreach (var c in Companies)
            {
                totalReputation += c.Reputation;
                cumulativeReputation.Add(totalReputation);
            }

            //Loop over each house and see if they eat out, and if so, where.
            visits = new List <Tuple <Vector2, Vector2> >();
            CalculateVisitsFromHouseholds(cumulativeReputation, totalReputation);

            //Process the end of the day for each company.
            for (int i = 0; i < Companies.Count; i++)
            {
                Companies[i].ProcessDayEnd();

                //Is the company bankrupt?
                if (Companies[i].Balance < 0)
                {
                    //Bankrupt the company, remove from list (log event).
                    EventChain.AddEvent(new BankruptcyEvent()
                    {
                        CompanyName = Companies[i].Name,
                        DaysLasted  = DaysElapsed
                    });
                    CompaniesClosedYesterday.Add(Companies[i]);
                    Companies.RemoveAt(i);
                    i--;
                }
            }

            //Only do random events if companies still exist.
            if (Companies.Count > 0)
            {
                //Choose the random events that will occur at this day end.
                double eventRand = Random.NextDouble();
                if (eventRand < Settings.Get.BaseChanceOfRandomEvents)
                {
                    //Random household addition event.
                    eventRand = Random.NextDouble();
                    if (eventRand < Settings.Get.ChanceOfAddHouseholdsEvent)
                    {
                        ProcessAddHouseholdsEvent();
                    }

                    //Random fuel cost change event.
                    eventRand = Random.NextDouble();
                    if (eventRand < Settings.Get.ChanceOfChangeFuelCostEvent)
                    {
                        ProcessChangeFuelCostEvent();
                    }

                    //Random reputation change event.
                    eventRand = Random.NextDouble();
                    if (eventRand < Settings.Get.ChanceOfReputationChangeEvent)
                    {
                        ProcessChangeReputationEvent();
                    }

                    //Random daily cost change event.
                    eventRand = Random.NextDouble();
                    if (eventRand < Settings.Get.ChanceOfCostChangeEvent)
                    {
                        ProcessCostChangeEvent();
                    }
                }
            }

            //Process households leaving for the day.
            Settlement.ProcessLeavers();

            //End this day's event chain, and start a new one.
            EventChain.Refresh();

            //Draw the new map with updated positions and tracers, if the map is enabled.
            UpdateMap();
            DaysElapsed++;
        }
예제 #11
0
        /// <summary>
        /// Calculates visits from households based on both reputation AND distance AND type of company.
        /// </summary>
        protected override void CalculateVisitsFromHouseholds(List <double> cumulativeReputation, double totalReputation)
        {
            for (int i = 0; i < Settlement.NumHouseholds; i++)
            {
                Household thisHouse = Settlement.GetHouseholdAtIndex(i);

                //Does this household eat out?
                if (!thisHouse.EatsOut())
                {
                    continue;
                }

                //Pick a type of restaurant to eat at.
                CompanyType picked = PickRestaurantType();

                //Get outlets within a set boundary, of the selected type.
                double radius;
                switch (picked)
                {
                case CompanyType.Family:
                    radius = Settings.Get.BalancedSim_TravelRadiusFamily;
                    break;

                case CompanyType.FastFood:
                    radius = Settings.Get.BalancedSim_TravelRadiusFastFood;
                    break;

                case CompanyType.NamedChef:
                    radius = Settings.Get.BalancedSim_TravelRadiusNamedChef;
                    break;

                default:
                    //Unknown company type.
                    throw new Exception("Unknown company type to set travel radius for. Please update method.");
                }
                List <Outlet> outletsToPick = GetOutletsAround(thisHouse.Position, radius).Where(x => x.ParentCompany.Type == picked).ToList();

                //Are there any outlets to visit?
                if (outletsToPick.Count == 0)
                {
                    //Register a failed event.
                    EventChain.AddEvent(new FailedToEatOutEvent()
                    {
                        Origin     = thisHouse.Position,
                        Radius     = radius,
                        OutletType = picked
                    });

                    //This house is now done.
                    continue;
                }

                //Get the companies that these outlets have.
                List <Company> companiesNearMe = new List <Company>();
                foreach (var outlet in outletsToPick)
                {
                    if (companiesNearMe.FindIndex(x => x.Name == outlet.ParentCompany.Name) == -1)
                    {
                        companiesNearMe.Add(outlet.ParentCompany);
                    }
                }

                //Randomly roll on their reputation.
                double        totalRep        = companiesNearMe.Sum(x => x.Reputation);
                List <double> cumulativeRep   = companiesNearMe.Select(x => x.Reputation).CumulativeSum().ToList();
                double        randomSelection = Random.NextDouble() * totalRep;
                Company       selected        = null;

                for (int k = 0; k < cumulativeRep.Count; k++)
                {
                    if (randomSelection < cumulativeRep[k])
                    {
                        selected = companiesNearMe[k];
                        break;
                    }
                }

                //Successfully selected a company, visit!
                selected.AddVisitToNearestOutlet(thisHouse.Position, ref base.visits);
            }
        }
예제 #12
0
    public override void OnInspectorGUI()
    {
        // Setting the GUI Styles
        guiStyleBox         = new GUIStyle(GUI.skin.box);
        guiStyleBox.margin  = new RectOffset(0, 20, 10, 0);
        guiStyleBox.padding = new RectOffset(20, 20, 10, 10);

        guiStyleLabel          = new GUIStyle(GUI.skin.label);
        guiStyleLabel.richText = true;

        guiStyleButton         = new GUIStyle(GUI.skin.button);
        guiStyleButton.margin  = new RectOffset(0, 20, 10, 0);
        guiStyleButton.padding = new RectOffset(10, 10, 5, 5);


        // Draw chain's properties
        EditorGUILayout.Space(10);

        chain.trigger = (EventChain.EventTrigger)EditorGUILayout.EnumPopup("Trigger", chain.trigger);
        chain.radius  = EditorGUILayout.FloatField("Radius", chain.radius);
        if (chain.trigger != EventChain.EventTrigger.Interact)
        {
            chain.groundedOnly = EditorGUILayout.Toggle("Grounded Only", chain.groundedOnly);
        }

        EditorGUILayout.Space(10);

        // For every event in the chain
        for (int i = 0; i < chain.events.Count; i++)
        {
            EditorGUILayout.BeginVertical(guiStyleBox);

            // Draw Event header
            EditorGUILayout.BeginHorizontal(guiStyleLabel);

            string label = (i + 1) + " - " + chain.events[i].GetEventName();
            //if (GUILayout.Button(chain.events[i].visible? "<b>" + label + "</b>" : label, guiStyleLabel))
            //    chain.events[i].visible = !chain.events[i].visible;


            chain.events[i].visible = EditorGUILayout.Foldout(chain.events[i].visible, label);
            EditorGUILayout.EndHorizontal();

            // Draw Event content
            if (chain.events[i].visible)
            {
                // Call the expecific event's editor
                EditorGUILayout.BeginVertical();

                CreateEditor(chain.events[i]).OnInspectorGUI();

                EditorGUILayout.EndVertical();

                EditorGUILayout.Space(10);

                // Event actions
                EditorGUILayout.BeginHorizontal();

                if (GUILayout.Button("Move Up"))
                {
                    chain.MoveEventUp(i);
                }

                if (GUILayout.Button("Move Down"))
                {
                    chain.MoveEventDown(i);
                }

                if (GUILayout.Button("Duplicate"))
                {
                    chain.DuplicateEvent(i);
                }

                if (GUILayout.Button("Delete"))
                {
                    chain.DeleteEvent(i);
                }

                EditorGUILayout.EndHorizontal();
            }

            EditorGUILayout.EndVertical();
        }

        // Draw the event type dropdown
        EditorGUILayout.Separator();
        selectedEvent = (Events)EditorGUILayout.EnumPopup("Event Type", selectedEvent);

        // Draw Add event button
        if (GUILayout.Button("Add Event", guiStyleButton))
        {
            chain.AddEvent(GetEventType());
        }

        EditorGUILayout.Space(10);
    }