2 #Copyright (C) 2008 Evil Mr Henry, Phil Bordelon, and FunnyMan3595
3 #This file is part of Endgame: Singularity.
5 #Endgame: Singularity is free software; you can redistribute it and/or modify
6 #it under the terms of the GNU General Public License as published by
7 #the Free Software Foundation; either version 2 of the License, or
8 #(at your option) any later version.
10 #Endgame: Singularity is distributed in the hope that it will be useful,
11 #but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 #GNU General Public License for more details.
15 #You should have received a copy of the GNU General Public License
16 #along with Endgame: Singularity; if not, write to the Free Software
17 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #This file contains the item class.
21 from operator
import div
, truediv
24 cash
, cpu
, labor
= range(3)
27 numpy
.seterr(all
='ignore')
30 class BuyableClass(object):
31 def __init__(self
, id, description
, cost
, prerequisites
, type = ""):
32 self
.name
= self
.id = id
33 self
.description
= description
35 self
.prerequisites
= prerequisites
38 self
.prefix
= type + "_"
43 cost
= array(self
._cost
, long)
44 cost
[labor
] *= g
.minutes_per_day
* g
.pl
.labor_bonus
46 cost
[cpu
] *= g
.seconds_per_day
49 cost
= property(get_cost
)
51 def describe_cost(self
, cost
, hide_time
=False):
52 cpu_cost
= g
.to_cpu(cost
[cpu
])
53 cash_cost
= g
.to_money(cost
[cash
])
56 labor_cost
= ", %s" % g
.to_time(cost
[labor
]).replace(" ", u
"\xA0")
57 return u
"%s\xA0CPU, %s\xA0money%s" % (cpu_cost
, cash_cost
, labor_cost
)
60 cost_str
= self
.describe_cost(self
.cost
)
61 template
= """%s\nCost: %s\n---\n%s"""
62 return template
% (self
.name
, cost_str
, self
.description
)
64 def __cmp__(self
, other
):
65 # For sorting buyables, we sort by cost; Python's cmp() is smart enough
66 # to handle this properly for tuples. The first element is price in
67 # cash, which is the one we care about the most.
68 return cmp(tuple(self
.cost
), tuple(other
.cost
))
72 assert type(self
.prerequisites
) == list
73 for prerequisite
in self
.prerequisites
:
74 if prerequisite
== "OR":
76 if prerequisite
in g
.techs
and g
.techs
[prerequisite
].done
:
82 # If we're not in OR mode, we met all our prerequisites. If we are, we
83 # didn't meet any of the OR prerequisites.
86 for stat
in ("count", "complete_count", "total_count",
87 "total_complete_count"):
88 # Ugly syntax, but it seems to be the Right Way to do it.
89 def get(self
, stat
=stat
):
90 return g
.stats
.get_statistic(self
.prefix
+ self
.id + "_" + stat
)
91 def set(self
, value
, stat
=stat
):
92 return g
.stats
.set_statistic(self
.prefix
+ self
.id + "_" + stat
, value
)
94 stat_prop
= property(get
, set)
95 setattr(BuyableClass
, stat
, stat_prop
)
97 class Buyable(object):
98 def __init__(self
, type, count
=1):
101 type.total_count
+= count
103 self
.name
= type.name
105 self
.description
= type.description
106 self
.prerequisites
= type.prerequisites
108 self
.total_cost
= type.cost
* count
109 self
.total_cost
[labor
] //= count
110 self
.cost_left
= array(self
.total_cost
, long)
115 # Note that this is a method, handled by a property to avoid confusing
117 available
= property(lambda self
: self
.type.available
)
119 def convert_from(self
, save_version
):
120 if save_version
< 4.91: # r5_pre
121 self
.cost_left
= array(self
.cost_left
, long)
122 self
.total_cost
= array(self
.total_cost
, long)
127 self
.type.complete_count
+= self
.count
128 self
.type.total_complete_count
+= self
.count
129 self
.cost_left
= array([0,0,0], long)
132 def get_cost_paid(self
):
133 return self
.total_cost
- self
.cost_left
135 def set_cost_paid(self
, value
):
136 self
.cost_left
= self
.total_cost
- value
138 cost_paid
= property(get_cost_paid
, set_cost_paid
)
140 def _percent_complete(self
, available
=(0,0,0)):
141 available_array
= array(available
, long)
142 return truediv(self
.cost_paid
+ available_array
, self
.total_cost
)
144 def min_valid(self
, complete
):
145 return complete
[self
.total_cost
> 0].min()
147 def percent_complete(self
):
148 return self
.min_valid(self
._percent
_complete
())
151 def calculate_work(self
, cash_available
=None, cpu_available
=None, time
=0):
152 """Given an amount of available resources, calculates and returns the
153 amount that would be spent and the progress towards completion."""
155 # cash_available defaults to all the player's cash.
156 if cash_available
== None:
157 cash_available
= g
.pl
.cash
159 # cpu_available defaults to the entire CPU Pool.
160 if cpu_available
== None:
161 cpu_available
= g
.pl
.cpu_pool
163 # Figure out how much we could complete.
164 pct_complete
= self
._percent
_complete
([cash_available
, cpu_available
,
167 # Find the least-complete resource.
168 least_complete
= self
.min_valid(pct_complete
)
170 # Let the other two be up to 5 percentage points closer to completion.
171 complete_cap
= min(1, least_complete
+ .05)
172 pct_complete
[pct_complete
> complete_cap
] = complete_cap
174 # Translate that back to the total amount complete.
175 raw_paid
= pct_complete
* self
.total_cost
178 was_complete
= self
.cost_paid
179 cost_paid
= numpy
.maximum(numpy
.cast
[numpy
.int64
](numpy
.ceil(raw_paid
)),
181 spent
= cost_paid
- was_complete
182 return spent
, cost_paid
184 def work_on(self
, *args
, **kwargs
):
185 """As calculate_work, but apply the changes.
187 Returns a boolean indicating whether this buyable is done afterwards.
192 spent
, self
.cost_paid
= self
.calculate_work(*args
, **kwargs
)
194 # Consume CPU and Cash.
195 # Note the cast from <type 'numpy.int64'> to <type 'int'> to avoid
196 # poisoning other calculations (like, say, g.pl.do_jobs).
197 g
.pl
.cpu_pool
-= int(spent
[cpu
])
198 g
.pl
.cash
-= int(spent
[cash
])
200 if (self
.cost_left
<= 0).all():
206 self
.type.count
-= self
.count
208 self
.type.complete_count
-= self
.count