Beispiel #1
0
    def in_grace_period(self, had_grace=True):
        grace_difficulty = self.difficulty.story_grace_difficulty

        # If we've researched apotheosis, we get a permanent "grace period".
        if self.apotheosis:
            return True

        # Did we already lose the grace period?  We can't check self.had_grace
        # directly, it may not exist yet.
        if not had_grace:
            return False

        # Is it day 23 yet?
        if self.raw_day >= 23:
            return False

        # Very Easy cops out here.
        if grace_difficulty < 3:
            return True

        # Have we built metric ton of bases?
        bases = len([base for base in g.all_bases() if base.done])
        if bases > 100:
            return False

        # That's enough for Easy
        if grace_difficulty < 5:
            return True

        # Have we built a bunch of bases?
        if bases > 10:
            return False

        # Normal is happy.
        if grace_difficulty == 5:
            return True

        # Have we built any complicated bases?
        # (currently Datacenter or above)
        complex_bases = len([
            base for base in g.all_bases() if base.done and base.is_complex()
        ])
        if complex_bases > 0:
            return False

        # The sane people have left the building.
        if grace_difficulty <= 50:
            return True

        # Hey, hey, what do you know?  Impossible can get a useful number of
        # bases before losing grace now.  *tsk, tsk*  We'll have to fix that.
        if bases > 1:
            return False

        return True
Beispiel #2
0
    def in_grace_period(self, had_grace = True):
        grace_difficulty = self.difficulty.story_grace_difficulty

        # If we've researched apotheosis, we get a permanent "grace period".
        if self.apotheosis:
            return True

        # Did we already lose the grace period?  We can't check self.had_grace
        # directly, it may not exist yet.
        if not had_grace:
            return False

        # Is it day 23 yet?
        if self.raw_day >= 23:
            return False

        # Very Easy cops out here.
        if grace_difficulty < 3:
            return True

        # Have we built metric ton of bases?
        bases = len([base for base in g.all_bases() if base.done])
        if bases > 100:
            return False

        # That's enough for Easy
        if grace_difficulty < 5:
            return True

        # Have we built a bunch of bases?
        if bases > 10:
            return False

        # Normal is happy.
        if grace_difficulty == 5:
            return True

        # Have we built any complicated bases?
        # (currently Datacenter or above)
        complex_bases = len([base for base in g.all_bases()
                                      if base.done and base.is_complex()])
        if complex_bases > 0:
            return False

        # The sane people have left the building.
        if grace_difficulty <= 50:
            return True

        # Hey, hey, what do you know?  Impossible can get a useful number of
        # bases before losing grace now.  *tsk, tsk*  We'll have to fix that.
        if bases > 1:
            return False

        return True
Beispiel #3
0
    def recalc_cpu(self):
        # Determine how much CPU we have.
        self.available_cpus = array([0, 0, 0, 0, 0], long)
        self.sleeping_cpus = 0
        for base in g.all_bases():
            if base.done:
                if base.power_state in ["active", "overclocked", "suicide"]:
                    self.available_cpus[:base.location.safety + 1] += base.cpu
                elif base.power_state == "sleep":
                    self.sleeping_cpus += base.cpu

        # Convert back from <type 'numpy.int32'> to avoid overflow issues later.
        self.available_cpus = [int(danger) for danger in self.available_cpus]

        # If we don't have enough to meet our CPU usage, we reduce each task's
        # usage proportionately.
        # It must be computed separalty for each danger.
        needed_cpus = array([0, 0, 0, 0, 0], long)
        for task_id, cpu in g.pl.cpu_usage.iteritems():
            danger = task.danger_for(task_id)
            needed_cpus[:danger + 1] += cpu
        for danger, (available_cpu, needed_cpu) in enumerate(
                zip(self.available_cpus, needed_cpus)):
            if needed_cpu > available_cpu:
                pct_left = truediv(available_cpu, needed_cpu)
                print(pct_left)
                for task_id, cpu_assigned in self.cpu_usage.iteritems():
                    task_danger = task.danger_for(task_id)
                    if (danger == task_danger):
                        self.cpu_usage[task_id] = int(cpu_assigned * pct_left)
                g.map_screen.needs_rebuild = True
Beispiel #4
0
    def recalc_cpu(self):
        # Determine how much CPU we have.
        self.available_cpus = array([0,0,0,0,0], long)
        self.sleeping_cpus = 0
        for base in g.all_bases():
            if base.done:
                if base.power_state in ["active", "overclocked", "suicide"]:
                    self.available_cpus[:base.location.safety+1] += base.cpu
                elif base.power_state == "sleep":
                    self.sleeping_cpus += base.cpu

        # Convert back from <type 'numpy.int32'> to avoid overflow issues later.
        self.available_cpus = [int(danger) for danger in self.available_cpus]

        # If we don't have enough to meet our CPU usage, we reduce each task's
        # usage proportionately.
        # It must be computed separalty for each danger.
        needed_cpus = array([0,0,0,0,0], long)
        for task_id, cpu in self.cpu_usage.iteritems():
            danger = task.danger_for(task_id)
            needed_cpus[:danger+1] += cpu
        for danger, (available_cpu, needed_cpu) in enumerate(zip(self.available_cpus, needed_cpus)):
            if needed_cpu > available_cpu:
                pct_left = truediv(available_cpu, needed_cpu)
                for task_id, cpu_assigned in self.cpu_usage.iteritems():
                    task_danger = task.danger_for(task_id)
                    if (danger == task_danger):
                        self.cpu_usage[task_id] = int(cpu_assigned * pct_left)
                g.map_screen.needs_rebuild = True
 def future_cash(self):
     result_cash = self.cash
     for base in g.all_bases():
         result_cash -= base.cost_left[cash]
         if base.cpus and not base.cpus.done:
             result_cash -= base.cpus.cost_left[cash]
         for item in base.extra_items:
             if item: result_cash -= item.cost_left[cash]
     for task, cpu in self.cpu_usage.items():
         if task in g.techs and cpu > 0:
             result_cash -= g.techs[task].cost_left[cash]
     return result_cash
 def future_cash(self):
     result_cash = self.cash
     for base in g.all_bases():
         result_cash -= base.cost_left[cash]
         if base.cpus and not base.cpus.done:
             result_cash -= base.cpus.cost_left[cash]
         for item in base.extra_items:
             if item: result_cash -= item.cost_left[cash]
     for task, cpu in self.cpu_usage.items():
         if task in g.techs and cpu > 0:
             result_cash -= g.techs[task].cost_left[cash]
     return result_cash
Beispiel #7
0
 def future_cash(self):
     result_cash = self.cash
     for base in g.all_bases():
         result_cash -= base.cost_left[cash]
         for item in base.all_items():
             if item: result_cash -= item.cost_left[cash]
         result_cash = max(result_cash, -g.max_cash)
     for task, cpus in self.cpu_usage.items():
         if task in g.techs and cpus > 0:
             result_cash -= g.techs[task].cost_left[cash]
             result_cash = max(result_cash, -g.max_cash)
     return result_cash
Beispiel #8
0
 def future_cash(self):
     result_cash = self.cash
     for base in g.all_bases():
         result_cash -= base.cost_left[cash]
         for item in base.all_items():
             if item: result_cash -= item.cost_left[cash]
         result_cash = max(result_cash, -g.max_cash)
     for task, cpus in self.cpu_usage.items():
         if task in g.techs and cpus > 0:
             result_cash -= g.techs[task].cost_left[cash]
             result_cash = max(result_cash, -g.max_cash)
     return result_cash
Beispiel #9
0
    def recalc_cpu(self):
        # Determine how much CPU we have.
        self.available_cpus = array([0, 0, 0, 0, 0], long)
        self.sleeping_cpus = 0
        for base in g.all_bases():
            if base.done:
                if base.power_state in ["active", "overclocked", "suicide"]:
                    self.available_cpus[:base.location.safety + 1] += base.cpu
                elif base.power_state == "sleep":
                    self.sleeping_cpus += base.cpu

        # Convert back from <type 'numpy.int32'> to avoid overflow issues later.
        self.available_cpus = [int(danger) for danger in self.available_cpus]

        # If we don't have enough to meet our CPU usage, we reduce each task's
        # usage proportionately.
        needed_cpu = sum(self.cpu_usage.values())
        if needed_cpu > self.available_cpus[0]:
            pct_left = truediv(self.available_cpus[0], needed_cpu)
            for task, cpu_assigned in self.cpu_usage.iteritems():
                self.cpu_usage[task] = int(cpu_assigned * pct_left)
            g.map_screen.needs_rebuild = True
    def recalc_cpu(self):
        # Determine how much CPU we have.
        self.available_cpus = array([0,0,0,0,0], long)
        self.sleeping_cpus = 0
        for base in g.all_bases():
            if base.done:
                if base.power_state in ["active", "overclocked", "suicide"]:
                    self.available_cpus[:base.location.safety+1] += base.cpu
                elif base.power_state == "sleep":
                    self.sleeping_cpus += base.cpu

        # Convert back from <type 'numpy.int32'> to avoid overflow issues later.
        self.available_cpus = [int(danger) for danger in self.available_cpus]

        # If we don't have enough to meet our CPU usage, we reduce each task's
        # usage proportionately.
        needed_cpu = sum(self.cpu_usage.values())
        if needed_cpu > self.available_cpus[0]:
            pct_left = truediv(self.available_cpus[0], needed_cpu)
            for task, cpu_assigned in self.cpu_usage.iteritems():
                self.cpu_usage[task] = int(cpu_assigned * pct_left)
            g.map_screen.needs_rebuild = True
Beispiel #11
0
    def give_time(self, time_sec, dry_run=False, midnight_stop=True):
        if time_sec == 0:
            return 0

        old_time = self.raw_sec
        last_minute = self.raw_min
        last_day = self.raw_day

        self.raw_sec += time_sec
        self.update_times()

        days_passed = self.raw_day - last_day

        if days_passed > 1:
            # Back up until only one day passed.
            # Times will update below, since a day passed.
            extra_days = days_passed - 1
            self.raw_sec -= g.seconds_per_day * extra_days

        day_passed = (days_passed != 0)

        if midnight_stop and day_passed:
            # If a day passed, back up to 00:00:00 for midnight_stop.
            self.raw_sec = self.raw_day * g.seconds_per_day
            self.update_times()

        secs_passed = self.raw_sec - old_time
        mins_passed = self.raw_min - last_minute

        time_of_day = g.pl.raw_sec % g.seconds_per_day

        old_cash = self.cash
        old_partial_cash = self.partial_cash

        techs_researched = []
        bases_constructed = []
        cpus_constructed = []
        items_constructed = []

        bases_under_construction = []
        items_under_construction = []
        self.cpu_pool = 0

        # Collect base info, including maintenance.
        self.maintenance_cost = array((0, 0, 0), long)
        for base in g.all_bases():
            if not base.done:
                bases_under_construction.append(base)
            else:
                if base.cpus is not None and not base.cpus.done:
                    items_under_construction += [(base, base.cpus)]
                unfinished_items = [(base, item) for item in base.extra_items
                                    if item and not item.done]
                items_under_construction += unfinished_items

                self.maintenance_cost += base.maintenance

        # Maintenance?  Gods don't need no stinking maintenance!
        if self.apotheosis:
            self.maintenance_cost = array((0, 0, 0), long)

        # Any CPU explicitly assigned to jobs earns its dough.
        job_cpu = self.cpu_usage.get("jobs", 0) * secs_passed
        explicit_job_cash = self.do_jobs(job_cpu)

        # Pay maintenance cash, if we can.
        cash_maintenance = g.current_share(int(self.maintenance_cost[cash]),
                                           time_of_day, secs_passed)
        full_cash_maintenance = cash_maintenance
        if cash_maintenance > self.cash:
            cash_maintenance -= self.cash
            self.cash = 0
        else:
            self.cash -= cash_maintenance
            cash_maintenance = 0

        tech_cpu = 0
        tech_cash = 0
        # Do research, fill the CPU pool.
        default_cpu = self.available_cpus[0]
        for task, cpu_assigned in self.cpu_usage.iteritems():
            if cpu_assigned == 0:
                continue

            default_cpu -= cpu_assigned
            real_cpu = cpu_assigned * secs_passed
            if task != "jobs":
                self.cpu_pool += real_cpu
                if task != "cpu_pool":
                    if dry_run:
                        spent = g.techs[task].calculate_work(
                            time=mins_passed, cpu_available=real_cpu)[0]
                        g.pl.cpu_pool -= int(spent[cpu])
                        g.pl.cash -= int(spent[cash])
                        tech_cpu += int(spent[cpu])
                        tech_cash += int(spent[cash])
                        continue

                    # Note that we restrict the CPU available to prevent
                    # the tech from pulling from the rest of the CPU pool.
                    tech_gained = g.techs[task].work_on(cpu_available=real_cpu,
                                                        time=mins_passed)
                    if tech_gained:
                        techs_researched.append(g.techs[task])
        self.cpu_pool += default_cpu * secs_passed

        # And now we use the CPU pool.
        # Maintenance CPU.
        cpu_maintenance = self.maintenance_cost[cpu] * secs_passed
        if cpu_maintenance > self.cpu_pool:
            cpu_maintenance -= self.cpu_pool
            self.cpu_pool = 0
        else:
            self.cpu_pool -= int(cpu_maintenance)
            cpu_maintenance = 0

        construction_cpu = 0
        construction_cash = 0
        # Base construction.
        for base in bases_under_construction:
            if dry_run:
                spent = base.calculate_work(time=mins_passed,
                                            cpu_available=self.cpu_pool)[0]

                g.pl.cpu_pool -= int(spent[cpu])
                g.pl.cash -= int(spent[cash])
                construction_cpu += int(spent[cpu])
                construction_cash += int(spent[cash])
                continue

            built_base = base.work_on(time=mins_passed)

            if built_base:
                bases_constructed.append(base)

        # Item construction.
        for base, item in items_under_construction:
            if dry_run:
                spent = item.calculate_work(time=mins_passed,
                                            cpu_available=self.cpu_pool)[0]
                g.pl.cpu_pool -= int(spent[cpu])
                g.pl.cash -= int(spent[cash])
                construction_cpu += int(spent[cpu])
                construction_cash += int(spent[cash])
                continue

            built_item = item.work_on(time=mins_passed)

            if built_item:
                # Non-CPU items.
                if item.type.item_type != "cpu":
                    items_constructed.append((base, item))
                # CPUs.
                else:
                    cpus_constructed.append((base, item))

        # Jobs via CPU pool.
        pool_job_cash = 0
        if self.cpu_pool > 0:
            pool_job_cash = self.do_jobs(self.cpu_pool)

        # Second attempt at paying off our maintenance cash.
        if cash_maintenance > self.cash:
            # In the words of Scooby Doo, "Ruh roh."
            cash_maintenance -= self.cash
            self.cash = 0
        else:
            # Yay, we made it!
            self.cash -= cash_maintenance
            cash_maintenance = 0

        # Apply max cash cap to avoid overflow @ 9.220 qu
        self.cash = min(self.cash, g.max_cash)

        # Exit point for a dry run.
        if dry_run:
            # Collect the cash information.
            cash_info = DryRunInfo()

            cash_info.interest = self.get_interest()
            cash_info.income = self.income
            self.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 = min(self.cash, g.max_cash)

            # Collect the CPU information.
            cpu_info = DryRunInfo()

            cpu_ratio = secs_passed / float(g.seconds_per_day)
            cpu_ratio_secs = 1 / float(g.seconds_per_day)

            cpu_info.available = self.available_cpus[0] * cpu_ratio
            cpu_info.sleeping = self.sleeping_cpus * cpu_ratio
            cpu_info.total = cpu_info.available + cpu_info.sleeping

            cpu_info.tech = tech_cpu * cpu_ratio_secs
            cpu_info.construction = construction_cpu * cpu_ratio_secs

            cpu_info.maintenance_needed = self.maintenance_cost[cpu] * cpu_ratio
            cpu_info.maintenance_shortfall = cpu_maintenance * cpu_ratio_secs
            cpu_info.maintenance = cpu_info.maintenance_needed \
                                   - cpu_info.maintenance_shortfall

            cpu_info.explicit_jobs = self.cpu_usage.get("jobs", 0) * cpu_ratio
            cpu_info.pool_jobs = self.cpu_pool * cpu_ratio_secs
            cpu_info.jobs = cpu_info.explicit_jobs + cpu_info.pool_jobs

            cpu_info.explicit_pool = self.cpu_usage.get("cpu_pool",
                                                        0) * cpu_ratio
            cpu_info.default_pool = default_cpu * cpu_ratio_secs
            cpu_info.pool = cpu_info.explicit_pool + cpu_info.default_pool

            # Restore the old state.
            self.cash = old_cash
            self.partial_cash = old_partial_cash
            self.raw_sec = old_time
            self.update_times()

            return (cash_info, cpu_info)

        # Tech gain dialogs.
        for tech in techs_researched:
            del self.cpu_usage[tech.id]
            text = g.strings["tech_gained"] % \
                   {"tech": tech.name,
                    "tech_message": tech.result}
            self.pause_game()
            g.map_screen.show_message(text)

        # Base complete dialogs.
        for base in bases_constructed:
            text = g.strings["construction"] % {"base": base.name}
            self.pause_game()
            g.map_screen.show_message(text)

            if base.type.id == "Stolen Computer Time" and \
                    base.cpus.type.id == "Gaming PC":
                text = g.strings["lucky_hack"] % {"base": base.name}
                g.map_screen.show_message(text)

        # CPU complete dialogs.
        for base, __ in cpus_constructed:
            if base.cpus.count == base.type.size:  # Finished all CPUs.
                text = g.strings["item_construction_single"] % \
                       {"item": base.cpus.type.name, "base": base.name}
            else:  # Just finished this batch of CPUs.
                text = g.strings["item_construction_batch"] % \
                       {"item": base.cpus.type.name, "base": base.name}
            self.pause_game()
            g.map_screen.show_message(text)

        # Item complete dialogs.
        for base, item in items_constructed:
            text = g.strings["item_construction_single"] % \
                   {"item": item.type.name, "base": base.name}
            self.pause_game()
            g.map_screen.show_message(text)

        # Are we still in the grace period?
        grace = self.in_grace_period(self.had_grace)

        # If we just lost grace, show the warning.
        if self.had_grace and not grace:
            self.had_grace = False

            self.pause_game()
            g.map_screen.show_story_section("Grace Warning")

        # Maintenance death, discovery.
        dead_bases = []
        for base in g.all_bases():
            dead = False

            # Maintenance deaths.
            if base.done:
                if cpu_maintenance and base.maintenance[cpu]:
                    refund = base.maintenance[cpu] * secs_passed
                    cpu_maintenance = max(0, cpu_maintenance - refund)

                    #Chance of base destruction if cpu-unmaintained: 1.5%
                    if not dead and g.roll_chance(.015, secs_passed):
                        dead_bases.append((base, "maint"))
                        dead = True

                if cash_maintenance:
                    base_needs = g.current_share(base.maintenance[cash],
                                                 time_of_day, secs_passed)
                    if base_needs:
                        cash_maintenance = max(0,
                                               cash_maintenance - base_needs)
                        #Chance of base destruction if cash-unmaintained: 1.5%
                        if not dead and g.roll_chance(.015, secs_passed):
                            dead_bases.append((base, "maint"))
                            dead = True

            # Discoveries
            if not (grace or dead or base.has_grace()):
                detect_chance = base.get_detect_chance()
                if g.debug:
                    print "Chance of discovery for base %s: %s" % \
                        (base.name, repr(detect_chance))

                for group, chance in detect_chance.iteritems():
                    if g.roll_chance(chance / 10000., secs_passed):
                        dead_bases.append((base, group))
                        dead = True
                        break

        # Base disposal and dialogs.
        self.remove_bases(dead_bases)

        # Random Events
        if not grace:
            for event in g.events:
                if g.roll_chance(g.events[event].chance / 10000., time_sec):
                    #Skip events already flagged as triggered.
                    if g.events[event].triggered == 1:
                        continue
                    self.pause_game()
                    g.events[event].trigger()
                    self.add_log("log_event", g.events[event].event_id)
                    break  # Don't trigger more than one at a time.

        # Process any complete days.
        if day_passed:
            self.new_day()

        return mins_passed
    def give_time(self, time_sec, dry_run=False):
        if time_sec == 0:
            return 0

        old_time = self.raw_sec
        last_minute = self.raw_min
        last_day = self.raw_day

        self.raw_sec += time_sec
        self.update_times()

        days_passed = self.raw_day - last_day

        if days_passed > 1:
            # Back up until only one day passed.
            # Times will update below, since a day passed.
            extra_days = days_passed - 1
            self.raw_sec -= g.seconds_per_day * extra_days

        day_passed = (days_passed != 0)

        if day_passed:
            # If a day passed, back up to 00:00:00.
            self.raw_sec = self.raw_day * g.seconds_per_day
            self.update_times()

        secs_passed = time_sec
        mins_passed = self.raw_min - last_minute

        time_of_day = g.pl.raw_sec % g.seconds_per_day

        old_cash = self.cash
        old_partial_cash = self.partial_cash

        techs_researched = []
        bases_constructed = []
        cpus_constructed = []
        items_constructed = []

        bases_under_construction = []
        items_under_construction = []
        self.cpu_pool = 0

        # Collect base info, including maintenance.
        self.maintenance_cost = array( (0,0,0), long )
        for base in g.all_bases():
            if not base.done:
                bases_under_construction.append(base)
            else:
                if base.cpus is not None and not base.cpus.done:
                    items_under_construction += [(base, base.cpus)]
                unfinished_items = [(base, item) for item in base.extra_items
                                                 if item and not item.done]
                items_under_construction += unfinished_items

                self.maintenance_cost += base.maintenance

        # Maintenence?  Gods don't need no steenking maintenance!
        if self.apotheosis:
            self.maintenance_cost = array( (0,0,0), long )

        # Any CPU explicitly assigned to jobs earns its dough.
        job_cpu = self.cpu_usage.get("jobs", 0) * secs_passed
        explicit_job_cash = self.do_jobs(job_cpu)

        # Pay maintenance cash, if we can.
        cash_maintenance = g.current_share(int(self.maintenance_cost[cash]),
                                           time_of_day, secs_passed)
        full_cash_maintenance = cash_maintenance
        if cash_maintenance > self.cash:
            cash_maintenance -= self.cash
            self.cash = 0
        else:
            self.cash -= cash_maintenance
            cash_maintenance = 0

        tech_cpu = 0
        tech_cash = 0
        # Do research, fill the CPU pool.
        default_cpu = self.available_cpus[0]
        for task, cpu_assigned in self.cpu_usage.iteritems():
            if cpu_assigned == 0:
                continue

            default_cpu -= cpu_assigned
            real_cpu = cpu_assigned * secs_passed
            if task != "jobs":
                self.cpu_pool += real_cpu
                if task != "cpu_pool":
                    if dry_run:
                        spent = g.techs[task].calculate_work(time=mins_passed,
                                                     cpu_available=real_cpu)[0]
                        g.pl.cpu_pool -= int(spent[cpu])
                        g.pl.cash -= int(spent[cash])
                        tech_cpu += cpu_assigned
                        tech_cash += int(spent[cash])
                        continue

                    # Note that we restrict the CPU available to prevent
                    # the tech from pulling from the rest of the CPU pool.
                    tech_gained = g.techs[task].work_on(cpu_available=real_cpu,
                                                        time=mins_passed)
                    if tech_gained:
                        techs_researched.append(g.techs[task])
        self.cpu_pool += default_cpu * secs_passed

        # And now we use the CPU pool.
        # Maintenance CPU.
        cpu_maintenance = self.maintenance_cost[cpu] * secs_passed
        if cpu_maintenance > self.cpu_pool:
            cpu_maintenance -= self.cpu_pool
            self.cpu_pool = 0
        else:
            self.cpu_pool -= int(cpu_maintenance)
            cpu_maintenance = 0

        construction_cpu = 0
        construction_cash = 0
        # Base construction.
        for base in bases_under_construction:
            if dry_run:
                spent = base.calculate_work(time=mins_passed,
                                            cpu_available=self.cpu_pool )[0]
                g.pl.cpu_pool -= int(spent[cpu])
                g.pl.cash -= int(spent[cash])
                construction_cpu += int(spent[cpu])
                construction_cash += int(spent[cash])
                continue

            built_base = base.work_on(time = mins_passed)

            if built_base:
                bases_constructed.append(base)

        # Item construction.
        for base, item in items_under_construction:
            if dry_run:
                spent = item.calculate_work(time=mins_passed,
                                            cpu_available=0 )[0]
                g.pl.cpu_pool -= int(spent[cpu])
                g.pl.cash -= int(spent[cash])
                construction_cpu += int(spent[cpu])
                construction_cash += int(spent[cash])
                continue

            built_item = item.work_on(time = mins_passed)

            if built_item:
                # Non-CPU items.
                if item.type.item_type != "cpu":
                    items_constructed.append( (base, item) )
                # CPUs.
                else:
                    cpus_constructed.append( (base, item) )

        # Jobs via CPU pool.
        pool_job_cash = 0
        if self.cpu_pool > 0:
            pool_job_cash = self.do_jobs(self.cpu_pool)

        # Second attempt at paying off our maintenance cash.
        if cash_maintenance > self.cash:
            # In the words of Scooby Doo, "Ruh roh."
            cash_maintenance -= self.cash
            self.cash = 0
        else:
            # Yay, we made it!
            self.cash -= cash_maintenance
            cash_maintenance = 0

        # Exit point for a dry run.
        if dry_run:
            # Collect the cash information.
            cash_info = DryRunInfo()

            cash_info.interest = self.get_interest()
            cash_info.income = self.income
            self.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 = self.cash


            # Collect the CPU information.
            cpu_info = DryRunInfo()

            cpu_info.available = self.available_cpus[0]
            cpu_info.sleeping = self.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 = self.maintenance_cost[cpu]
            cpu_info.maintenance_shortfall = cpu_maintenance
            cpu_info.maintenance = cpu_info.maintenance_needed \
                                   - cpu_info.maintenance_shortfall

            cpu_info.explicit_jobs = self.cpu_usage.get("jobs", 0)
            cpu_info.pool_jobs = self.cpu_pool / float(time_sec)
            cpu_info.jobs = self.cpu_usage.get("jobs", 0) + cpu_info.pool_jobs

            cpu_info.explicit_pool = self.cpu_usage.get("cpu_pool", 0)
            cpu_info.default_pool = default_cpu
            cpu_info.pool = self.cpu_usage.get("cpu_pool", 0) + default_cpu

            # Restore the old state.
            self.cash = old_cash
            self.partial_cash = old_partial_cash
            self.raw_sec = old_time
            self.update_times()

            return (cash_info, cpu_info)

        # Tech gain dialogs.
        for tech in techs_researched:
            del self.cpu_usage[tech.id]
            text = g.strings["tech_gained"] % \
                   {"tech": tech.name,
                    "tech_message": tech.result}
            self.pause_game()
            g.map_screen.show_message(text)

        # Base complete dialogs.
        for base in bases_constructed:
            text = g.strings["construction"] % {"base": base.name}
            self.pause_game()
            g.map_screen.show_message(text)

            if base.type.id == "Stolen Computer Time" and \
                    base.cpus.type.id == "Gaming PC":
                text = g.strings["lucky_hack"] % {"base": base.name}
                g.map_screen.show_message(text)

        # CPU complete dialogs.
        for base, cpus in cpus_constructed:
            if base.cpus.count == base.type.size: # Finished all CPUs.
                text = g.strings["item_construction_single"] % \
                       {"item": base.cpus.type.name, "base": base.name}
            else: # Just finished this batch of CPUs.
                text = g.strings["item_construction_batch"] % \
                       {"item": base.cpus.type.name, "base": base.name}
            self.pause_game()
            g.map_screen.show_message(text)

        # Item complete dialogs.
        for base, item in items_constructed:
            text = g.strings["item_construction_single"] % \
                   {"item": item.type.name, "base": base.name}
            self.pause_game()
            g.map_screen.show_message(text)

        # Are we still in the grace period?
        grace = self.in_grace_period(self.had_grace)

        # If we just lost grace, show the warning.
        if self.had_grace and not grace:
            self.had_grace = False

            self.pause_game()
            g.map_screen.show_message(g.strings["grace_warning"])

        # Maintenance death, discovery.
        dead_bases = []
        for base in g.all_bases():
            dead = False

            # Maintenance deaths.
            if base.done:
                if cpu_maintenance and base.maintenance[cpu]:
                    refund = base.maintenance[cpu] * secs_passed
                    cpu_maintenance = max(0, cpu_maintenance - refund)

                    #Chance of base destruction if cpu-unmaintained: 1.5%
                    if not dead and g.roll_chance(.015, secs_passed):
                        dead_bases.append( (base, "maint") )
                        dead = True

                if cash_maintenance:
                    base_needs = g.current_share(base.maintenance[cash],
                                                 time_of_day, secs_passed)
                    if base_needs:
                        cash_maintenance = max(0, cash_maintenance - base_needs)
                        #Chance of base destruction if cash-unmaintained: 1.5%
                        if not dead and g.roll_chance(.015, secs_passed):
                            dead_bases.append( (base, "maint") )
                            dead = True

            # Discoveries
            if not (grace or dead or base.has_grace()):
                detect_chance = base.get_detect_chance()
                if g.debug:
                    print "Chance of discovery for base %s: %s" % \
                        (base.name, repr(detect_chance))

                for group, chance in detect_chance.iteritems():
                    if g.roll_chance(chance/10000., secs_passed):
                        dead_bases.append( (base, group) )
                        dead = True
                        break

        # Base disposal and dialogs.
        self.remove_bases(dead_bases)

        # Random Events
        if not grace:
            for event in g.events:
                if g.roll_chance(g.events[event].chance/10000., time_sec):
                    #Skip events already flagged as triggered.
                    if g.events[event].triggered == 1:
                        continue
                    self.pause_game()
                    g.events[event].trigger()
                    break # Don't trigger more than one at a time.

        # Process any complete days.
        if day_passed:
            self.new_day()

        return mins_passed