1 # ###################################################
2 # Copyright (C) 2008 The OpenAnno Team
4 # This file is part of OpenAnno.
6 # OpenAnno is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the
18 # Free Software Foundation, Inc.,
19 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 # ###################################################
24 from game
.util
import Point
, Rect
26 class BuildableSingle(object):
28 def areBuildRequirementsSatisfied(cls
, x
, y
, before
= None, **kwargs
):
29 state
= {'x' : x
, 'y' : y
}
31 for check
in (cls
.isIslandBuildRequirementSatisfied
, cls
.isSettlementBuildRequirementSatisfied
, cls
.isGroundBuildRequirementSatisfied
, cls
.isBuildingBuildRequirementSatisfied
, cls
.isUnitBuildRequirementSatisfied
):
32 update
= check(**state
)
37 if not update
.get('buildable', True):
39 if before
is not None:
40 update
= cls
.isMultiBuildRequirementSatisfied(*before
, **state
)
45 if not update
.get('buildable', True):
50 def isMultiBuildRequirementSatisfied(cls
, *before
, **state
):
52 if not i
.get('buildable', True):
54 if i
['island'] != state
['island']:
55 return {'buildable' : False}
59 def isIslandBuildRequirementSatisfied(cls
, x
, y
, **state
):
60 island
= game
.main
.session
.world
.get_island(x
, y
)
62 return {'buildable' : False}
64 for p
.x
, p
.y
in ((xx
,yy
) for xx
in xrange(x
, x
+ cls
.size
[0]) for yy
in xrange(y
, y
+ cls
.size
[1])):
65 if island
.get_tile(p
) is None:
66 return {'buildable' : False}
67 return {'island' : island
}
70 def isSettlementBuildRequirementSatisfied(cls
, x
, y
, island
, **state
):
71 settlements
= island
.get_settlements(Rect(x
, y
, x
+ cls
.size
[0] - 1, y
+ cls
.size
[1] - 1))
72 if len(settlements
) != 1:
73 return {'buildable' : False}
74 return {'settlement' : settlements
.pop()}
77 def isGroundBuildRequirementSatisfied(cls
, x
, y
, island
, **state
):
79 for p
.x
, p
.y
in ((xx
,yy
) for xx
in xrange(x
, x
+ cls
.size
[0]) for yy
in xrange(y
, y
+ cls
.size
[1])):
80 tile_classes
= island
.get_tile(p
).__class
__.classes
81 if 'constructible' not in tile_classes
:
82 return {'buildable' : False}
86 def isBuildingBuildRequirementSatisfied(cls
, x
, y
, island
, **state
):
87 from nature
import GrowingBuilding
91 for p
.x
, p
.y
in [ (xx
,yy
) for xx
in xrange(x
, x
+ cls
.size
[0]) for yy
in xrange(y
, y
+ cls
.size
[1]) ]:
92 obj
= island
.get_tile(p
).object
94 if isinstance(obj
, GrowingBuilding
):
95 if obj
.__class
__ is cls
:
97 tear
.append(obj
.getId())
99 return {'buildable' : False}
100 return {} if len(tear
) == 0 else {'tear' : tear
}
103 def isUnitBuildRequirementSatisfied(cls
, x
, y
, island
, **state
):
107 def getBuildList(cls
, point1
, point2
, **kwargs
):
108 x
= int(round(point2
[0])) - (cls
.size
[0] - 1) / 2 if (cls
.size
[0] % 2) == 1 else int(math
.ceil(point2
[0])) - (cls
.size
[0]) / 2
109 y
= int(round(point2
[1])) - (cls
.size
[1] - 1) / 2 if (cls
.size
[1] % 2) == 1 else int(math
.ceil(point2
[1])) - (cls
.size
[1]) / 2
110 building
= cls
.areBuildRequirementsSatisfied(x
, y
, **kwargs
)
116 class BuildableRect(BuildableSingle
):
118 def getBuildList(cls
, point1
, point2
, **kwargs
):
120 for x
, y
in [ (x
, y
) for x
in xrange(int(min(round(point1
[0]), round(point2
[0]))), 1 + int(max(round(point1
[0]), round(point2
[0])))) for y
in xrange(int(min(round(point1
[1]), round(point2
[1]))), 1 + int(max(round(point1
[1]), round(point2
[1])))) ]:
121 building
= cls
.areBuildRequirementsSatisfied(x
, y
, buildings
, **kwargs
)
122 if building
is not None:
123 buildings
.append(building
)
127 class BuildableLine(BuildableSingle
):
129 def getBuildList(cls
, point1
, point2
, **kwargs
):
135 kwargs
['rotation'] = 45
136 y
= int(round(point1
[1]))
137 for x
in xrange(int(round(point1
[0])), int(round(point2
[0])), (1 if int(round(point2
[0])) > int(round(point1
[0])) else -1)):
138 building
= cls
.areBuildRequirementsSatisfied(x
, y
, buildings
, **kwargs
)
139 if building
is not None:
140 building
.update({'action' : ('d' if int(round(point2
[0])) < int(round(point1
[0])) else 'b') if len(buildings
) == 0 else 'bd'})
141 buildings
.append(building
)
142 x
= int(round(point2
[0]))
144 for y
in xrange(int(round(point1
[1])), int(round(point2
[1])) + (1 if int(round(point2
[1])) > int(round(point1
[1])) else -1), (1 if int(round(point2
[1])) > int(round(point1
[1])) else -1)):
145 if len(buildings
) == 0: #first tile
146 if y
== int(round(point2
[1])): #only tile
149 action
= 'c' if int(round(point2
[1])) > int(round(point1
[1])) else 'a'
150 elif y
== int(round(point2
[1])): #last tile
151 if int(round(point1
[1])) == int(round(point2
[1])): #only tile in this loop
152 action
= 'd' if int(round(point2
[0])) > int(round(point1
[0])) else 'b'
154 action
= 'a' if int(round(point2
[1])) > int(round(point1
[1])) else 'c'
155 elif y
== int(round(point1
[1])): #edge
156 if int(round(point2
[0])) > int(round(point1
[0])):
157 action
= 'cd' if int(round(point2
[1])) > int(round(point1
[1])) else 'ad'
159 action
= 'bc' if int(round(point2
[1])) > int(round(point1
[1])) else 'ab'
164 building
= cls
.areBuildRequirementsSatisfied(x
, y
, buildings
, **kwargs
)
165 if building
is not None:
166 building
.update({'action' : action
})
167 buildings
.append(building
)
170 class BuildableSingleWithSurrounding(BuildableSingle
):
172 def getBuildList(cls
, point1
, point2
, **kwargs
):
173 x
= int(round(point2
[0])) - (cls
.size
[0] - 1) / 2 if (cls
.size
[0] % 2) == 1 else int(math
.ceil(point2
[0])) - (cls
.size
[0]) / 2
174 y
= int(round(point2
[1])) - (cls
.size
[1] - 1) / 2 if (cls
.size
[1] % 2) == 1 else int(math
.ceil(point2
[1])) - (cls
.size
[1]) / 2
175 building
= cls
.areBuildRequirementsSatisfied(x
, y
, **kwargs
)
178 buildings
= [building
]
179 for xx
in xrange(x
- cls
.radius
, x
+ cls
.size
[0] + cls
.radius
):
180 for yy
in xrange(y
- cls
.radius
, y
+ cls
.size
[1] + cls
.radius
):
181 if ((xx
< x
or xx
>= x
+ cls
.size
[0]) or (yy
< y
or yy
>= y
+ cls
.size
[1])) and ((max(x
- xx
, 0, xx
- x
- cls
.size
[0] + 1) ** 2) + (max(y
- yy
, 0, yy
- y
- cls
.size
[1] + 1) ** 2)) <= cls
.radius
** 2:
182 building
= game
.main
.session
.entities
.buildings
[cls
._surroundingBuildingClass
].areBuildRequirementsSatisfied(xx
, yy
, **kwargs
)
183 if building
is not None:
184 building
.update(building
= game
.main
.session
.entities
.buildings
[cls
._surroundingBuildingClass
], **kwargs
)
185 buildings
.append(building
)