-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcombat_npc.py
322 lines (280 loc) · 13.3 KB
/
combat_npc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
import random
from typing import Dict, Any
from map import remove_from_map
from backend import update_user_data
from item_generator import generate_weapon, generate_armor
from enemies import Enemy, enemy_types
from combat_utils import get_weapon_damage, apply_spell_effect, apply_armor_protection, death_roll, attempt_spell_cast
from player import calculate_total_hp, calculate_total_mana
from spells import spell_types
from collections import deque
def fight_npc(battle_data: Dict, npc_data: Dict[str, Any], coords: str, user_data: Dict, user: str, usersdb: Dict,
mapdb: Dict) -> None:
enemy_class = enemy_types.get(npc_data['type'].lower())
if enemy_class is None:
battle_data["rounds"].append({"round": 0, "message": f"Unknown enemy type: {npc_data['type']}"})
return
enemy = enemy_class(npc_data['level'])
if hasattr(enemy, 'spells') and enemy.spells:
enemy.spell_queue = deque(enemy.spells)
max_base_hp = 100
max_base_mana = 100
max_total_hp = calculate_total_hp(max_base_hp, user_data["exp"])
max_total_mana = calculate_total_mana(max_base_mana, user_data["exp"])
# Initialize battle data with correct HP and Mana values
battle_data["player"].update({
"name": user,
"max_hp": max_total_hp,
"current_hp": user_data["hp"],
"max_mana": max_total_mana,
"current_mana": user_data["mana"]
})
battle_data["enemy"].update({
"name": enemy.type,
"max_hp": enemy.max_hp,
"current_hp": enemy.hp,
"level": enemy.level
})
# Add initial round data
initial_round = {
"round": 0,
"message": f"Battle starts! {user} (HP: {user_data['hp']}/{max_total_hp}, Mana: {user_data['mana']}/{max_total_mana}) vs Level {enemy.level} {enemy.type} (HP: {enemy.hp}/{enemy.max_hp})",
"player_hp": user_data["hp"],
"player_mana": user_data["mana"],
"enemy_hp": enemy.hp,
"actions": []
}
battle_data["rounds"].append(initial_round)
round_number = 0
while enemy.hp > 0 and user_data["alive"]:
round_number += 1
round_data = {"round": round_number, "actions": []}
if user_data["hp"] > 0:
# Player's turn
handle_player_turn(user_data, user, enemy, round_data, usersdb, max_total_hp, max_total_mana)
if enemy.hp > 0:
# Enemy's turn
handle_enemy_turn(user_data, enemy, round_data, round_number, max_total_hp, max_total_mana)
round_data["player_hp"] = user_data["hp"]
round_data["player_mana"] = user_data["mana"]
round_data["enemy_hp"] = enemy.hp
battle_data["rounds"].append(round_data)
if enemy.hp <= 0:
defeat_round = process_npc_defeat(enemy, coords, user_data, user, usersdb, mapdb, battle_data, round_number, max_total_hp, max_total_mana)
battle_data["rounds"].append(defeat_round)
break
if user_data["hp"] <= 0:
handle_player_defeat(user_data, user, enemy, usersdb, battle_data, round_number, max_total_hp, max_total_mana)
break
# Update final battle stats
battle_data["player"]["current_hp"] = user_data["hp"]
battle_data["player"]["current_mana"] = user_data["mana"]
battle_data["enemy"]["current_hp"] = enemy.hp
def handle_player_turn(user_data: Dict, user: str, enemy: Any, round_data: Dict, usersdb: Dict,
max_total_hp: int, max_total_mana: int) -> int:
damage_dealt = 0
initial_player_hp = user_data["hp"]
initial_player_mana = user_data["mana"]
initial_enemy_hp = enemy.hp
spell_cast = attempt_spell_cast(user_data, spell_types)
if spell_cast:
damage_dealt = handle_spell_cast(user_data, user, enemy, spell_cast, round_data, usersdb, max_total_hp, max_total_mana)
else:
damage_dealt = handle_weapon_attack(user_data, enemy, round_data, max_total_hp, max_total_mana)
enemy.hp = max(0, enemy.hp - damage_dealt)
round_data["actions"][-1].update({
"final_player_hp": user_data["hp"],
"final_player_mana": user_data["mana"],
"final_enemy_hp": enemy.hp,
"initial_player_hp": initial_player_hp,
"initial_player_mana": initial_player_mana,
"initial_enemy_hp": initial_enemy_hp
})
return damage_dealt
def handle_spell_cast(user_data: Dict, user: str, enemy: Any, spell_cast: Dict, round_data: Dict, usersdb: Dict,
max_total_hp: int, max_total_mana: int) -> int:
initial_enemy_hp = enemy.hp
initial_player_hp = user_data['hp']
initial_mana = user_data['mana']
# Apply the spell effect
spell_effect = spell_cast['spell_object'].effect(user_data, enemy.__dict__)
# Update mana
user_data['mana'] = max(0, user_data['mana'] - spell_cast['mana_cost'])
# Determine what happened based on the spell effect
damage_dealt = spell_effect.get('damage_dealt', 0)
healing_done = spell_effect.get('healing_done', 0)
# Create the action message
message = spell_effect.get('message', f"You cast {spell_cast['name']}")
message += f" Enemy {enemy.type} HP: {enemy.hp}/{enemy.max_hp}. "
message += f"Your HP: {user_data['hp']}/{max_total_hp}. "
message += f"Your mana: {user_data['mana']}/{max_total_mana} (-{initial_mana - user_data['mana']})."
# Log the action
round_data["actions"].append({
"actor": "player",
"type": "spell",
"spell_name": spell_cast['name'],
"effect": spell_effect,
"damage_dealt": damage_dealt,
"healing_done": healing_done,
"mana_used": initial_mana - user_data['mana'],
"hp_change": user_data['hp'] - initial_player_hp,
"enemy_hp_change": initial_enemy_hp - enemy.hp,
"message": message
})
# Update user data in the database
update_user_data(user=user, updated_values={"mana": user_data["mana"], "hp": user_data["hp"]},
user_data_dict=usersdb)
return damage_dealt
def handle_weapon_attack(user_data: Dict, enemy: Any, round_data: Dict, max_total_hp: int, max_total_mana: int) -> int:
user_dmg = get_weapon_damage(user_data)
if user_dmg['damage'] > 0:
return process_hit(user_data, enemy, user_dmg, round_data, max_total_hp, max_total_mana)
else:
return process_miss(user_data, enemy, round_data, max_total_hp, max_total_mana)
def process_hit(user_data: Dict, enemy: Any, user_dmg: Dict, round_data: Dict, max_total_hp: int, max_total_mana: int) -> int:
if enemy.attempt_evasion():
round_data["actions"].append({
"actor": "enemy",
"type": "evasion",
"message": f"The level {enemy.level} {enemy.type} evaded your attack."
})
return 0
elif enemy.attempt_block():
blocked_damage = int(user_dmg['damage'] * enemy.block_reduction)
damage_dealt = max(0, user_dmg['damage'] - blocked_damage)
round_data["actions"].append({
"actor": "enemy",
"type": "block",
"message": f"The level {enemy.level} {enemy.type} blocked part of your attack. Damage reduced from {user_dmg['damage']} to {damage_dealt}."
})
else:
damage_dealt = user_dmg['damage']
round_data["actions"].append({
"actor": "player",
"type": "attack",
"damage": damage_dealt,
"message": f"You {user_dmg['message']} the level {enemy.level} {enemy.type} for {damage_dealt} damage "
f"(Base: {user_dmg['base_damage']}, Martial bonus: {user_dmg['martial_bonus']}). "
f"Enemy HP: {enemy.hp}/{enemy.max_hp}. Your HP: {user_data['hp']}/{max_total_hp}. "
f"Your Mana: {user_data['mana']}/{max_total_mana}"
})
return damage_dealt
def process_miss(user_data: Dict, enemy: Any, round_data: Dict, max_total_hp: int, max_total_mana: int) -> int:
weapon = next((item for item in user_data.get("equipped", []) if item.get("slot") == "right_hand"), None)
if weapon:
message = f"Your attack with {weapon['type']} missed the {enemy.type}."
else:
message = f"Your unarmed attack missed the {enemy.type}."
message += f" Your HP: {user_data['hp']}/{max_total_hp}. Your Mana: {user_data['mana']}/{max_total_mana}"
round_data["actions"].append({
"actor": "player",
"type": "miss",
"damage": 0,
"message": message
})
return 0
def handle_enemy_turn(user_data: Dict, enemy: Any, round_data: Dict, round_number: int, max_total_hp: int, max_total_mana: int) -> None:
npc_dmg = enemy.roll_damage()
initial_player_hp = user_data["hp"]
initial_player_mana = user_data["mana"]
initial_enemy_hp = enemy.hp
final_damage, absorbed_damage = apply_armor_protection(user_data, npc_dmg["damage"], round_data, round_number)
user_data["hp"] = max(0, user_data["hp"] - final_damage) # Ensure HP doesn't go below 0
round_data["actions"].append({
"actor": "enemy",
"type": "attack",
"damage": final_damage,
"initial_player_hp": initial_player_hp,
"final_player_hp": user_data["hp"],
"initial_player_mana": initial_player_mana,
"final_player_mana": user_data["mana"],
"initial_enemy_hp": initial_enemy_hp,
"final_enemy_hp": enemy.hp,
"message": f"The level {enemy.level} {enemy.type} {npc_dmg['message']} you for {final_damage} damage. Your HP: {user_data['hp']}/{max_total_hp}. Your Mana: {user_data['mana']}/{max_total_mana}"
})
def handle_player_defeat(user_data: Dict, user: str, enemy: Any, usersdb: Dict, battle_data: Dict, round_number: int,
max_total_hp: int, max_total_mana: int) -> None:
if death_roll(enemy.crit_chance):
battle_data["rounds"].append({
"round": round_number + 1,
"actions": [{
"actor": "system",
"type": "defeat",
"message": f"You have been defeated and died. Your HP: 0/{max_total_hp}. Your Mana: {user_data['mana']}/{max_total_mana}"
}],
"player_hp": 0,
"player_mana": user_data["mana"],
"enemy_hp": enemy.hp
})
user_data["alive"] = False
user_data["deaths"] = user_data.get("deaths", 0) + 1
update_user_data(user=user, updated_values={"alive": False, "hp": 0, "mana": user_data["mana"], "deaths": user_data["deaths"]},
user_data_dict=usersdb)
else:
battle_data["rounds"].append({
"round": round_number + 1,
"actions": [{
"actor": "system",
"type": "escape",
"message": f"You are critically wounded but managed to escape. Your HP: 1/{max_total_hp}. Your Mana: {user_data['mana']}/{max_total_mana}"
}],
"player_hp": 1,
"player_mana": user_data["mana"],
"enemy_hp": enemy.hp
})
update_user_data(user=user, updated_values={"action_points": user_data["action_points"] - 1, "hp": 1,
"mana": user_data["mana"]},
user_data_dict=usersdb)
def process_npc_defeat(enemy: Enemy, coords: str, user_data: Dict, user: str, usersdb: Dict, mapdb: Dict,
battle_data: Dict, round_number: int, max_total_hp: int, max_total_mana: int) -> Dict:
defeat_round = {
"round": round_number + 1,
"actions": [{
"actor": "system",
"type": "defeat",
"message": f"The level {enemy.level} {enemy.type} is defeated. Your HP: {user_data['hp']}/{max_total_hp}. Your Mana: {user_data['mana']}/{max_total_mana}"
}],
"player_hp": user_data["hp"],
"player_mana": user_data["mana"],
"enemy_hp": 0
}
if random.random() < enemy.drop_chance:
min_item_level = max(1, int(enemy.level / 2))
max_item_level = enemy.level
new_item = generate_weapon(min_level=min_item_level,
max_level=max_item_level) if random.random() < 0.5 else generate_armor(
min_level=min_item_level, max_level=max_item_level)
defeat_round["actions"].append({
"actor": "system",
"type": "loot",
"message": f"You found a level {new_item['level']} {new_item['type']}!",
"item": new_item
})
user_data["unequipped"].append(new_item)
else:
defeat_round["actions"].append({
"actor": "system",
"type": "no_loot",
"message": f"The defeated {enemy.type} didn't drop any items."
})
remove_from_map(entity_type=enemy.type.lower(), coords=coords, map_data_dict=mapdb)
experience_gained = enemy.experience
defeat_round["actions"].append({
"actor": "system",
"type": "exp_gain",
"message": f"You gained {experience_gained} experience points.",
"exp_gained": experience_gained
})
ingredients = user_data.get("ingredients", {})
for item, amount in enemy.regular_drop.items():
ingredients[item] = ingredients.get(item, 0) + amount
updated_values = {
"action_points": user_data["action_points"] - 1,
"exp": user_data["exp"] + experience_gained,
"hp": user_data["hp"],
"mana": user_data["mana"],
"unequipped": user_data["unequipped"],
"ingredients": ingredients
}
update_user_data(user=user, updated_values=updated_values, user_data_dict=usersdb)
return defeat_round