empire-core 0.7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- empire_core/__init__.py +36 -0
- empire_core/_archive/actions.py +511 -0
- empire_core/_archive/automation/__init__.py +24 -0
- empire_core/_archive/automation/alliance_tools.py +266 -0
- empire_core/_archive/automation/battle_reports.py +196 -0
- empire_core/_archive/automation/building_queue.py +242 -0
- empire_core/_archive/automation/defense_manager.py +124 -0
- empire_core/_archive/automation/map_scanner.py +370 -0
- empire_core/_archive/automation/multi_account.py +296 -0
- empire_core/_archive/automation/quest_automation.py +94 -0
- empire_core/_archive/automation/resource_manager.py +380 -0
- empire_core/_archive/automation/target_finder.py +153 -0
- empire_core/_archive/automation/tasks.py +224 -0
- empire_core/_archive/automation/unit_production.py +719 -0
- empire_core/_archive/cli.py +68 -0
- empire_core/_archive/client_async.py +469 -0
- empire_core/_archive/commands.py +201 -0
- empire_core/_archive/connection_async.py +228 -0
- empire_core/_archive/defense.py +156 -0
- empire_core/_archive/events/__init__.py +35 -0
- empire_core/_archive/events/base.py +153 -0
- empire_core/_archive/events/manager.py +85 -0
- empire_core/accounts.py +190 -0
- empire_core/client/__init__.py +0 -0
- empire_core/client/client.py +459 -0
- empire_core/config.py +87 -0
- empire_core/exceptions.py +42 -0
- empire_core/network/__init__.py +0 -0
- empire_core/network/connection.py +378 -0
- empire_core/protocol/__init__.py +0 -0
- empire_core/protocol/models/__init__.py +339 -0
- empire_core/protocol/models/alliance.py +186 -0
- empire_core/protocol/models/army.py +444 -0
- empire_core/protocol/models/attack.py +229 -0
- empire_core/protocol/models/auth.py +216 -0
- empire_core/protocol/models/base.py +403 -0
- empire_core/protocol/models/building.py +455 -0
- empire_core/protocol/models/castle.py +317 -0
- empire_core/protocol/models/chat.py +150 -0
- empire_core/protocol/models/defense.py +300 -0
- empire_core/protocol/models/map.py +269 -0
- empire_core/protocol/packet.py +104 -0
- empire_core/services/__init__.py +31 -0
- empire_core/services/alliance.py +222 -0
- empire_core/services/base.py +107 -0
- empire_core/services/castle.py +221 -0
- empire_core/state/__init__.py +0 -0
- empire_core/state/manager.py +398 -0
- empire_core/state/models.py +215 -0
- empire_core/state/quest_models.py +60 -0
- empire_core/state/report_models.py +115 -0
- empire_core/state/unit_models.py +75 -0
- empire_core/state/world_models.py +269 -0
- empire_core/storage/__init__.py +1 -0
- empire_core/storage/database.py +237 -0
- empire_core/utils/__init__.py +0 -0
- empire_core/utils/battle_sim.py +172 -0
- empire_core/utils/calculations.py +170 -0
- empire_core/utils/crypto.py +8 -0
- empire_core/utils/decorators.py +69 -0
- empire_core/utils/enums.py +111 -0
- empire_core/utils/helpers.py +252 -0
- empire_core/utils/response_awaiter.py +153 -0
- empire_core/utils/troops.py +93 -0
- empire_core-0.7.3.dist-info/METADATA +197 -0
- empire_core-0.7.3.dist-info/RECORD +67 -0
- empire_core-0.7.3.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Battle simulation engine.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Dict
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class UnitType:
|
|
14
|
+
"""Unit type definition."""
|
|
15
|
+
|
|
16
|
+
id: int
|
|
17
|
+
name: str
|
|
18
|
+
attack: int
|
|
19
|
+
defense: int
|
|
20
|
+
health: int
|
|
21
|
+
speed: float
|
|
22
|
+
capacity: int
|
|
23
|
+
food_cost: int
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Common unit definitions (example values - adjust based on actual game)
|
|
27
|
+
UNIT_TYPES = {
|
|
28
|
+
620: UnitType(620, "Militia", 10, 10, 50, 20, 10, 1),
|
|
29
|
+
614: UnitType(614, "Swordsman", 30, 20, 100, 18, 20, 2),
|
|
30
|
+
611: UnitType(611, "Bowman", 25, 15, 80, 20, 15, 1),
|
|
31
|
+
629: UnitType(629, "Cavalry", 50, 30, 150, 30, 30, 3),
|
|
32
|
+
626: UnitType(626, "Archer", 35, 20, 90, 20, 15, 2),
|
|
33
|
+
637: UnitType(637, "Knight", 80, 50, 200, 25, 50, 5),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class BattleResult:
|
|
39
|
+
"""Result of a battle simulation."""
|
|
40
|
+
|
|
41
|
+
attacker_wins: bool
|
|
42
|
+
attacker_losses: Dict[int, int]
|
|
43
|
+
defender_losses: Dict[int, int]
|
|
44
|
+
attacker_survivors: Dict[int, int]
|
|
45
|
+
defender_survivors: Dict[int, int]
|
|
46
|
+
loot: Dict[str, int]
|
|
47
|
+
rounds: int
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BattleSimulator:
|
|
51
|
+
"""Simulate battles between armies."""
|
|
52
|
+
|
|
53
|
+
def __init__(self):
|
|
54
|
+
self.unit_types = UNIT_TYPES
|
|
55
|
+
|
|
56
|
+
def simulate(
|
|
57
|
+
self,
|
|
58
|
+
attacker_army: Dict[int, int],
|
|
59
|
+
defender_army: Dict[int, int],
|
|
60
|
+
attacker_bonus: float = 0.0,
|
|
61
|
+
defender_bonus: float = 0.0,
|
|
62
|
+
defender_wall_level: int = 0,
|
|
63
|
+
) -> BattleResult:
|
|
64
|
+
"""
|
|
65
|
+
Simulate a battle.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
attacker_army: {unit_id: count}
|
|
69
|
+
defender_army: {unit_id: count}
|
|
70
|
+
attacker_bonus: Attack bonus % (0-100)
|
|
71
|
+
defender_bonus: Defense bonus % (0-100)
|
|
72
|
+
defender_wall_level: Wall level (adds defense)
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
BattleResult
|
|
76
|
+
"""
|
|
77
|
+
# Calculate total power
|
|
78
|
+
attacker_power = self._calculate_power(attacker_army, attacker_bonus)
|
|
79
|
+
defender_power = self._calculate_power(defender_army, defender_bonus)
|
|
80
|
+
|
|
81
|
+
# Add wall bonus
|
|
82
|
+
wall_bonus = defender_wall_level * 50 # 50 defense per level
|
|
83
|
+
defender_power += wall_bonus
|
|
84
|
+
|
|
85
|
+
# Determine winner
|
|
86
|
+
attacker_wins = attacker_power > defender_power
|
|
87
|
+
|
|
88
|
+
# Calculate losses (simplified)
|
|
89
|
+
if attacker_wins:
|
|
90
|
+
# Attacker wins - defender loses all, attacker loses some
|
|
91
|
+
power_ratio = defender_power / attacker_power if attacker_power > 0 else 0
|
|
92
|
+
attacker_losses = self._calculate_losses(attacker_army, power_ratio)
|
|
93
|
+
defender_losses = defender_army.copy()
|
|
94
|
+
else:
|
|
95
|
+
# Defender wins - attacker loses all, defender loses some
|
|
96
|
+
power_ratio = attacker_power / defender_power if defender_power > 0 else 0
|
|
97
|
+
attacker_losses = attacker_army.copy()
|
|
98
|
+
defender_losses = self._calculate_losses(defender_army, power_ratio)
|
|
99
|
+
|
|
100
|
+
# Calculate survivors
|
|
101
|
+
attacker_survivors = {uid: count - attacker_losses.get(uid, 0) for uid, count in attacker_army.items()}
|
|
102
|
+
defender_survivors = {uid: count - defender_losses.get(uid, 0) for uid, count in defender_army.items()}
|
|
103
|
+
|
|
104
|
+
# Calculate loot (if attacker wins)
|
|
105
|
+
loot = {}
|
|
106
|
+
if attacker_wins:
|
|
107
|
+
total_capacity = sum(
|
|
108
|
+
UNIT_TYPES.get(uid, UNIT_TYPES[620]).capacity * count for uid, count in attacker_survivors.items()
|
|
109
|
+
)
|
|
110
|
+
loot = {
|
|
111
|
+
"wood": int(total_capacity * 0.33),
|
|
112
|
+
"stone": int(total_capacity * 0.33),
|
|
113
|
+
"food": int(total_capacity * 0.34),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return BattleResult(
|
|
117
|
+
attacker_wins=attacker_wins,
|
|
118
|
+
attacker_losses=attacker_losses,
|
|
119
|
+
defender_losses=defender_losses,
|
|
120
|
+
attacker_survivors=attacker_survivors,
|
|
121
|
+
defender_survivors=defender_survivors,
|
|
122
|
+
loot=loot,
|
|
123
|
+
rounds=1, # Simplified - single round
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def _calculate_power(self, army: Dict[int, int], bonus: float = 0.0) -> float:
|
|
127
|
+
"""Calculate total army power."""
|
|
128
|
+
total = 0.0
|
|
129
|
+
|
|
130
|
+
for unit_id, count in army.items():
|
|
131
|
+
unit = self.unit_types.get(unit_id)
|
|
132
|
+
if not unit:
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
unit_power = (unit.attack + unit.defense + unit.health) / 3
|
|
136
|
+
total += unit_power * count
|
|
137
|
+
|
|
138
|
+
# Apply bonus
|
|
139
|
+
total *= 1 + bonus / 100
|
|
140
|
+
|
|
141
|
+
return total
|
|
142
|
+
|
|
143
|
+
def _calculate_losses(self, army: Dict[int, int], loss_ratio: float) -> Dict[int, int]:
|
|
144
|
+
"""Calculate unit losses."""
|
|
145
|
+
losses = {}
|
|
146
|
+
|
|
147
|
+
for unit_id, count in army.items():
|
|
148
|
+
lost = int(count * loss_ratio)
|
|
149
|
+
if lost > 0:
|
|
150
|
+
losses[unit_id] = lost
|
|
151
|
+
|
|
152
|
+
return losses
|
|
153
|
+
|
|
154
|
+
def estimate_outcome(self, attacker_army: Dict[int, int], defender_army: Dict[int, int]) -> str:
|
|
155
|
+
"""Quick estimate of battle outcome."""
|
|
156
|
+
att_power = self._calculate_power(attacker_army)
|
|
157
|
+
def_power = self._calculate_power(defender_army)
|
|
158
|
+
|
|
159
|
+
ratio = att_power / def_power if def_power > 0 else 999
|
|
160
|
+
|
|
161
|
+
if ratio > 2.0:
|
|
162
|
+
return "Easy Win"
|
|
163
|
+
elif ratio > 1.5:
|
|
164
|
+
return "Likely Win"
|
|
165
|
+
elif ratio > 1.0:
|
|
166
|
+
return "Close Win"
|
|
167
|
+
elif ratio > 0.75:
|
|
168
|
+
return "Close Loss"
|
|
169
|
+
elif ratio > 0.5:
|
|
170
|
+
return "Likely Loss"
|
|
171
|
+
else:
|
|
172
|
+
return "Heavy Loss"
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Game calculation utilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from typing import Tuple
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def calculate_distance(x1: int, y1: int, x2: int, y2: int) -> float:
|
|
10
|
+
"""
|
|
11
|
+
Calculate distance between two coordinates.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
x1, y1: First coordinate
|
|
15
|
+
x2, y2: Second coordinate
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
float: Distance
|
|
19
|
+
"""
|
|
20
|
+
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def calculate_travel_time(distance: float, speed: float = 20.0, speed_bonus: float = 0.0) -> int:
|
|
24
|
+
"""
|
|
25
|
+
Calculate travel time for army movement.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
distance: Distance to travel
|
|
29
|
+
speed: Base speed (default 20)
|
|
30
|
+
speed_bonus: Speed bonus percentage (0-100)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
int: Travel time in seconds
|
|
34
|
+
"""
|
|
35
|
+
effective_speed = speed * (1 + speed_bonus / 100)
|
|
36
|
+
return int(distance / effective_speed * 60) # Convert to seconds
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def calculate_resource_production(production_rate: float, hours: float) -> int:
|
|
40
|
+
"""
|
|
41
|
+
Calculate resource production over time.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
production_rate: Resources per hour
|
|
45
|
+
hours: Number of hours
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
int: Total resources produced
|
|
49
|
+
"""
|
|
50
|
+
return int(production_rate * hours)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def calculate_building_cost(base_cost: int, level: int, multiplier: float = 1.5) -> int:
|
|
54
|
+
"""
|
|
55
|
+
Calculate building upgrade cost.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
base_cost: Base cost at level 1
|
|
59
|
+
level: Target level
|
|
60
|
+
multiplier: Cost multiplier per level
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
int: Total cost
|
|
64
|
+
"""
|
|
65
|
+
return int(base_cost * (multiplier ** (level - 1)))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def calculate_unit_power(unit_stats: dict, count: int) -> int:
|
|
69
|
+
"""
|
|
70
|
+
Calculate total unit power.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
unit_stats: Dict with attack, defense, health
|
|
74
|
+
count: Number of units
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
int: Total power
|
|
78
|
+
"""
|
|
79
|
+
attack = unit_stats.get("attack", 0)
|
|
80
|
+
defense = unit_stats.get("defense", 0)
|
|
81
|
+
health = unit_stats.get("health", 0)
|
|
82
|
+
|
|
83
|
+
base_power = (attack + defense + health) / 3
|
|
84
|
+
return int(base_power * count)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def is_within_range(x1: int, y1: int, x2: int, y2: int, max_range: float) -> bool:
|
|
88
|
+
"""
|
|
89
|
+
Check if coordinates are within range.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
x1, y1: First coordinate
|
|
93
|
+
x2, y2: Second coordinate
|
|
94
|
+
max_range: Maximum range
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
bool: True if within range
|
|
98
|
+
"""
|
|
99
|
+
distance = calculate_distance(x1, y1, x2, y2)
|
|
100
|
+
return distance <= max_range
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def format_time(seconds: int) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Format seconds to human readable time.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
seconds: Time in seconds
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
str: Formatted time (e.g., "1h 30m 45s")
|
|
112
|
+
"""
|
|
113
|
+
if seconds < 0:
|
|
114
|
+
return "0s"
|
|
115
|
+
|
|
116
|
+
hours = seconds // 3600
|
|
117
|
+
minutes = (seconds % 3600) // 60
|
|
118
|
+
secs = seconds % 60
|
|
119
|
+
|
|
120
|
+
parts = []
|
|
121
|
+
if hours > 0:
|
|
122
|
+
parts.append(f"{hours}h")
|
|
123
|
+
if minutes > 0:
|
|
124
|
+
parts.append(f"{minutes}m")
|
|
125
|
+
if secs > 0 or not parts:
|
|
126
|
+
parts.append(f"{secs}s")
|
|
127
|
+
|
|
128
|
+
return " ".join(parts)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def calculate_coordinates_in_radius(center_x: int, center_y: int, radius: float) -> list[Tuple[int, int]]:
|
|
132
|
+
"""
|
|
133
|
+
Get all coordinates within radius.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
center_x: Center X coordinate
|
|
137
|
+
center_y: Center Y coordinate
|
|
138
|
+
radius: Radius
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
list: List of (x, y) tuples
|
|
142
|
+
"""
|
|
143
|
+
coords = []
|
|
144
|
+
r = int(math.ceil(radius))
|
|
145
|
+
|
|
146
|
+
for x in range(center_x - r, center_x + r + 1):
|
|
147
|
+
for y in range(center_y - r, center_y + r + 1):
|
|
148
|
+
if calculate_distance(center_x, center_y, x, y) <= radius:
|
|
149
|
+
coords.append((x, y))
|
|
150
|
+
|
|
151
|
+
return coords
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def calculate_loot_capacity(unit_capacities: dict, unit_counts: dict) -> int:
|
|
155
|
+
"""
|
|
156
|
+
Calculate total loot capacity.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
unit_capacities: Dict of {unit_id: capacity}
|
|
160
|
+
unit_counts: Dict of {unit_id: count}
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
int: Total capacity
|
|
164
|
+
"""
|
|
165
|
+
total = 0
|
|
166
|
+
for unit_id, count in unit_counts.items():
|
|
167
|
+
capacity = unit_capacities.get(unit_id, 0)
|
|
168
|
+
total += capacity * count
|
|
169
|
+
|
|
170
|
+
return total
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import functools
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Callable, Optional, Tuple, Type
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def handle_errors(
|
|
8
|
+
logger: Optional[logging.Logger] = None,
|
|
9
|
+
log_msg: Optional[str] = None,
|
|
10
|
+
re_raise: bool = True,
|
|
11
|
+
cleanup_method: Optional[str] = None,
|
|
12
|
+
ignore: Optional[Tuple[Type[BaseException], ...]] = None,
|
|
13
|
+
):
|
|
14
|
+
"""
|
|
15
|
+
Decorator to centralize error handling, logging, and cleanup.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
logger: The logger instance to use. If None, tries to get 'logger' from instance or module.
|
|
19
|
+
log_msg: Custom message to prefix the error log with.
|
|
20
|
+
re_raise: Whether to re-raise the caught exception.
|
|
21
|
+
cleanup_method: Name of a method on 'self' to call if an exception occurs (for instance methods).
|
|
22
|
+
ignore: Tuple of exception types to ignore (not log as error, just debug/pass).
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def decorator(func: Callable):
|
|
26
|
+
@functools.wraps(func)
|
|
27
|
+
async def wrapper(*args, **kwargs):
|
|
28
|
+
# Determine logger
|
|
29
|
+
_logger = logger
|
|
30
|
+
if _logger is None:
|
|
31
|
+
# Try to get 'self.logger' or module level logger
|
|
32
|
+
if args and hasattr(args[0], "logger"):
|
|
33
|
+
_logger = args[0].logger
|
|
34
|
+
else:
|
|
35
|
+
_logger = logging.getLogger(func.__module__)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
return await func(*args, **kwargs)
|
|
39
|
+
except asyncio.CancelledError as e:
|
|
40
|
+
# CancelledError is usually control flow, maybe just re-raise
|
|
41
|
+
if ignore and asyncio.CancelledError in ignore:
|
|
42
|
+
pass
|
|
43
|
+
else:
|
|
44
|
+
_logger.debug(f"{func.__name__} cancelled.")
|
|
45
|
+
raise e
|
|
46
|
+
except Exception as e:
|
|
47
|
+
if ignore and isinstance(e, ignore):
|
|
48
|
+
_logger.debug(f"Ignored error in {func.__name__}: {e}")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
msg = log_msg or f"Error in {func.__name__}"
|
|
52
|
+
_logger.error(f"{msg}: {e}", exc_info=True)
|
|
53
|
+
|
|
54
|
+
# Cleanup logic
|
|
55
|
+
if cleanup_method and args:
|
|
56
|
+
self_obj = args[0]
|
|
57
|
+
if hasattr(self_obj, cleanup_method):
|
|
58
|
+
cleanup = getattr(self_obj, cleanup_method)
|
|
59
|
+
if asyncio.iscoroutinefunction(cleanup):
|
|
60
|
+
await cleanup()
|
|
61
|
+
else:
|
|
62
|
+
cleanup()
|
|
63
|
+
|
|
64
|
+
if re_raise:
|
|
65
|
+
raise e
|
|
66
|
+
|
|
67
|
+
return wrapper
|
|
68
|
+
|
|
69
|
+
return decorator
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from enum import IntEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MapObjectType(IntEnum):
|
|
5
|
+
EMPTY = 0
|
|
6
|
+
CASTLE = 1
|
|
7
|
+
DUNGEON = 2
|
|
8
|
+
CAPITAL = 3
|
|
9
|
+
OUTPOST = 4
|
|
10
|
+
TREASURE_DUNGEON = 7
|
|
11
|
+
TREASURE_CAMP = 8
|
|
12
|
+
SHADOW_AREA = 9
|
|
13
|
+
VILLAGE = 10
|
|
14
|
+
BOSS_DUNGEON = 11
|
|
15
|
+
KINGDOM_CASTLE = 12
|
|
16
|
+
EVENT_DUNGEON = 13
|
|
17
|
+
NO_LANDMARK = 14
|
|
18
|
+
FACTION_CAMP = 15
|
|
19
|
+
FACTION_VILLAGE = 16
|
|
20
|
+
FACTION_TOWER = 17
|
|
21
|
+
FACTION_CAPITAL = 18
|
|
22
|
+
PLAGUE_AREA = 19
|
|
23
|
+
TROOP_HOSTEL = 20
|
|
24
|
+
ALIEN_CAMP = 21
|
|
25
|
+
METRO = 22
|
|
26
|
+
KINGS_TOWER = 23
|
|
27
|
+
ISLE_RESOURCE = 24
|
|
28
|
+
ISLE_DUNGEON = 25
|
|
29
|
+
MONUMENT = 26
|
|
30
|
+
NOMAD_CAMP = 27
|
|
31
|
+
LABORATORY = 28
|
|
32
|
+
SAMURAI_CAMP = 29
|
|
33
|
+
FACTION_INVASION_CAMP = 30
|
|
34
|
+
DYNAMIC = 31
|
|
35
|
+
ROBBER_BARON_CASTLE = 32 # Added explicitly
|
|
36
|
+
SAMURAI_ALIEN_CAMP = 33
|
|
37
|
+
RED_ALIEN_CAMP = 34
|
|
38
|
+
ALLIANCE_NOMAD_CAMP = 35
|
|
39
|
+
DAIMYO_CASTLE = 37
|
|
40
|
+
DAIMYO_TOWNSHIP = 38
|
|
41
|
+
ABG_RESOURCE_TOWER = 40
|
|
42
|
+
ABG_TOWER = 41
|
|
43
|
+
WOLF_KING = 42
|
|
44
|
+
NO_OUTPOST = 99
|
|
45
|
+
UNKNOWN = -1
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def is_player(self) -> bool:
|
|
49
|
+
"""Is this object a player-owned entity?"""
|
|
50
|
+
return self in (
|
|
51
|
+
MapObjectType.CASTLE,
|
|
52
|
+
MapObjectType.OUTPOST,
|
|
53
|
+
MapObjectType.CAPITAL,
|
|
54
|
+
MapObjectType.METRO,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def is_npc(self) -> bool:
|
|
59
|
+
"""Is this a permanent NPC/Robber Baron target?"""
|
|
60
|
+
return self in (
|
|
61
|
+
MapObjectType.DUNGEON,
|
|
62
|
+
MapObjectType.ROBBER_BARON_CASTLE,
|
|
63
|
+
MapObjectType.BOSS_DUNGEON,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def is_event(self) -> bool:
|
|
68
|
+
"""Is this a temporary event target (Nomad, Samurai, Alien)?"""
|
|
69
|
+
return self in (
|
|
70
|
+
MapObjectType.NOMAD_CAMP,
|
|
71
|
+
MapObjectType.SAMURAI_CAMP,
|
|
72
|
+
MapObjectType.ALIEN_CAMP,
|
|
73
|
+
MapObjectType.SAMURAI_ALIEN_CAMP,
|
|
74
|
+
MapObjectType.RED_ALIEN_CAMP,
|
|
75
|
+
MapObjectType.ALLIANCE_NOMAD_CAMP,
|
|
76
|
+
MapObjectType.EVENT_DUNGEON,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def is_resource(self) -> bool:
|
|
81
|
+
"""Is this a resource village or island?"""
|
|
82
|
+
return self in (
|
|
83
|
+
MapObjectType.VILLAGE,
|
|
84
|
+
MapObjectType.ISLE_RESOURCE,
|
|
85
|
+
MapObjectType.FACTION_VILLAGE,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class KingdomType(IntEnum):
|
|
90
|
+
GREEN = 0
|
|
91
|
+
SANDS = 1
|
|
92
|
+
ICE = 2
|
|
93
|
+
FIRE = 3
|
|
94
|
+
STORM = 4
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class MovementType(IntEnum):
|
|
98
|
+
"""Types of army movements."""
|
|
99
|
+
|
|
100
|
+
ATTACK = 1
|
|
101
|
+
SUPPORT = 2
|
|
102
|
+
TRANSPORT = 3
|
|
103
|
+
SPY = 4
|
|
104
|
+
RAID = 5
|
|
105
|
+
SETTLE = 6
|
|
106
|
+
CAMP = 7
|
|
107
|
+
TRADE = 8
|
|
108
|
+
ATTACK_CAMP = 9
|
|
109
|
+
RAID_CAMP = 10
|
|
110
|
+
RETURN = 11
|
|
111
|
+
UNKNOWN = -1
|