@ Pohon BBS
Trails In Sky Combat Emu - Procedural (3 replies)

■ 🕑 1. Trails In Sky Combat Emu - Procedural
│  #!/usr/bin/env python3
│  """
│  Trails in the Sky - Procedural Combat Timeline Engine with Persistent Event Labels
│  """
│  import os
│  import sys
│  import time
│  import random
│  
│  # === EVENT TYPES ===
│  TYPE_CHARACTER = 0 # Player character taking action
│  TYPE_ENEMY = 1 # Enemy AI taking action
│  TYPE_SPELL_RESOLVE = 2 # Spell resolves after cast delay
│  TYPE_STATUS_EXPIRE = 4 # Status effect ends
│  TYPE_PLAYER_INPUT = 5 # Wait for player input before proceeding
│  
│  # === STATUS EFFECTS COLORS ===
│  STATUS_COLORS = {
│   "Casting": "\033[37m", # Light grey / off-white
│   "Poisoned": "\033[95m", # Purple
│   "Burning": "\033[91m", # Red
│   "Slowed": "\033[94m", # Blue
│   "Haste": "\033[92m", # Green
│   "Muted": "\033[93m", # Yellow
│   "Dead": "\033[90m" # Gray
│  }
│  RESET_COLOR = "\033[0m"
│  
│  # === LABEL POOL (1-9,a-z,A-Z) ===
│  label_pool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
│  label_counter = 0
│  
│  def get_label():
│   """Get next label in the cyclic pool"""
│   global label_counter
│   label = label_pool[label_counter % len(label_pool)]
│   label_counter += 1
│   return label
│  
│  # === DATA STRUCTURES ===
│  def create_character(name, hp, ep, cp, atk, defense, speed, mov, is_player=False):
│   """Create a new character dictionary with persistent label"""
│   return {
│   'name': name,
│   'hp': hp,
│   'max_hp': hp,
│   'ep': ep,
│   'cp': cp,
│   'atk': atk,
│   'defense': defense,
│   'speed': speed,
│   'mov': mov,
│   'is_player': is_player,
│   'alive': True,
│   'status_effects': [],
│   'next_action_time': 0,
│   'orbment': [4, 2, 0, 1, 1, 0, 0], # Fire, Water, Earth, Wind, Time, Space, Mirage
│   'label': get_label()
│   }
│  
│  def create_spell_resolve_event(caster_id, target_id, spell_name, resolve_time):
│   """Create a spell resolve event with persistent label"""
│   return {
│   'name': f"{spell_name} ({caster_id}→{target_id})",
│   'next_action_time': resolve_time,
│   'caster_id': caster_id,
│   'target_id': target_id,
│   'spell_name': spell_name,
│   'type': TYPE_SPELL_RESOLVE,
│   'label': get_label()
│   }
│  
│  def create_status_expire_event(target_id, effect_name, expire_time):
│   """Create a status expiration event with persistent label"""
│   return {
│   'name': f"{effect_name} expires",
│   'next_action_time': expire_time,
│   'target_id': target_id,
│   'effect_name': effect_name,
│   'type': TYPE_STATUS_EXPIRE,
│   'label': get_label()
│   }
│  
│  # === UTILITY FUNCTIONS ===
│  def get_terminal_size():
│   try:
│   return os.get_terminal_size()
│   except:
│   return type('obj', (object,), {'columns': 80, 'lines': 24})
│  
│  def clear_screen():
│   os.system('cls' if os.name == 'nt' else 'clear')
│  
│  def format_time(time_val):
│   return f"{time_val:08d}"
│  
│  def is_valid_participant(p):
│   """Check if participant should be displayed on timeline"""
│   if isinstance(p, dict):
│   if p.get('type') == TYPE_STATUS_EXPIRE:
│   return p['next_action_time'] > global_time
│   return p.get('alive', True) or p.get('type') in [TYPE_SPELL_RESOLVE]
│   return False
│  
│  def get_status_color_for(event):
│   """Determine color based on spell name, status expiration, or character status"""
│   if isinstance(event, dict):
│   # Spell Resolve: check spell name
│   if event.get('type') == TYPE_SPELL_RESOLVE:
│   if event['spell_name'] == "Burn":
│   return STATUS_COLORS["Burning"]
│   elif event['spell_name'] == "Poison":
│   return STATUS_COLORS["Poisoned"]
│   elif event['spell_name'] == "Heal":
│   return STATUS_COLORS["Haste"]
│  
│   # Status Expire: use the status name
│   elif event.get('type') == TYPE_STATUS_EXPIRE:
│   effect_name = event.get('effect_name', '')
│   return STATUS_COLORS.get(effect_name, "")
│  
│   # Character: check their status effects
│   elif 'status_effects' in event:
│   for se in event['status_effects']:
│   if se['name'] in STATUS_COLORS:
│   return STATUS_COLORS[se['name']]
│   return ""
│  
│  # === STATUS EFFECTS ===
│  def apply_status_effect(target, effect_name, duration, on_apply=None, on_tick=None, on_expire=None):
│   """Apply a status effect to a target character"""
│   existing = None
│   for se in target['status_effects']:
│   if se['name'] == effect_name:
│   existing = se
│   break
│   if existing:
│   if existing['duration'] > 0:
│   existing['duration'] = max(existing['duration'], duration)
│   return
│   # Add the effect to the target's status list
│   new_effect = {
│   'name': effect_name,
│   'duration': duration,
│   'on_apply': on_apply,
│   'on_tick': on_tick,
│   'on_expire': on_expire
│   }
│   target['status_effects'].append(new_effect)
│   # Call apply function if it exists
│   if new_effect['on_apply']:
│   new_effect['on_apply'](target)
│   # Create expiration event
│   if new_effect['duration'] > 0:
│   expire_event = create_status_expire_event(
│   id(target),
│   effect_name,
│   global_time + new_effect['duration']
│   )
│   participants.append(expire_event)
│  
│  def tick_status_effects(characters, global_time):
│   """Tick all active status effects"""
│   for char in characters:
│   if not char['alive']:
│   continue
│   for effect in list(char['status_effects']):
│   effect['duration'] -= 1
│   if effect['on_tick']:
│   effect['on_tick'](char)
│   if effect['duration'] <= 0:
│   if effect['on_expire']:
│   effect['on_expire'](char)
│   char['status_effects'].remove(effect)
│  
│  # === SPELL SYSTEM ===
│  def cast_burn_spell(caster, target, resolve_time):
│   message = f"{caster['name']} casts Burn on {target['name']}!"
│   print(message.rjust(31))
│   damage = int(caster['atk'] * 1.5)
│   target['hp'] = max(0, target['hp'] - damage)
│   if target['hp'] == 0:
│   print(f"{target['name']} collapses!")
│   target['alive'] = False
│  
│   # Remove Casting status
│   caster['status_effects'] = [se for se in caster['status_effects'] if se['name'] != 'Casting']
│  
│   # Apply burn effect (30 AT duration)
│   apply_status_effect(
│   target,
│   "Burning",
│   30,
│   on_apply=lambda t: print(f"{t['name']} catches fire!"),
│   on_tick=lambda t: t.update({'hp': max(0, t['hp'] - 1)}),
│   on_expire=lambda t: print(f"{t['name']} is no longer burning.")
│   )
│  
│  def cast_poison_spell(caster, target, resolve_time):
│   print(f"{caster['name']} casts Poison on {target['name']}!")
│   damage = int(caster['atk'] * 1.5)
│   target['hp'] = max(0, target['hp'] - damage)
│   if target['hp'] == 0:
│   print(f"{target['name']} collapses!")
│   target['alive'] = False
│  
│   # Remove Casting status
│   caster['status_effects'] = [se for se in caster['status_effects'] if se['name'] != 'Casting']
│  
│   # Apply poison effect (20 AT duration)
│   apply_status_effect(
│   target,
│   "Poisoned",
│   20,
│   on_apply=lambda t: print(f"{t['name']} is poisoned!"),
│   on_tick=lambda t: t.update({'hp': max(0, t['hp'] - 1)}),
│   on_expire=lambda t: print(f"{t['name']} is no longer poisoned.")
│   )
│  
│  def cast_heal_spell(caster, target, resolve_time):
│   print(f"{caster['name']} casts Heal on {target['name']}!")
│   target['hp'] = min(target['max_hp'], target['hp'] + 50)
│   print(f"{target['name']} healed to {target['hp']}/{target['max_hp']}")
│  
│   # Remove Casting status
│   caster['status_effects'] = [se for se in caster['status_effects'] if se['name'] != 'Casting']
│  
│  # === COMBAT ACTIONS ===
│  def handle_player_turn(actor, enemies, participants, global_time):
│   """Handle a player's turn"""
│   print(f"\n{actor['name']}'s Turn:")
│   print("A: Attack | B: Cast Burn | P: Cast Poison | H: Heal | R: Run")
│   choice = input("Choose action: ").strip().lower()
│  
│   targets = [e for e in enemies if e['alive']]
│   if not targets:
│   print("No enemies alive.")
│   return
│  
│   if choice == 'a':
│   target = select_target_from_list(targets)
│   if target:
│   print(f"{
│   
├─■ 🕑 2.
│   Hm can't post screenshot? Well
│   
│   'no OOP' version
│   
│   maybe easier to understand than OOP version.
│   
│   
│    
└─■ 🕑 3.
    There are Emus in Trails in the Sky? I've seen many bird type monsters but never anything like an emu.
     

Pohon BBS