nodes/data.pyΒΆ
Part of Tanks of Freedom.
1"""Game constants and data tables for Tanks of Freedom.
2
3Unit stats are lifted from upstream `scripts/objects/units/{soldier,tank,
4helicopter}.gd`; the map layout and starting line-up are this port's own,
5sized for a single 12x12 skirmish.
6"""
7
8from __future__ import annotations
9
10# ============================================================================
11# Window / world layout
12# ============================================================================
13
14WINDOW_WIDTH = 1280
15WINDOW_HEIGHT = 720
16
17# Map size: 12x12 fits a small skirmish in screen space comfortably
18MAP_W = 12
19MAP_H = 12
20
21# Iso tile dimensions. Upstream uses 64x32 for the diamond; using same here.
22TILE_W = 64
23TILE_H = 32
24
25# World origin offset so the diamond sits centred horizontally below the HUD bar
26WORLD_OFFSET_X = WINDOW_WIDTH * 0.5
27WORLD_OFFSET_Y = 120
28
29HUD_HEIGHT = 60 # top bar
30INFO_PANEL_W = 280 # right-hand info panel
31
32# ============================================================================
33# Player ids
34# ============================================================================
35
36PLAYER_BLUE = 0
37PLAYER_RED = 1
38PLAYER_NEUTRAL = -1
39
40PLAYER_COLOUR = {
41 PLAYER_BLUE: (0.30, 0.55, 0.95, 1.0),
42 PLAYER_RED: (0.95, 0.35, 0.30, 1.0),
43 PLAYER_NEUTRAL: (0.75, 0.75, 0.78, 1.0),
44}
45
46PLAYER_NAME = {
47 PLAYER_BLUE: "BLUE",
48 PLAYER_RED: "RED",
49 PLAYER_NEUTRAL: "NEUTRAL",
50}
51
52# ============================================================================
53# Unit types (from upstream unit.gd subclasses)
54# ============================================================================
55
56UNIT_SOLDIER = 0
57UNIT_TANK = 1
58UNIT_HELICOPTER = 2
59
60UNIT_STATS = {
61 UNIT_SOLDIER: {
62 "name": "INFANTRY",
63 "life": 10,
64 "max_life": 10,
65 "attack": 5,
66 "max_ap": 4,
67 "attack_ap": 1,
68 "max_attacks": 1,
69 "can_capture": True,
70 },
71 UNIT_TANK: {
72 "name": "TANK",
73 "life": 15,
74 "max_life": 15,
75 "attack": 10,
76 "max_ap": 6,
77 "attack_ap": 1,
78 "max_attacks": 1,
79 "can_capture": False,
80 },
81 UNIT_HELICOPTER: {
82 "name": "HELICOPTER",
83 "life": 10,
84 "max_life": 10,
85 "attack": 8,
86 "max_ap": 8,
87 "attack_ap": 1,
88 "max_attacks": 1,
89 "can_capture": False,
90 },
91}
92
93# How far a unit can reach a target, in grid steps. All three units are
94# melee-range in this port, matching upstream's adjacency-only combat.
95ATTACK_RANGE = {
96 UNIT_SOLDIER: 1,
97 UNIT_TANK: 1,
98 UNIT_HELICOPTER: 1,
99}
100
101# ============================================================================
102# Building types (from building.gd)
103# ============================================================================
104
105# Upstream builds units out of barracks / factory / airport; this port has no
106# production, so the four kinds differ only in look and in the HQ win condition.
107BLDG_HQ = 0
108BLDG_BARRACKS = 1
109BLDG_FACTORY = 2
110BLDG_AIRPORT = 3
111
112BUILDING_STATS = {
113 BLDG_HQ: {"name": "HQ"},
114 BLDG_BARRACKS: {"name": "BARRACKS"},
115 BLDG_FACTORY: {"name": "FACTORY"},
116 BLDG_AIRPORT: {"name": "AIRPORT"},
117}
118
119# ============================================================================
120# Terrain (impassable bits: placed on tile map by world)
121# ============================================================================
122
123TERR_GRASS = 0
124TERR_WATER = 1 # impassable for ground units
125TERR_TREE = 2 # impassable for everyone except heli
126TERR_MOUNTAIN = 3 # impassable
127
128TERRAIN_FROM_CHAR = {
129 "g": TERR_GRASS,
130 "w": TERR_WATER,
131 "f": TERR_TREE,
132 "t": TERR_TREE,
133 "m": TERR_MOUNTAIN,
134 "r": TERR_GRASS, # 'road' visually identical to grass for our procedural look
135}
136
137# 12x12 map. 'g' grass, 'f' forest/tree, 'w' water, 'm' mountain.
138# Symmetric: blue south-west, red north-east, with a neutral mid corridor.
139MAP_LAYOUT_DEFAULT = [
140 "ggggwwggffgg",
141 "gggwwggggfgg",
142 "ggffmgggrrgg",
143 "gffggggggrgg",
144 "ggggggwwgggg",
145 "gggggggwgggg",
146 "ggggwggggggg",
147 "ggggwwgggggg",
148 "ggrggggggffg",
149 "ggrrgggmffgg",
150 "ggfggggmmggg",
151 "ggffggggwwgg",
152]
153
154# ============================================================================
155# Starting state: buildings & units. Tied to MAP_LAYOUT_DEFAULT.
156# ============================================================================
157
158# (x, y, building_type, owner)
159STARTING_BUILDINGS = [
160 (1, 10, BLDG_HQ, PLAYER_BLUE),
161 (3, 10, BLDG_BARRACKS, PLAYER_BLUE),
162 (1, 8, BLDG_FACTORY, PLAYER_BLUE),
163 (3, 8, BLDG_AIRPORT, PLAYER_BLUE),
164 (10, 1, BLDG_HQ, PLAYER_RED),
165 (8, 1, BLDG_BARRACKS, PLAYER_RED),
166 (10, 3, BLDG_FACTORY, PLAYER_RED),
167 (8, 3, BLDG_AIRPORT, PLAYER_RED),
168 # Neutral mid-map captures
169 (5, 5, BLDG_BARRACKS, PLAYER_NEUTRAL),
170 (6, 6, BLDG_FACTORY, PLAYER_NEUTRAL),
171]
172
173# (x, y, unit_type, owner)
174STARTING_UNITS = [
175 (2, 10, UNIT_SOLDIER, PLAYER_BLUE),
176 (3, 9, UNIT_SOLDIER, PLAYER_BLUE),
177 (2, 8, UNIT_TANK, PLAYER_BLUE),
178 (4, 9, UNIT_HELICOPTER, PLAYER_BLUE),
179 (9, 1, UNIT_SOLDIER, PLAYER_RED),
180 (8, 2, UNIT_SOLDIER, PLAYER_RED),
181 (9, 3, UNIT_TANK, PLAYER_RED),
182 (7, 2, UNIT_HELICOPTER, PLAYER_RED),
183]
184
185# ============================================================================
186# Audio (CC-BY-SA assets bundled from upstream)
187# ============================================================================
188
189SFX_SELECT = "select.wav"
190SFX_MOVE = "move.wav"
191SFX_END_TURN = "end_turn.wav"
192SFX_EXPLOSION = "explosion.wav"
193SFX_HURT = "hurt.wav"
194SFX_BUTTON = "button.wav"
195SFX_NO_MOVES = "no_moves.wav"
196
197
198# ============================================================================
199# Combat tables
200# ============================================================================
201
202# Attacker -> Defender ban list (upstream: tank can't shoot helicopters).
203_NO_ATTACK = {(UNIT_TANK, UNIT_HELICOPTER)}
204
205
206def can_attack_unit_type(att_type: int, def_type: int) -> bool:
207 return (att_type, def_type) not in _NO_ATTACK