Home » Stars! Clones, Extensions, Modding » Stars! Nova - Open Discussion and Help » Stars! Nova 0.4.0 (developmental) Release
Re: Stars! Nova 0.4.0 (developmental) Release |
Fri, 25 June 2010 14:21 |
|
sirgwain | | Senior Chief Petty Officer | Messages: 86
Registered: March 2004 Location: Tucson | |
|
Quote: | I have seen a web based race designer but I haven't seen the code/guts/algorithm, can you point me in the right direction?
|
Ready, aim... go!
Also, this old FreeStars thread full of pointers.
I had to actually decompile the flash race wizard to get the algorithm for planet hab calculations. It's a pain in the neck.
For posterity, here is the python code in all its glory. This is the Race class which has the calculations for advantage points. I haven't been working on this in a while. It's almost a straight copy of the code I decompiled from the flash version and I tried to add comments where I could figure out what was going on. It still makes my head spin a bit. It's also TERRIBLY slow. I don't know if you'd see this in a compiled language, but in a scripting language like python it takes a long time to generate all those fake planets for the hab values. Given how fast and lightweight the original Stars! was, I wonder if this algorithm is entirely accurate.
class Race(object):
"""
A race the user uses in the game. Each user can have multiple
races, and when joining a game a copy of the race is made and assigned to the game
"""
def __init__(self, name, plural_name=None):
self.name = name
if plural_name is None:
self.plural_name = str(name) + 's'
else:
self.plural_name = plural_name
self.game = None
self.user = None
self.prt = None
self.lrts = []
self.hab_low = Hab()
self.hab_high = Hab()
self.growth_rate = None
self.colonists_per_resource = None
self.factory_output = None
self.factory_cost = None
self.num_factories = None
self.factories_cost_less = None
self.mine_output = None
self.mine_cost = None
self.num_mines = None
self.techs_start_high = None
self.spend_leftovers_on = None
self.immune_grav = None
self.immune_temp = None
self.immune_rad = None
self.research_cost = ResearchCost()
# hab points used in race point calcs
self.habpoints = None
def __repr__(self):
return "<Race: %s (%s) PRT: %s, LRTs: %s, Hab(%s -> %s immune: (%s %s %s)), rc: %s>" % (self.name, self.plural_name, self.prt, self.lrts, self.hab_low, self.hab_high, self.immune_grav, self.immune_temp, self.immune_rad, self.research_cost)
@classmethod
def humanoid(cls, user):
"""
Create an instance of a Race with default Humanoid properties
"""
race = Race('Humanoid', 'Humanoids')
race.prt = PRT.JoaT
race.lrts = []
race.hab_low = Hab(15, 15, 15)
race.hab_high = Hab(85, 85, 85)
race.growth_rate = .15
race.colonists_per_resource = 1000
race.factory_output = 10
race.factory_cost = 10
race.num_factories = 10
race.factories_cost_less = False
race.mine_output = 10
race.mine_cost = 5
race.num_mines = 10
race.techs_start_high = False
race.immune_grav = False
race.immune_temp = False
race.immune_rad = False
race.spend_leftovers_on = SpendLeftoversOn.SurfaceMinerals
race.research_cost = ResearchCost(ResearchCostLevel.Standard, ResearchCostLevel.Standard, ResearchCostLevel.Standard, ResearchCostLevel.Standard, ResearchCostLevel.Standard, ResearchCostLevel.Standard)
race.user = user
race.init()
return race
def habcenter(self, index):
"""
Return the center point of this hab, i.e. for
hab 25 to 75 the center is 50
hab 60 to 100 the center is 80
"""
#return (self.hab_high[index] + self.hab_low[index]) / 2
return self._habcenter[index]
def habwidth(self, index):
"""
The habwidth of a race (away from center)
for 25 to 75 the width is 25 (25 away from 50)
for 60 to 100 the width is 20
"""
#return (self.hab_high[index] - self.hab_low[index]) / 2
return self._habwidth[index]
def immune(self, index):
"""
Return true if this race is immmune to the given index of hab
type, i.e. 0 == immune_grav
"""
if index == 0:
return self.immune_grav
elif index == 1:
return self.immune_temp
else:
return self.immune_rad
def research_cost_for_level(self, field, level):
"""
Get the research cost for a tech field/level
"""
cost = Consts.tech_research_cost[level]
rcl = self.research_cost[field]
if rcl == ResearchCostLevel.Extra:
cost *= (1.75)
elif rcl == ResearchCostLevel.Less:
cost *= (.5)
return int(cost)
def haslrt(self, lrt):
return self.lrts is not None and lrt in self.lrts
def advantage_points(self):
"""
Compute the advantage points for this race
"""
points = Consts.race_starting_points
if self.habpoints is None:
self.habpoints = self._hab_points() / 2000;
gr_factor = int(self.growth_rate * 100 + 0.5); # use raw growth rate, otherwise HEs pay for GR at 2x
gr_rate = gr_factor;
# update the points based on growth rate
if gr_factor <= 5:
points += (6 - gr_factor) * 4200;
elif gr_factor <= 13:
if gr_factor == 6: points += 3600
if gr_factor == 7: points += 2250
if gr_factor == 8: points += 600
if gr_factor == 9: points += 225
gr_factor = gr_factor * 2 - 5;
elif gr_factor < 20:
gr_factor = (gr_factor - 6) * 3
else:
gr_factor = 45;
points -= int(self.habpoints * gr_factor + .5) / 24
# give points for off center habs
immunities = 0
for habtype in xrange(0, 3):
if self.immune(habtype):
immunities += 1
else:
points += abs(self.habcenter(habtype) - 50) * 4
# multiple immunities are penalized extra
if immunities > 1:
points -= 150
# determine factory costs
oper_points = self.num_factories;
prod_points = self.factory_output;
if oper_points > 10 or prod_points > 10:
oper_points -= 9
if oper_points < 1:
oper_points = 1
prod_points -= 9
if prod_points < 1:
prod_points = 1
# HE penalty, 2 for all PRTs execpt 3 for HE
if self.prt == PRT.HE:
factory_production_cost = 3
else:
factory_production_cost = 2
prod_points *= factory_production_cost
# additional penalty for two- and three-immune
if immunities >= 2:
points -= ((prod_points * oper_points) * gr_rate) / 2
else:
points -= ((prod_points * oper_points) * gr_rate) / 9
# pop efficiency
popeff = self.colonists_per_resource / 100
if popeff > 25: popeff = 25
if popeff <= 7: points -= 2400
elif popeff == 8: points -= 1260
elif popeff == 9: points -= 600
elif popeff > 10: points += (popeff - 10) * 120
# factory points (AR races have very simple points)
if self.prt == PRT.AR:
points += 210
else:
prodpoints = 10 - self.factory_output
costpoints = 10 - self.factory_cost
operpoints = 10 - self.num_factories
tmppoints = 0
if prodpoints > 0:
tmppoints = prodpoints * 100
else:
tmppoints = prodpoints * 121
if costpoints > 0:
tmppoints += costpoints * costpoints * -60
else:
tmppoints += costpoints * -55
if operpoints > 0:
tmppoints += operpoints * 40
else:
tmppoints += operpoints * 35
# limit low factory points
llfp = 700
if tmppoints > llfp:
tmppoints = (tmppoints - llfp) / 3 + llfp
if operpoints <= -7:
if operpoints < -11:
if operpoints < -14:
tmppoints -= 360
else:
tmppoints += (operpoints + 7) * 45
else:
tmppoints += (operpoints + 6) * 30
if operpoints <= -3:
tmppoints += (prodpoints + 2) * 60
"""
I have this commented out in my code. I wish I could remember why. I don't think it's needed but I can't remember where it came from. Dang.
if operpoints > 14:
tmppoints -= 360
elif operpoints > 11:
tmppoints -= (operpoints - 7) * 45
elif operpoints > =7:
tmppoints -= (operpoints - 6) * 30
if prodpoints >= 3:
tmppoints -= (prodpoints -2) * 60
"""
points += tmppoints
if self.factories_cost_less:
points -= 175
# mines
prodpoints = 10 - self.mine_output
costpoints = 3 - self.mine_cost
operpoints = 10 - self.num_mines
tmppoints = 0
if prodpoints > 0:
tmppoints = prodpoints * 100
else:
tmppoints = prodpoints * 169
if costpoints > 0:
tmppoints -= 360
else:
tmppoints += (costpoints * -65 + 80)
if operpoints > 0:
tmppoints += operpoints * 40
else:
tmppoints += operpoints * 35
points += tmppoints
# prt and lrt point costs
points -= prt_point_cost[self.prt]
if self.lrts is not None:
for lrt in self.lrts:
points -= lrt_point_cost[lrt]
# too many lrts
goodlrts = 0
badlrts = 0
# figure out how many bad vs good lrts we have.
if self.lrts is not None:
for lrt in self.lrts:
if lrt_point_cost[lrt] > 0:
goodlrts += 1
else:
badlrts += 1
if badlrts + goodlrts > 4:
points -= (badlrts + goodlrts) * (badlrts + goodlrts - 4) * 10
if badlrts - goodlrts > 3:
points -= (badlrts - goodlrts - 3) * 60
if goodlrts - badlrts > 3:
points -= (goodlrts - badlrts - 3) * 40
# No Advanced scanners is penalized in some races
if self.lrts is not None and LRT.NAS in self.lrts:
if self.prt == PRT.PP:
points -= 280
elif self.prt == PRT.SS:
points -= 200
elif self.prt == PRT.JoaT:
points -= 40
# techs
techcosts = 0
for rc in self.research_cost:
if rc == ResearchCostLevel.Extra:
techcosts -= 1
elif rc == ResearchCostLevel.Less:
techcosts += 1
if techcosts > 0:
points -= (techcosts**2)*130
if techcosts >= 6:
points += 1430 # already paid 4680 so true cost is 3250
elif techcosts == 5:
points += 520 # already paid 3250 so true cost is 2730
elif techcosts < 0:
techcosts -= techcosts
points += techcosts * (techcosts + 9) * 15
if techcosts >= 6:
points += 30
if techcosts > 4 and self.colonists_per_resource < 1000:
points -= 190
if self.techs_start_high:
points -= 180
if self.prt == PRT.AR and self.research_cost.energy == ResearchCostLevel.Extra:
points -= 100
return points / 3
def _hab_points(self):
rp = RacePoints(self)
return rp.points()
class RacePoints(object):
def __init__(self, race):
self.race = race
def points(self):
# create a blank planet with no name at (0, 0)
self.planet = Planet('', 0, 0)
# create a blank Habitability setting
self.planet.hab = Hab()
self.test_hab_width = [50, 50, 50]
self.test_hab_start = [20, 20, 20]
self.iternum = [11, 11, 11]
self.tfdone = [0, 0, 0]
if self.race.lrts is not None and LRT.TT in self.race.lrts:
self.ttfactor = [0, 8, 17]
else:
self.ttfactor = [0, 5, 15]
points = 0.0
for h in xrange(0, 3):
if h == 0:
desire_factor = 7
ttfactor = self.ttfactor[0]
elif h == 1:
desire_factor = 5
ttfactor = self.ttfactor[1]
else:
desire_factor = 6
ttfactor = self.ttfactor[2]
for habtype in xrange(0, 3):
if self.race.immune(habtype):
self.test_hab_start[habtype] = 50
self.test_hab_width[habtype] = 11
self.iternum[habtype] = 1
else:
self.test_hab_start[habtype] = self.race.habcenter(habtype) - self.race.habwidth(habtype) - ttfactor
if self.test_hab_start[habtype] < 0:
self.test_hab_start[habtype] = 0
tmphab = self.race.habcenter(habtype) + self.race.habwidth(habtype) + ttfactor
if tmphab > 100:
tmphab = 100
self.test_hab_width[habtype] = tmphab - self.test_hab_start[habtype];
points += self.points_recursion(0, desire_factor, ttfactor)
return int(points / 10.0 + .5)
def points_recursion(self, habtype, desire_factor, ttfactor):
sumoverhab = 0.0
if habtype < 3:
for i in xrange(0, self.iternum[habtype]):
if i == 0 or self.iternum[habtype] <= 1:
tmphab = self.test_hab_start[habtype]
else:
tmphab = self.test_hab_width[habtype] * i / (self.iternum[habtype] - 1) + self.test_hab_start[habtype]
# account for terraforming
if ttfactor != 0 and not self.race.immune(habtype):
tmphab2 = self.race.habcenter(habtype) - tmphab
if abs(tmphab2) <= ttfactor:
tmphab2 = 0
elif tmphab2 < 0:
tmphab2 += ttfactor
else:
tmphab2 -= ttfactor
self.tfdone[habtype] = tmphab2
tmphab = self.race.habcenter(habtype) - tmphab2
self.planet.hab[habtype] = tmphab
sumoverhab += self.points_recursion(habtype + 1, desire_factor, ttfactor)
if not self.race.immune(habtype):
sumoverhab = sumoverhab * self.test_hab_width[habtype] / 100;
else:
# if immune to this trait, the value is always the same
# so just sum it all 11 times
sumoverhab *= 11;
else:
sumoverhab = self.planet.hab_value(self.race)#, pall, rall, iftall)
maxterra = 0
for i in xrange(0, 3):
maxterra += self.tfdone[i]
if maxterra > ttfactor:
sumoverhab -= maxterra - ttfactor
if sumoverhab < 0:
sumoverhab = 0
sumoverhab *= sumoverhab
sumoverhab *= desire_factor
return sumoverhab
Report message to a moderator
|
|
|
|
|
Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Sat, 29 May 2010 05:49
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Coyote on Sat, 29 May 2010 19:56
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Mon, 31 May 2010 16:44
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Coyote on Sun, 30 May 2010 19:43
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Mon, 31 May 2010 04:48
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: gible on Tue, 01 June 2010 01:59
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: gible on Tue, 01 June 2010 07:06
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Tue, 01 June 2010 16:42
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Coyote on Tue, 01 June 2010 23:25
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Fri, 04 June 2010 21:29
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Coyote on Wed, 09 June 2010 23:12
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Fri, 11 June 2010 07:28
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Coyote on Fri, 11 June 2010 15:09
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Coyote on Thu, 24 June 2010 20:29
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Fri, 25 June 2010 18:41
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
By: Daniel on Thu, 01 July 2010 16:28
|
|
|
Re: Stars! Nova 0.4.0 (developmental) Release
|
Goto Forum:
Current Time: Sun May 05 15:17:44 EDT 2024
|