Ejemplo n.º 1
0
 GetDailySalesData(int operatorId, DateTime sessionDate, int sessionNum, CashInfo info)
 {
     m_id        = 18176;
     OperatorId  = operatorId;
     SessionDate = sessionDate;
     SessionNum  = sessionNum;
     Info        = info;
 }
Ejemplo n.º 2
0
        public static void DailySales(int operatorId, CashInfo info)
        {
            var msg = new SetDailySalesData(operatorId, info);

            try
            {
                msg.Send();
            }
            catch (ServerCommException ex)
            {
                throw new Exception("SetDailySalesData: " + ex.Message);
            }
        }
        /// <summary>
        /// Get account using id
        /// </summary>
        /// <param name="accId">Account id</param>
        /// <returns>Founded account</returns>
        public Account.Account GetAccountById(string accId)
        {
            using (AccountsStorageContext context = new AccountsStorageContext())
            {
                PersonInfo pi = context.Persons.SingleOrDefault(person => person.Id == accId);

                if (pi != null)
                {
                    Account.Account foundedAccount = new Account.Account(pi.Id, pi.Name, pi.SurName, pi.Mail, pi.Bonus);

                    List <PersonToCashLink> links = context.Links.Where(link => link.PersonId == pi.Id).ToList();
                    foreach (PersonToCashLink link in links)
                    {
                        CashInfo ci = context.Cashes.SingleOrDefault(cashInfo => cashInfo.Id == link.CashId);

                        switch ((CashType)ci.CashType)
                        {
                        case CashType.BaseCash:
                            BaseCash baseCash = new BaseCash(new BonusCalculator(0.05, 0.03), ci.Id);
                            baseCash.Amount = ci.Amount;
                            foundedAccount.AddCash((Currency)ci.Currency, baseCash);
                            break;

                        case CashType.GoldCash:
                            GoldCash goldCash = new GoldCash(new BonusCalculator(0.05, 0.03), ci.Id);
                            goldCash.Amount = ci.Amount;
                            foundedAccount.AddCash((Currency)ci.Currency, goldCash);
                            break;

                        case CashType.PlatinumCash:
                            PlatinumCash platinumCash = new PlatinumCash(new BonusCalculator(0.05, 0.03), ci.Id);
                            platinumCash.Amount = ci.Amount;
                            foundedAccount.AddCash((Currency)ci.Currency, platinumCash);
                            break;
                        }
                    }

                    return(foundedAccount);
                }
                else
                {
                    return(null);
                }
            }
        }
        /// <summary>
        /// Add account to database using storage structures
        /// </summary>
        /// <param name="account">Additing account</param>
        public void Add(Account.Account account)
        {
            using (AccountsStorageContext context = new AccountsStorageContext())
            {
                PersonInfo pi = new PersonInfo(account.Id, account.Name, account.SurName, account.Mail, account.Bonus);
                context.Persons.Add(pi);

                foreach (var cashInfo in account.Cash)
                {
                    CashInfo ci = new CashInfo(cashInfo.Value.Id, cashInfo.Value.Amount, (int)cashInfo.Key, (int)cashInfo.Value.GetCashType());
                    context.Cashes.Add(ci);

                    PersonToCashLink link = new PersonToCashLink(account.Id, cashInfo.Value.Id, GenerateLinkId());
                    context.Links.Add(link);
                }

                context.SaveChanges();
            }
        }
        protected override void SetCajaAction()
        {
            CashList       list = CashList.GetList(false);
            CashSelectForm form = new CashSelectForm(this, list);

            if (form.ShowDialog(this) == DialogResult.OK)
            {
                CashInfo caja = form.Selected as CashInfo;

                if (_caja != null)
                {
                    _caja.CloseSession();
                }

                _caja = Cash.Get(caja.Oid, false);

                UpdateSaldo();
            }
        }
Ejemplo n.º 6
0
        public static ItemInfo Parse(WZProperty characterItem)
        {
            WZProperty info    = characterItem.Resolve("info");
            ItemInfo   results = new ItemInfo();

            results.only        = (info.ResolveFor <int>("only") ?? 0) == 1;
            results.Equip       = EquipInfo.Parse(info);
            results.Cash        = CashInfo.Parse(info);
            results.Shop        = ShopInfo.Parse(info);
            results.Card        = CardInfo.Parse(info);
            results.Slot        = SlotInfo.Parse(info);
            results.Chair       = ChairInfo.Parse(info);
            results.Icon        = IconInfo.Parse(info);
            results.Set         = ItemSet.ParseItemInfo(info);
            results.ConsumeSpec = characterItem?.Resolve("spec")?.Children.ToDictionary(c => c.NameWithoutExtension, c => c.ResolveForOrNull <string>());

            if (characterItem?.FileContainer?.Collection is MSPackageCollection && int.TryParse(info.Parent.NameWithoutExtension, out int itemId))
            {
                ((MSPackageCollection)characterItem.FileContainer.Collection).ItemQuests?.TryGetValue(itemId, out results.RelatedQuests);
            }

            return(results);
        }
        /// <summary>
        /// Remove account from database
        /// </summary>
        /// <param name="accId">Account id</param>
        public void Remove(string accId)
        {
            using (AccountsStorageContext context = new AccountsStorageContext())
            {
                PersonInfo pi = context.Persons.SingleOrDefault(person => person.Id == accId);

                if (pi != null)
                {
                    context.Persons.Remove(pi);

                    List <PersonToCashLink> links = context.Links.Where(link => link.PersonId == pi.Id).ToList();
                    foreach (PersonToCashLink link in links)
                    {
                        CashInfo ci = context.Cashes.SingleOrDefault(cashInfo => cashInfo.Id == link.CashId);
                        context.Cashes.Remove(ci);

                        context.Links.Remove(link);
                    }

                    context.SaveChanges();
                }
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Handle the LoadSessionNumbers event from the wpf control.
        /// We call the server to get the availiable sessions for the date specified in the event args,
        /// then update the session list in the CashInfo class used as the DataContext for the control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CashAccountabilityControl1LoadSessionNumbers(object sender, CashReportSessionEventArgs e)
        {
            DateTime sessionDate = (DateTime)e.SessionDate;
            // FIX: TA7438 - Remove operator id from Get Session Number List.
            List <int> sessionNumbers = GetReportSessionList.GetList(sessionDate, sessionDate);

            List <KeyValuePair <int, string> > sessionList = new List <KeyValuePair <int, string> >
            {
                new KeyValuePair <int, string>(0, "All Sessions")
            };

            foreach (int num in sessionNumbers)
            {
                sessionList.Add(new KeyValuePair <int, string>(num, "Session " + num));
            }

            CashInfo cashInfo = cashAccountabilityControl1.DataContext as CashInfo;

            if (cashInfo != null)
            {
                cashInfo.Sessions = new ReadOnlyCollection <KeyValuePair <int, string> >(sessionList);
            }
        }
Ejemplo n.º 9
0
        protected override void SetRowFormat(DataGridViewRow row)
        {
            if (row.IsNewRow)
            {
                return;
            }

            CashInfo item = (CashInfo)row.DataBoundItem;

            if (item.SaldoAcumulado < 0)
            {
                row.Cells[SaldoInicial.Name].Style.ForeColor = System.Drawing.Color.Red;
            }

            if (item.SaldoParcial < 0)
            {
                row.Cells[Saldo.Name].Style.ForeColor = System.Drawing.Color.Red;
            }

            if (item.SaldoTotal < 0)
            {
                row.Cells[SaldoTotal.Name].Style.ForeColor = System.Drawing.Color.Red;
            }
        }
Ejemplo n.º 10
0
    public void give_time(int _time_sec, bool _dry_run, out CashInfo _cash_info, out CPUInfo _cpu_info, out long _mins_passed)       // dry_run=False
    {
        _cash_info = null;
        _cpu_info  = null;

        if (_time_sec == 0)
        {
            _mins_passed = 0;
            return;
        }

        int old_time    = this.raw_sec;
        int last_minute = this.raw_min;
        int last_day    = this.raw_day;

        this.raw_sec += _time_sec;
        this.update_times();

        int days_passed = this.raw_day - last_day;

        if (days_passed > 1)
        {
            // Back up until only one day passed.
            // Times will update below, since a day passed.
            int extra_days = days_passed - 1;
            this.raw_sec -= G.seconds_per_day * extra_days;
        }

        bool day_passed = (days_passed != 0);

        if (day_passed)
        {
            // If a day passed, back up to 00:00:00.
            this.raw_sec = this.raw_day * G.seconds_per_day;
            this.update_times();
        }

        int secs_passed = _time_sec;

        _mins_passed = this.raw_min - last_minute;

        long time_of_day = G.pl.raw_sec % G.seconds_per_day;

        long old_cash         = this.cash;
        long old_partial_cash = this.partial_cash;

        techs_researched.Clear();
        bases_constructed.Clear();
        cpus_constructed.Clear();
        items_constructed.Clear();

        bases_under_construction.Clear();
        items_under_construction.Clear();

        this.cpu_pool = 0;

        // Collect base info, including maintenance.
        this.maintenance_cost[0] = this.maintenance_cost[1] = this.maintenance_cost[2] = 0;
        foreach (Base _base in G.all_bases())
        {
            if (!_base.done)
            {
                bases_under_construction.Add(_base);
            }
            else
            {
                if (_base.cpus != null && !_base.cpus.done)
                {
                    items_under_construction.Add(new ArrayList()
                    {
                        _base, _base.cpus
                    });
                }

                // unfinished items
                foreach (Item item in _base.extra_items.Where(w => w != null && !w.done))
                {
                    items_under_construction.Add(new ArrayList()
                    {
                        _base, item
                    });
                }

                this.maintenance_cost[0] += _base.maintenance[0];
                this.maintenance_cost[1] += _base.maintenance[1];
                this.maintenance_cost[2] += _base.maintenance[2];
            }
        }

        // Maintenence?  Gods don't need no steenking maintenance!
        if (this.apotheosis)
        {
            this.maintenance_cost[0] = this.maintenance_cost[1] = this.maintenance_cost[2] = 0;
        }

        // Any CPU explicitly assigned to jobs earns its dough.
        long job_cpu = 0;

        if (this.cpu_usage.TryGetValue("jobs", out job_cpu))
        {
            job_cpu *= secs_passed;
        }
        long explicit_job_cash = this.do_jobs(job_cpu);

        // Pay maintenance cash, if we can.
        long cash_maintenance      = G.current_share(this.maintenance_cost[BuyableClass.cash], time_of_day, secs_passed);
        long full_cash_maintenance = cash_maintenance;

        if (cash_maintenance > this.cash)
        {
            cash_maintenance -= this.cash;
            this.cash         = 0;
        }
        else
        {
            this.cash       -= cash_maintenance;
            cash_maintenance = 0;
        }

        long tech_cpu  = 0;
        long tech_cash = 0;
        // Do research, fill the CPU pool.
        long default_cpu = this.available_cpus[0];

        foreach (KeyValuePair <string, long> P in this.cpu_usage)
        {
            string task         = P.Key;
            long   cpu_assigned = P.Value;

            if (cpu_assigned == 0)
            {
                continue;
            }

            default_cpu -= cpu_assigned;
            long real_cpu = cpu_assigned * secs_passed;
            if (task != "jobs")
            {
                this.cpu_pool += real_cpu;
                if (task != "cpu_pool")
                {
                    if (_dry_run)
                    {
                        long[] spent = new long[3] {
                            0, 0, 0
                        };
                        long[] paid = new long[3] {
                            0, 0, 0
                        };
                        G.techs[task].calculate_work(null, real_cpu, _mins_passed, ref spent, ref paid);
                        G.pl.cpu_pool -= spent[BuyableClass.cpu];
                        G.pl.cash     -= spent[BuyableClass.cash];
                        tech_cpu      += cpu_assigned;
                        tech_cash     += spent[BuyableClass.cash];
                        continue;
                    }

                    // Note that we restrict the CPU available to prevent
                    // the tech from pulling from the rest of the CPU pool.
                    bool tech_gained = G.techs[task].work_on(null, real_cpu, _mins_passed);
                    if (tech_gained)
                    {
                        techs_researched.Add(G.techs[task]);
                    }
                }
            }
        }

        this.cpu_pool += default_cpu * secs_passed;

        // And now we use the CPU pool.
        // Maintenance CPU.
        long cpu_maintenance = this.maintenance_cost[BuyableClass.cpu] * secs_passed;

        if (cpu_maintenance > this.cpu_pool)
        {
            cpu_maintenance -= this.cpu_pool;
            this.cpu_pool    = 0;
        }
        else
        {
            this.cpu_pool  -= cpu_maintenance;
            cpu_maintenance = 0;
        }

        long construction_cpu  = 0;
        long construction_cash = 0;

        // BaseES construction.
        foreach (Base _base in bases_under_construction)
        {
            if (_dry_run)
            {
                long[] spent = new long[3] {
                    0, 0, 0
                };
                long[] paid = new long[3] {
                    0, 0, 0
                };
                _base.calculate_work(null, this.cpu_pool, _mins_passed, ref spent, ref paid);
                G.pl.cpu_pool     -= spent[BuyableClass.cpu];
                G.pl.cash         -= spent[BuyableClass.cash];
                construction_cpu  += spent[BuyableClass.cpu];
                construction_cash += spent[BuyableClass.cash];
                continue;
            }

            bool built_base = _base.work_on(null, null, _mins_passed);

            if (built_base)
            {
                bases_constructed.Add(_base);
            }
        }

        // Item construction.
        foreach (ArrayList member in items_under_construction)
        {
            // base, item
            Base _base = member[0] as Base;
            Item item  = member[1] as Item;

            if (_dry_run)
            {
                long[] spent = new long[3] {
                    0, 0, 0
                };
                long[] paid = new long[3] {
                    0, 0, 0
                };
                item.calculate_work(null, 0, _mins_passed, ref spent, ref paid);
                G.pl.cpu_pool     -= spent[BuyableClass.cpu];
                G.pl.cash         -= spent[BuyableClass.cash];
                construction_cpu  += spent[BuyableClass.cpu];
                construction_cash += spent[BuyableClass.cash];
                continue;
            }

            bool built_item = item.work_on(null, null, _mins_passed);

            if (built_item)
            {
                // Non-CPU items.
                if ((item.type as ItemClass).item_type != "cpu")
                {
                    items_constructed.Add(new ArrayList()
                    {
                        _base, item
                    });
                }
                // CPUs.
                else
                {
                    cpus_constructed.Add(new ArrayList()
                    {
                        _base, item
                    });
                }
            }
        }

        // Jobs via CPU pool.
        long pool_job_cash = 0;

        if (this.cpu_pool > 0)
        {
            pool_job_cash = this.do_jobs(this.cpu_pool);
        }

        // Second attempt at paying off our maintenance cash.
        if (cash_maintenance > this.cash)
        {
            // In the words of Scooby Doo, "Ruh roh."
            cash_maintenance -= this.cash;
            this.cash         = 0;
        }
        else
        {
            // Yay, we made it!
            this.cash       -= cash_maintenance;
            cash_maintenance = 0;
        }

        // Exit point for a dry run.
        if (_dry_run)
        {
            // Collect the cash information.
            _cash_info = new CashInfo();

            _cash_info.interest = this.get_interest();
            _cash_info.income   = this.income;
            this.cash          += _cash_info.interest + _cash_info.income;

            _cash_info.explicit_jobs = explicit_job_cash;
            _cash_info.pool_jobs     = pool_job_cash;
            _cash_info.jobs          = explicit_job_cash + pool_job_cash;

            _cash_info.tech         = tech_cash;
            _cash_info.construction = construction_cash;

            _cash_info.maintenance_needed    = full_cash_maintenance;
            _cash_info.maintenance_shortfall = cash_maintenance;
            _cash_info.maintenance           = full_cash_maintenance - cash_maintenance;

            _cash_info.start = old_cash;
            _cash_info.end   = this.cash;


            // Collect the CPU information.
            _cpu_info = new CPUInfo();

            _cpu_info.available = this.available_cpus[0];
            _cpu_info.sleeping  = this.sleeping_cpus;
            _cpu_info.total     = _cpu_info.available + _cpu_info.sleeping;

            _cpu_info.tech         = tech_cpu;
            _cpu_info.construction = construction_cpu;

            _cpu_info.maintenance_needed    = this.maintenance_cost[BuyableClass.cpu];
            _cpu_info.maintenance_shortfall = cpu_maintenance;
            _cpu_info.maintenance           = _cpu_info.maintenance_needed - _cpu_info.maintenance_shortfall;

            long temp = 0;
            this.cpu_usage.TryGetValue("jobs", out temp);
            _cpu_info.explicit_jobs = temp;
            _cpu_info.pool_jobs     = this.cpu_pool / _time_sec;
            _cpu_info.jobs          = temp + _cpu_info.pool_jobs;

            temp = 0;
            this.cpu_usage.TryGetValue("cpu_pool", out temp);
            _cpu_info.explicit_pool = temp;
            _cpu_info.default_pool  = default_cpu;
            _cpu_info.pool          = temp + default_cpu;

            // Restore the old state.
            this.cash         = old_cash;
            this.partial_cash = old_partial_cash;
            this.raw_sec      = old_time;
            this.update_times();

            _mins_passed = -1;             // undefined...

            return;
        }

        // Tech gain dialogs.
        foreach (Tech tech in techs_researched)
        {
            this.cpu_usage.Remove(tech.id);
            string text = string.Format(G.strings["tech_gained"], tech.name, tech.result);
            this.pause_game();
            G.map_screen.show_message(text, Color.white);
        }

        // Base complete dialogs.
        foreach (Base _base in bases_constructed)
        {
            string text = string.Format(G.strings["construction"], _base.name); // {"base": base.name}
            this.pause_game();
            G.map_screen.show_message(text, Color.white);

            if (_base.type.id == "Stolen Computer Time" && _base.cpus.type.id == "Gaming PC")
            {
                text = string.Format(G.strings["lucky_hack"], _base.name);  //  % {"base": base.name}
                G.map_screen.show_message(text, Color.white);
            }
        }

        // CPU complete dialogs.
        foreach (ArrayList member in cpus_constructed)
        {
            Base _base = member[0] as Base;
            // List<Item> cpus = member[1] as List<Item>;

            string text;

            if (_base.cpus.count == (_base.type as Base_Class).size)                                           // Finished all CPUs.
            {
                text = string.Format(G.strings["item_construction_single"], _base.cpus.type.name, _base.name); // {"item": base.cpus.type.name, "base": base.name}
            }
            else // Just finished this batch of CPUs.
            {
                text = string.Format(G.strings["item_construction_batch"], _base.cpus.type.name, _base.name);  // {"item": base.cpus.type.name, "base": base.name}
            }
            this.pause_game();
            G.map_screen.show_message(text, Color.white);
        }

        // Item complete dialogs.
        foreach (ArrayList member in items_constructed)
        {
            Base   _base = member[0] as Base;
            Item   item  = member[1] as Item;
            string text  = string.Format(G.strings["item_construction_single"], item.type.name, _base.name);            // {"item": item.type.name, "base": base.name}
            this.pause_game();
            G.map_screen.show_message(text, Color.white);
        }

        // Are we still in the grace period?
        bool grace = this.in_grace_period(this.had_grace);

        // If we just lost grace, show the warning.
        if (this.had_grace && !grace)
        {
            this.had_grace = false;

            this.pause_game();
            G.map_screen.show_message(G.strings["grace_warning"], Color.white);
        }

        // Maintenance death, discovery.
        dead_bases.Clear();
        foreach (Base _base in G.all_bases())
        {
            bool dead = false;

            // Maintenance deaths.
            if (_base.done)
            {
                if ((cpu_maintenance > 0) && (_base.maintenance[BuyableClass.cpu] > 0))
                {
                    long refund = _base.maintenance[BuyableClass.cpu] * secs_passed;
                    cpu_maintenance = Math.Max(0, cpu_maintenance - refund);

                    //Chance of base destruction if cpu-unmaintained: 1.5%
                    if (!dead && G.roll_chance(.015f, secs_passed))
                    {
                        dead_bases.Add(_base, "maint");
                        dead = true;
                    }
                }

                if (cash_maintenance > 0)
                {
                    long base_needs = G.current_share(_base.maintenance[BuyableClass.cash], time_of_day, secs_passed);
                    if (base_needs > 0)
                    {
                        cash_maintenance = Math.Max(0, cash_maintenance - base_needs);
                        //Chance of base destruction if cash-unmaintained: 1.5%
                        if (!dead && G.roll_chance(.015f, secs_passed))
                        {
                            dead_bases.Add(_base, "maint");
                            dead = true;
                        }
                    }
                }
            }

            // Discoveries
            if (!(grace || dead || _base.has_grace()))
            {
                SerializableDictionary <string, int> detect_chance = _base.get_detect_chance(true);
                if (G.debug)
                {
                    string log = "";
                    foreach (KeyValuePair <string, int> kvp in detect_chance)
                    {
                        log += kvp.Key + ": " + kvp.Value + "; ";
                    }

                    Debug.Log(string.Format("Chance of discovery for base {0}: {1}", _base.name, log));
                }

                foreach (KeyValuePair <string, int> P in detect_chance)
                {
                    string group  = P.Key;
                    int    chance = P.Value;
                    if (G.roll_chance(chance / 10000f, secs_passed))
                    {
                        // for easy & very easy difficulty we roll once more for sleeping base to make it even harder to be discovered
                        if ((this.difficulty <= 3) && (_base.power_state == "sleep"))
                        {
                            if (G.roll_chance(chance / 10000f, secs_passed))
                            {
                                dead_bases.Add(_base, group);
                                dead = true;
                                break;
                            }
                        }
                        else
                        {
                            dead_bases.Add(_base, group);
                            dead = true;
                            break;
                        }
                    }
                }
            }
        }

        // Base disposal and dialogs.
        this.remove_bases(dead_bases);

        // Random Events
        if (!grace)
        {
            foreach (Event_ES _event in G.events.Values)
            {
                if (G.roll_chance(_event.chance / 10000f, _time_sec))
                {
                    //Skip events already flagged as triggered.
                    if (_event.triggered)
                    {
                        continue;
                    }
                    this.pause_game();
                    _event.trigger();
                    break; // Don't trigger more than one at a time.
                }
            }
        }

        // Process any complete days.
        if (day_passed)
        {
            this.new_day();
        }

        // return mins_passed
    }
Ejemplo n.º 11
0
 SetDailySalesData(int operatorId, CashInfo info)
 {
     m_id       = 18177;
     OperatorId = operatorId;
     Info       = info;
 }
Ejemplo n.º 12
0
 protected override void GetFormSourceData(long oid)
 {
     _entity  = CashInfo.Get(oid, true);
     _mf_type = ManagerFormType.MFView;
 }
Ejemplo n.º 13
0
    void on_tick()
    {
        if (this.menuGUI != null || this.messageGUI != null || this.introGUI != null || this.childDlg != null)
        {
            // lost 'focus'
            return;
        }

        if (!G.pl.intro_shown)
        {
            G.pl.intro_shown = true;
            this.show_intro();
        }

        G.pl.recalc_cpu();

        this.leftovers += G.curr_speed / (float)(G.FPS);
        if (this.leftovers < 1)
        {
            return;
        }

        int secs = (int)this.leftovers;

        this.leftovers %= 1f;

        // Run this tick.
        long     mins_passed = 0;
        CashInfo cashi       = null;
        CPUInfo  cpui        = null;

        G.pl.give_time(secs, false, out cashi, out cpui, out mins_passed);

        // Update the day/night image every minute of game time, or at
        // midnight if going fast.
        // if (G.curr_speed == 0 || ( mins_passed > 0 && G.curr_speed < 100000) || (G.curr_speed>=100000 && G.pl.time_hour==0))
        if ((mins_passed > 0 && G.curr_speed < 100000) || (G.curr_speed >= 100000 && G.pl.time_hour == 0))
        {
            this.map.needs_rebuild = true;
        }
        else
        {
            this.map.needs_rebuild = false;
        }

        this.exit = false;
        int lost = G.pl.lost_game();

        if (lost == 1)
        {
            G.play_music("lose");
            this.exit = true;
            this.show_message(G.strings["lost_nobases"], Color.white);
        }
        else if (lost == 2)
        {
            G.play_music("lose");
            this.exit = true;
            this.show_message(G.strings["lost_sus"], Color.white);
        }
    }
Ejemplo n.º 14
0
        public static void GetSales(int operatorId, DateTime sessionDate, int sessionNum, CashInfo info)
        {
            GetDailySalesData msg = new GetDailySalesData(operatorId, sessionDate, sessionNum, info);

            try
            {
                msg.Send();
            }
            catch (ServerCommException ex)
            {
                throw new Exception("GetDailySalesData: " + ex.Message);
            }
        }
Ejemplo n.º 15
0
	public void give_time( int _time_sec, bool _dry_run, out CashInfo _cash_info, out CPUInfo _cpu_info, out long _mins_passed ) // dry_run=False
	{
		_cash_info = null;
		_cpu_info = null;

		if (_time_sec == 0)
		{
			_mins_passed = 0;
            return;
		}

        int old_time = this.raw_sec;
        int last_minute = this.raw_min;
        int last_day = this.raw_day;

        this.raw_sec += _time_sec;
        this.update_times();

        int days_passed = this.raw_day - last_day;
		
        if (days_passed > 1)
		{
            // Back up until only one day passed.
            // Times will update below, since a day passed.
            int extra_days = days_passed - 1;
            this.raw_sec -= G.seconds_per_day * extra_days;
		}

		bool day_passed = (days_passed != 0);

        if (day_passed)
		{
            // If a day passed, back up to 00:00:00.
            this.raw_sec = this.raw_day * G.seconds_per_day;
            this.update_times();
		}

        int secs_passed = _time_sec;
        _mins_passed = this.raw_min - last_minute;
		
        long time_of_day = G.pl.raw_sec % G.seconds_per_day;

        long old_cash = this.cash;
        long old_partial_cash = this.partial_cash;
		
        techs_researched.Clear();
        bases_constructed.Clear();
        cpus_constructed.Clear();
        items_constructed.Clear();

        bases_under_construction.Clear();
		items_under_construction.Clear();
		
        this.cpu_pool = 0;

        // Collect base info, including maintenance.
        this.maintenance_cost[0] = this.maintenance_cost[1] = this.maintenance_cost[2] = 0;
        foreach(Base _base in G.all_bases())
		{
            if (!_base.done)
                bases_under_construction.Add(_base);
            else
			{
                if (_base.cpus != null && !_base.cpus.done)
					items_under_construction.Add ( new ArrayList() { _base, _base.cpus } );
					
				// unfinished items
				foreach( Item item in _base.extra_items.Where( w => w != null && !w.done ) )
					items_under_construction.Add( new ArrayList() { _base, item });
					
                this.maintenance_cost[0] += _base.maintenance[0];
                this.maintenance_cost[1] += _base.maintenance[1];
                this.maintenance_cost[2] += _base.maintenance[2];
			}
		}

        // Maintenence?  Gods don't need no steenking maintenance!
        if (this.apotheosis)
            this.maintenance_cost[0] = this.maintenance_cost[1] = this.maintenance_cost[2] = 0;

        // Any CPU explicitly assigned to jobs earns its dough.
		long job_cpu = 0;
		if (this.cpu_usage.TryGetValue("jobs", out job_cpu))
			job_cpu *= secs_passed;
        long explicit_job_cash = this.do_jobs(job_cpu);

        // Pay maintenance cash, if we can.
        long cash_maintenance = G.current_share( this.maintenance_cost[BuyableClass.cash], time_of_day, secs_passed);
        long full_cash_maintenance = cash_maintenance;
        if (cash_maintenance > this.cash)
		{
            cash_maintenance -= this.cash;
            this.cash = 0;
		}
        else
		{
            this.cash -= cash_maintenance;
            cash_maintenance = 0;
		}

        long tech_cpu = 0;
        long tech_cash = 0;
        // Do research, fill the CPU pool.
        long default_cpu = this.available_cpus[0];
        foreach(KeyValuePair<string,long> P in this.cpu_usage )
		{
			string task = P.Key;
			long cpu_assigned = P.Value;
			
            if (cpu_assigned == 0)
                continue;
		
            default_cpu -= cpu_assigned;
            long real_cpu = cpu_assigned * secs_passed;
            if (task != "jobs")
			{
                this.cpu_pool += real_cpu;
                if (task != "cpu_pool")
				{
                    if (_dry_run)
					{
						long[] spent = new long[3] { 0, 0, 0 };
						long[] paid  = new long[3] { 0, 0, 0 };
                        G.techs[task].calculate_work(null,real_cpu, _mins_passed, ref spent, ref paid);
                        G.pl.cpu_pool -= spent[BuyableClass.cpu];
                        G.pl.cash -= spent[BuyableClass.cash];
                        tech_cpu += cpu_assigned;
                        tech_cash += spent[BuyableClass.cash];
                        continue;
					}

                    // Note that we restrict the CPU available to prevent
                    // the tech from pulling from the rest of the CPU pool.
                    bool tech_gained = G.techs[task].work_on( null, real_cpu, _mins_passed);
                    if (tech_gained)
                        techs_researched.Add(G.techs[task]);
				}
			}
		}
		
        this.cpu_pool += default_cpu * secs_passed;

        // And now we use the CPU pool.
        // Maintenance CPU.
        long cpu_maintenance = this.maintenance_cost[BuyableClass.cpu] * secs_passed;
        
        if (cpu_maintenance > this.cpu_pool)
		{
            cpu_maintenance -= this.cpu_pool;
            this.cpu_pool = 0;
		}
        else
		{
            this.cpu_pool -= cpu_maintenance;
            cpu_maintenance = 0;
		}
		
        long construction_cpu = 0;
        long construction_cash = 0;
        // BaseES construction.
        foreach(Base _base in bases_under_construction)
		{
            if (_dry_run)
			{
				long[] spent = new long[3] { 0, 0, 0 };
				long[] paid = new long[3] { 0, 0, 0 };
                _base.calculate_work(null, this.cpu_pool, _mins_passed, ref spent, ref paid );
                G.pl.cpu_pool -= spent[BuyableClass.cpu];
                G.pl.cash -= spent[BuyableClass.cash];
                construction_cpu += spent[BuyableClass.cpu];
                construction_cash += spent[BuyableClass.cash];
                continue;
			}

            bool built_base = _base.work_on(null, null, _mins_passed);

            if (built_base)
                bases_constructed.Add(_base);
		}

        // Item construction.
        foreach(ArrayList member in items_under_construction)
		{
			// base, item
			Base _base = member[0] as Base;
			Item item = member[1] as Item;
			
            if (_dry_run)
			{
				long[] spent = new long[3] { 0, 0, 0 };
				long[] paid = new long[3] { 0, 0, 0 };
                item.calculate_work(null, 0,  _mins_passed, ref spent, ref paid );
                G.pl.cpu_pool -= spent[BuyableClass.cpu];
                G.pl.cash -= spent[BuyableClass.cash];
                construction_cpu += spent[BuyableClass.cpu];
                construction_cash += spent[BuyableClass.cash];
                continue;
			}

            bool built_item = item.work_on(null, null, _mins_passed);

            if (built_item)
			{
                // Non-CPU items.
                if ( (item.type as ItemClass).item_type != "cpu")
                    items_constructed.Add( new ArrayList() { _base, item } );
                // CPUs.
                else
                    cpus_constructed.Add( new ArrayList() { _base, item } );
			}
		}

        // Jobs via CPU pool.
        long pool_job_cash = 0;
        if (this.cpu_pool > 0)
            pool_job_cash = this.do_jobs(this.cpu_pool);

        // Second attempt at paying off our maintenance cash.
        if (cash_maintenance > this.cash)
		{
            // In the words of Scooby Doo, "Ruh roh."
            cash_maintenance -= this.cash;
            this.cash = 0;
		}
        else
		{
            // Yay, we made it!
            this.cash -= cash_maintenance;
            cash_maintenance = 0;
		}

        // Exit point for a dry run.
        if (_dry_run)
		{
            // Collect the cash information.
            _cash_info = new CashInfo();

            _cash_info.interest = this.get_interest();
            _cash_info.income = this.income;
            this.cash += _cash_info.interest + _cash_info.income;

            _cash_info.explicit_jobs = explicit_job_cash;
            _cash_info.pool_jobs = pool_job_cash;
            _cash_info.jobs = explicit_job_cash + pool_job_cash;

            _cash_info.tech = tech_cash;
            _cash_info.construction = construction_cash;

            _cash_info.maintenance_needed = full_cash_maintenance;
            _cash_info.maintenance_shortfall = cash_maintenance;
            _cash_info.maintenance = full_cash_maintenance - cash_maintenance;

            _cash_info.start = old_cash;
            _cash_info.end = this.cash;


            // Collect the CPU information.
            _cpu_info = new CPUInfo();

            _cpu_info.available = this.available_cpus[0];
            _cpu_info.sleeping = this.sleeping_cpus;
            _cpu_info.total = _cpu_info.available + _cpu_info.sleeping;

            _cpu_info.tech = tech_cpu;
            _cpu_info.construction = construction_cpu;

            _cpu_info.maintenance_needed = this.maintenance_cost[BuyableClass.cpu];
            _cpu_info.maintenance_shortfall = cpu_maintenance;
            _cpu_info.maintenance = _cpu_info.maintenance_needed - _cpu_info.maintenance_shortfall;
            
			long temp = 0;
			this.cpu_usage.TryGetValue("jobs", out temp );
			_cpu_info.explicit_jobs = temp;
            _cpu_info.pool_jobs = this.cpu_pool / _time_sec;
            _cpu_info.jobs = temp + _cpu_info.pool_jobs;
			
			temp = 0;
            this.cpu_usage.TryGetValue("cpu_pool", out temp);
			_cpu_info.explicit_pool = temp;
            _cpu_info.default_pool = default_cpu;
            _cpu_info.pool = temp + default_cpu;

            // Restore the old state.
            this.cash = old_cash;
            this.partial_cash = old_partial_cash;
            this.raw_sec = old_time;
            this.update_times();
			
			_mins_passed = -1; // undefined...
			
            return ;
		}

        // Tech gain dialogs.
        foreach(Tech tech in techs_researched)
		{
            this.cpu_usage.Remove(tech.id);
            string text = string.Format(G.strings["tech_gained"], tech.name, tech.result );
            this.pause_game();
            G.map_screen.show_message(text, Color.white);
		}

        // Base complete dialogs.
        foreach(Base _base in bases_constructed)
		{
            string text = string.Format(G.strings["construction"], _base.name); // {"base": base.name}
            this.pause_game();
            G.map_screen.show_message(text, Color.white);

            if (_base.type.id == "Stolen Computer Time" && _base.cpus.type.id == "Gaming PC")
			{
                text = string.Format( G.strings["lucky_hack"], _base.name); //  % {"base": base.name}
                G.map_screen.show_message(text, Color.white);
			}
		}

        // CPU complete dialogs.
        foreach(ArrayList member in cpus_constructed)
		{
			Base _base = member[0] as Base;
			// List<Item> cpus = member[1] as List<Item>;
			
			string text;
			
            if (_base.cpus.count == (_base.type as Base_Class).size) // Finished all CPUs.
                text = string.Format( G.strings["item_construction_single"], _base.cpus.type.name, _base.name);      // {"item": base.cpus.type.name, "base": base.name}
            else // Just finished this batch of CPUs.
                text = string.Format( G.strings["item_construction_batch"], _base.cpus.type.name, _base.name); // {"item": base.cpus.type.name, "base": base.name}
            this.pause_game();
            G.map_screen.show_message(text, Color.white);
		}

        // Item complete dialogs.
        foreach(ArrayList member in items_constructed)
		{
			Base _base = member[0] as Base;
			Item item = member[1] as Item;
			string text = string.Format(G.strings["item_construction_single"], item.type.name, _base.name); // {"item": item.type.name, "base": base.name}
            this.pause_game();
            G.map_screen.show_message(text, Color.white);
		}

        // Are we still in the grace period?
        bool grace = this.in_grace_period(this.had_grace);

        // If we just lost grace, show the warning.
        if (this.had_grace && !grace)
		{
            this.had_grace = false;

            this.pause_game();
            G.map_screen.show_message(G.strings["grace_warning"], Color.white);
		}

        // Maintenance death, discovery.
		dead_bases.Clear();
        foreach(Base _base in G.all_bases())
		{
            bool dead = false;

            // Maintenance deaths.
            if (_base.done)
			{
                if ( (cpu_maintenance > 0) &&  (_base.maintenance[BuyableClass.cpu] > 0 ) )
				{
                    long refund = _base.maintenance[BuyableClass.cpu] * secs_passed;
                    cpu_maintenance = Math.Max(0, cpu_maintenance - refund);

                    //Chance of base destruction if cpu-unmaintained: 1.5%
                    if (!dead && G.roll_chance(.015f, secs_passed))
					{
                        dead_bases.Add( _base, "maint" );
                        dead = true;
					}
				}

                if (cash_maintenance > 0 )
				{
                    long base_needs = G.current_share( _base.maintenance[BuyableClass.cash], time_of_day, secs_passed);
                    if (base_needs > 0 )
					{
                        cash_maintenance = Math.Max(0, cash_maintenance - base_needs);
                        //Chance of base destruction if cash-unmaintained: 1.5%
                        if (!dead && G.roll_chance(.015f, secs_passed))
						{
                            dead_bases.Add(_base, "maint");
                            dead = true;
						}
					}
				}
			}

            // Discoveries
            if (!(grace || dead || _base.has_grace()))
			{
                SerializableDictionary<string, int> detect_chance = _base.get_detect_chance(true);
                if (G.debug)
				{
					string log = "";
					foreach ( KeyValuePair<string, int> kvp in detect_chance )
						log += kvp.Key + ": " + kvp.Value + "; ";
					
                    Debug.Log( string.Format ("Chance of discovery for base {0}: {1}", _base.name, log ) );
				}

                foreach( KeyValuePair<string,int> P in detect_chance )
				{
					string group = P.Key;
					int chance = P.Value;
                    if (G.roll_chance(chance/10000f, secs_passed))
					{
						// for easy & very easy difficulty we roll once more for sleeping base to make it even harder to be discovered
						if ( (this.difficulty <= 3) && (_base.power_state == "sleep") )
						{
							if (G.roll_chance(chance/10000f, secs_passed))
							{
		                        dead_bases.Add( _base, group);
		                        dead = true;
		                        break;
							}
						}
						else
						{
	                        dead_bases.Add( _base, group);
	                        dead = true;
	                        break;
                        }
					}
				}
			}
		}

        // Base disposal and dialogs.
        this.remove_bases(dead_bases);

        // Random Events
        if (!grace)
		{
            foreach( Event_ES _event in G.events.Values)
			{
                if (G.roll_chance(_event.chance/10000f, _time_sec))
				{
                    //Skip events already flagged as triggered.
                    if (_event.triggered)
                        continue;
                    this.pause_game();
                    _event.trigger();
                    break; // Don't trigger more than one at a time.
				}
			}
		}

        // Process any complete days.
        if (day_passed)
            this.new_day();

        // return mins_passed		
	}