nodes/td_data.pyΒΆ
Part of Tower Defence.
1"""Tower Defence constants + spawn / turret data tables.
2
3Translated from upstream's `constants.py`, `enemy_data.py`, `turret_data.py`.
4Cooldowns and speeds were originally frame-counted (60 FPS); we convert
5millisecond cooldowns into seconds and pygame px/frame speeds into px/sec
6(`speed * 60`) so the SimVX delta-time integration is frame-rate independent.
7"""
8
9from __future__ import annotations
10
11ROWS = 15
12COLS = 15
13TILE_SIZE = 48
14SIDE_PANEL = 300
15SCREEN_WIDTH = TILE_SIZE * COLS # 720
16SCREEN_HEIGHT = TILE_SIZE * ROWS # 720
17WINDOW_WIDTH = SCREEN_WIDTH + SIDE_PANEL
18WINDOW_HEIGHT = SCREEN_HEIGHT
19
20START_HEALTH = 20
21START_MONEY = 900
22TOTAL_LEVELS = 15
23
24# Enemy spawn cadence (seconds between spawns) -- upstream is 400 ms.
25SPAWN_COOLDOWN = 0.4
26
27# Turret tunables
28TURRET_LEVELS = 4
29BUY_COST = 200
30UPGRADE_COST = 100
31KILL_REWARD = 1
32LEVEL_COMPLETE_REWARD = 100
33ANIMATION_STEPS = 8
34ANIMATION_FPS = 67 # upstream: 1 frame per 15 ms => ~67 FPS animation
35DAMAGE = 5
36
37# Per-tower-type tunables (slow + sniper variants on top of the upstream "basic")
38TURRET_TYPES = {
39 # Default: balanced, animated turret from the tutorial. Ranges are bumped
40 # ~30% over the upstream values so a single turret covers a full
41 # adjacent path segment (the upstream values needed dense placement and
42 # are a poor demo for a single-wave port).
43 "basic": [
44 {"range": 120, "cooldown": 0.9, "damage": 5, "colour": (1.0, 1.0, 1.0, 1.0)},
45 {"range": 140, "cooldown": 0.8, "damage": 6, "colour": (1.0, 1.0, 1.0, 1.0)},
46 {"range": 160, "cooldown": 0.7, "damage": 7, "colour": (1.0, 1.0, 1.0, 1.0)},
47 {"range": 190, "cooldown": 0.6, "damage": 9, "colour": (1.0, 1.0, 1.0, 1.0)},
48 ],
49 # Slow: short range, deals less damage but applies a slow-debuff for 1 s
50 "slow": [
51 {
52 "range": 70,
53 "cooldown": 0.8,
54 "damage": 2,
55 "colour": (0.55, 0.85, 1.0, 1.0),
56 "slow_factor": 0.5,
57 "slow_seconds": 1.0,
58 },
59 {
60 "range": 85,
61 "cooldown": 0.7,
62 "damage": 3,
63 "colour": (0.55, 0.85, 1.0, 1.0),
64 "slow_factor": 0.45,
65 "slow_seconds": 1.2,
66 },
67 {
68 "range": 100,
69 "cooldown": 0.6,
70 "damage": 3,
71 "colour": (0.55, 0.85, 1.0, 1.0),
72 "slow_factor": 0.4,
73 "slow_seconds": 1.4,
74 },
75 {
76 "range": 120,
77 "cooldown": 0.5,
78 "damage": 4,
79 "colour": (0.55, 0.85, 1.0, 1.0),
80 "slow_factor": 0.35,
81 "slow_seconds": 1.6,
82 },
83 ],
84 # Sniper: long range, slow rate, big damage
85 "sniper": [
86 {"range": 200, "cooldown": 2.4, "damage": 14, "colour": (1.0, 0.65, 0.35, 1.0)},
87 {"range": 230, "cooldown": 2.1, "damage": 18, "colour": (1.0, 0.65, 0.35, 1.0)},
88 {"range": 260, "cooldown": 1.8, "damage": 24, "colour": (1.0, 0.65, 0.35, 1.0)},
89 {"range": 300, "cooldown": 1.5, "damage": 30, "colour": (1.0, 0.65, 0.35, 1.0)},
90 ],
91}
92
93TURRET_COSTS = {"basic": 200, "slow": 250, "sniper": 350}
94TURRET_LABELS = {"basic": "BASIC", "slow": "SLOW", "sniper": "SNIPER"}
95
96ENEMY_DATA = {
97 "weak": {"health": 10, "speed": 120.0}, # upstream 2 px/frame * 60 = 120 px/s
98 "medium": {"health": 15, "speed": 180.0},
99 "strong": {"health": 20, "speed": 240.0},
100 "elite": {"health": 30, "speed": 360.0},
101}
102
103ENEMY_COLOURS = {
104 "weak": (1.0, 1.0, 1.0, 1.0),
105 "medium": (0.85, 1.0, 0.85, 1.0),
106 "strong": (1.0, 0.85, 0.85, 1.0),
107 "elite": (1.0, 0.92, 0.4, 1.0),
108}
109
110# Spawn schedule per level (count per type). Trimmed slightly from upstream
111# to keep early waves snappier for testing.
112ENEMY_SPAWN_DATA = [
113 {"weak": 8, "medium": 0, "strong": 0, "elite": 0}, # 1
114 {"weak": 12, "medium": 0, "strong": 0, "elite": 0}, # 2
115 {"weak": 10, "medium": 4, "strong": 0, "elite": 0}, # 3
116 {"weak": 12, "medium": 8, "strong": 0, "elite": 0}, # 4
117 {"weak": 5, "medium": 10, "strong": 1, "elite": 0}, # 5
118 {"weak": 8, "medium": 8, "strong": 3, "elite": 0}, # 6
119 {"weak": 10, "medium": 12, "strong": 4, "elite": 0}, # 7
120 {"weak": 6, "medium": 10, "strong": 6, "elite": 1}, # 8
121 {"weak": 8, "medium": 8, "strong": 8, "elite": 2}, # 9
122 {"weak": 0, "medium": 20, "strong": 0, "elite": 0}, # 10
123 {"weak": 4, "medium": 8, "strong": 8, "elite": 2}, # 11
124 {"weak": 0, "medium": 10, "strong": 8, "elite": 4}, # 12
125 {"weak": 12, "medium": 0, "strong": 14, "elite": 6}, # 13
126 {"weak": 10, "medium": 10, "strong": 10, "elite": 8}, # 14
127 {"weak": 12, "medium": 12, "strong": 12, "elite": 12}, # 15
128]