draft tutorial revisions
This commit is contained in:
parent
838da4571d
commit
48359b5a48
70 changed files with 6216 additions and 28 deletions
13
docs/cookbook/combat/combat_animated_movement_basic.py
Normal file
13
docs/cookbook/combat/combat_animated_movement_basic.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
"""McRogueFace - Animated Movement (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_animated_movement
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_animated_movement_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
if new_x != current_x:
|
||||
anim = mcrfpy.Animation("x", float(new_x), duration, "easeInOut", callback=done)
|
||||
else:
|
||||
anim = mcrfpy.Animation("y", float(new_y), duration, "easeInOut", callback=done)
|
||||
12
docs/cookbook/combat/combat_animated_movement_basic_2.py
Normal file
12
docs/cookbook/combat/combat_animated_movement_basic_2.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
"""McRogueFace - Animated Movement (basic_2)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_animated_movement
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_animated_movement_basic_2.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
current_anim = mcrfpy.Animation("x", 100.0, 0.5, "linear")
|
||||
current_anim.start(entity)
|
||||
# Later: current_anim = None # Let it complete or create new one
|
||||
45
docs/cookbook/combat/combat_enemy_ai_basic.py
Normal file
45
docs/cookbook/combat/combat_enemy_ai_basic.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
"""McRogueFace - Basic Enemy AI (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_enemy_ai
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_enemy_ai_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
def wander(enemy, grid):
|
||||
"""Move randomly to an adjacent walkable tile."""
|
||||
ex, ey = int(enemy.x), int(enemy.y)
|
||||
|
||||
# Get valid adjacent tiles
|
||||
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
|
||||
random.shuffle(directions)
|
||||
|
||||
for dx, dy in directions:
|
||||
new_x, new_y = ex + dx, ey + dy
|
||||
|
||||
if is_walkable(grid, new_x, new_y) and not is_occupied(new_x, new_y):
|
||||
enemy.x = new_x
|
||||
enemy.y = new_y
|
||||
return
|
||||
|
||||
# No valid moves - stay in place
|
||||
|
||||
def is_walkable(grid, x, y):
|
||||
"""Check if a tile can be walked on."""
|
||||
grid_w, grid_h = grid.grid_size
|
||||
if x < 0 or x >= grid_w or y < 0 or y >= grid_h:
|
||||
return False
|
||||
return grid.at(x, y).walkable
|
||||
|
||||
def is_occupied(x, y, entities=None):
|
||||
"""Check if a tile is occupied by another entity."""
|
||||
if entities is None:
|
||||
return False
|
||||
|
||||
for entity in entities:
|
||||
if int(entity.x) == x and int(entity.y) == y:
|
||||
return True
|
||||
return False
|
||||
11
docs/cookbook/combat/combat_enemy_ai_multi.py
Normal file
11
docs/cookbook/combat/combat_enemy_ai_multi.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
"""McRogueFace - Basic Enemy AI (multi)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_enemy_ai
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_enemy_ai_multi.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
# Filter to cardinal directions only
|
||||
path = [p for p in path if abs(p[0] - ex) + abs(p[1] - ey) == 1]
|
||||
14
docs/cookbook/combat/combat_enemy_ai_multi_2.py
Normal file
14
docs/cookbook/combat/combat_enemy_ai_multi_2.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
"""McRogueFace - Basic Enemy AI (multi_2)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_enemy_ai
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_enemy_ai_multi_2.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
def alert_nearby(x, y, radius, enemies):
|
||||
for enemy in enemies:
|
||||
dist = abs(enemy.entity.x - x) + abs(enemy.entity.y - y)
|
||||
if dist <= radius and hasattr(enemy.ai, 'alert'):
|
||||
enemy.ai.alert = True
|
||||
82
docs/cookbook/combat/combat_melee_basic.py
Normal file
82
docs/cookbook/combat/combat_melee_basic.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
"""McRogueFace - Melee Combat System (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_melee
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_melee_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
class CombatLog:
|
||||
"""Scrolling combat message log."""
|
||||
|
||||
def __init__(self, x, y, width, height, max_messages=10):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.max_messages = max_messages
|
||||
self.messages = []
|
||||
self.captions = []
|
||||
|
||||
ui = mcrfpy.sceneUI(mcrfpy.currentScene())
|
||||
|
||||
# Background
|
||||
self.frame = mcrfpy.Frame(x, y, width, height)
|
||||
self.frame.fill_color = mcrfpy.Color(0, 0, 0, 180)
|
||||
ui.append(self.frame)
|
||||
|
||||
def add_message(self, text, color=None):
|
||||
"""Add a message to the log."""
|
||||
if color is None:
|
||||
color = mcrfpy.Color(200, 200, 200)
|
||||
|
||||
self.messages.append((text, color))
|
||||
|
||||
# Keep only recent messages
|
||||
if len(self.messages) > self.max_messages:
|
||||
self.messages.pop(0)
|
||||
|
||||
self._refresh_display()
|
||||
|
||||
def _refresh_display(self):
|
||||
"""Redraw all messages."""
|
||||
ui = mcrfpy.sceneUI(mcrfpy.currentScene())
|
||||
|
||||
# Remove old captions
|
||||
for caption in self.captions:
|
||||
try:
|
||||
ui.remove(caption)
|
||||
except:
|
||||
pass
|
||||
self.captions.clear()
|
||||
|
||||
# Create new captions
|
||||
line_height = 18
|
||||
for i, (text, color) in enumerate(self.messages):
|
||||
caption = mcrfpy.Caption(text, self.x + 5, self.y + 5 + i * line_height)
|
||||
caption.fill_color = color
|
||||
ui.append(caption)
|
||||
self.captions.append(caption)
|
||||
|
||||
def log_attack(self, attacker_name, defender_name, damage, killed=False, critical=False):
|
||||
"""Log an attack event."""
|
||||
if critical:
|
||||
text = f"{attacker_name} CRITS {defender_name} for {damage}!"
|
||||
color = mcrfpy.Color(255, 255, 0)
|
||||
else:
|
||||
text = f"{attacker_name} hits {defender_name} for {damage}."
|
||||
color = mcrfpy.Color(200, 200, 200)
|
||||
|
||||
self.add_message(text, color)
|
||||
|
||||
if killed:
|
||||
self.add_message(f"{defender_name} is defeated!", mcrfpy.Color(255, 100, 100))
|
||||
|
||||
|
||||
# Global combat log
|
||||
combat_log = None
|
||||
|
||||
def init_combat_log():
|
||||
global combat_log
|
||||
combat_log = CombatLog(10, 500, 400, 200)
|
||||
15
docs/cookbook/combat/combat_melee_complete.py
Normal file
15
docs/cookbook/combat/combat_melee_complete.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
"""McRogueFace - Melee Combat System (complete)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_melee
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_melee_complete.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
def die_with_animation(entity):
|
||||
# Play death animation
|
||||
anim = mcrfpy.Animation("opacity", 0.0, 0.5, "linear")
|
||||
anim.start(entity)
|
||||
# Remove after animation
|
||||
mcrfpy.setTimer("remove", lambda dt: remove_entity(entity), 500)
|
||||
14
docs/cookbook/combat/combat_melee_complete_2.py
Normal file
14
docs/cookbook/combat/combat_melee_complete_2.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
"""McRogueFace - Melee Combat System (complete_2)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_melee
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_melee_complete_2.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
@dataclass
|
||||
class AdvancedFighter(Fighter):
|
||||
fire_resist: float = 0.0
|
||||
ice_resist: float = 0.0
|
||||
physical_resist: float = 0.0
|
||||
56
docs/cookbook/combat/combat_status_effects_basic.py
Normal file
56
docs/cookbook/combat/combat_status_effects_basic.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""McRogueFace - Status Effects (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_status_effects
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_status_effects_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
class StackableEffect(StatusEffect):
|
||||
"""Effect that stacks intensity."""
|
||||
|
||||
def __init__(self, name, duration, intensity=1, max_stacks=5, **kwargs):
|
||||
super().__init__(name, duration, **kwargs)
|
||||
self.intensity = intensity
|
||||
self.max_stacks = max_stacks
|
||||
self.stacks = 1
|
||||
|
||||
def add_stack(self):
|
||||
"""Add another stack."""
|
||||
if self.stacks < self.max_stacks:
|
||||
self.stacks += 1
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class StackingEffectManager(EffectManager):
|
||||
"""Effect manager with stacking support."""
|
||||
|
||||
def add_effect(self, effect):
|
||||
if isinstance(effect, StackableEffect):
|
||||
# Check for existing stacks
|
||||
for existing in self.effects:
|
||||
if existing.name == effect.name:
|
||||
if existing.add_stack():
|
||||
# Refresh duration
|
||||
existing.duration = max(existing.duration, effect.duration)
|
||||
return
|
||||
else:
|
||||
return # Max stacks
|
||||
|
||||
# Default behavior
|
||||
super().add_effect(effect)
|
||||
|
||||
|
||||
# Stacking poison example
|
||||
def create_stacking_poison(base_damage=1, duration=5):
|
||||
def on_tick(target):
|
||||
# Find the poison effect to get stack count
|
||||
effect = target.effects.get_effect("poison")
|
||||
if effect:
|
||||
damage = base_damage * effect.stacks
|
||||
target.hp -= damage
|
||||
print(f"{target.name} takes {damage} poison damage! ({effect.stacks} stacks)")
|
||||
|
||||
return StackableEffect("poison", duration, on_tick=on_tick, max_stacks=5)
|
||||
16
docs/cookbook/combat/combat_status_effects_basic_2.py
Normal file
16
docs/cookbook/combat/combat_status_effects_basic_2.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""McRogueFace - Status Effects (basic_2)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_status_effects
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_status_effects_basic_2.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
def apply_effect(self, effect):
|
||||
if effect.name in self.immunities:
|
||||
print(f"{self.name} is immune to {effect.name}!")
|
||||
return
|
||||
if effect.name in self.resistances:
|
||||
effect.duration //= 2 # Half duration
|
||||
self.effects.add_effect(effect)
|
||||
12
docs/cookbook/combat/combat_status_effects_basic_3.py
Normal file
12
docs/cookbook/combat/combat_status_effects_basic_3.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
"""McRogueFace - Status Effects (basic_3)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_status_effects
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_status_effects_basic_3.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
def serialize_effects(effect_manager):
|
||||
return [{"name": e.name, "duration": e.duration}
|
||||
for e in effect_manager.effects]
|
||||
45
docs/cookbook/combat/combat_turn_system.py
Normal file
45
docs/cookbook/combat/combat_turn_system.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
"""McRogueFace - Turn-Based Game Loop (combat_turn_system)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/combat_turn_system
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/combat/combat_turn_system.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
def create_turn_order_ui(turn_manager, x=800, y=50):
|
||||
"""Create a visual turn order display."""
|
||||
ui = mcrfpy.sceneUI(mcrfpy.currentScene())
|
||||
|
||||
# Background frame
|
||||
frame = mcrfpy.Frame(x, y, 200, 300)
|
||||
frame.fill_color = mcrfpy.Color(30, 30, 30, 200)
|
||||
frame.outline = 2
|
||||
frame.outline_color = mcrfpy.Color(100, 100, 100)
|
||||
ui.append(frame)
|
||||
|
||||
# Title
|
||||
title = mcrfpy.Caption("Turn Order", x + 10, y + 10)
|
||||
title.fill_color = mcrfpy.Color(255, 255, 255)
|
||||
ui.append(title)
|
||||
|
||||
return frame
|
||||
|
||||
def update_turn_order_display(frame, turn_manager, x=800, y=50):
|
||||
"""Update the turn order display."""
|
||||
ui = mcrfpy.sceneUI(mcrfpy.currentScene())
|
||||
|
||||
# Clear old entries (keep frame and title)
|
||||
# In practice, store references to caption objects and update them
|
||||
|
||||
for i, actor_data in enumerate(turn_manager.actors):
|
||||
actor = actor_data["actor"]
|
||||
is_current = (i == turn_manager.current)
|
||||
|
||||
# Actor name/type
|
||||
name = getattr(actor, 'name', f"Actor {i}")
|
||||
color = mcrfpy.Color(255, 255, 0) if is_current else mcrfpy.Color(200, 200, 200)
|
||||
|
||||
caption = mcrfpy.Caption(name, x + 10, y + 40 + i * 25)
|
||||
caption.fill_color = color
|
||||
ui.append(caption)
|
||||
Loading…
Add table
Add a link
Reference in a new issue