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

#1. Trails In Sky Combat Emu - Procedural
Published: 2025-05-22 [Thu] 21:28, by Anonymous
#!/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.
Published: 2025-05-22 [Thu] 21:32, by Anonymous
Hm can't post screenshot? Well

'no OOP' version

maybe easier to understand than OOP version.

.

#3.
Published: 2025-05-26 [Mon] 20:49, by Anonymous
There are Emus in Trails in the Sky? I've seen many bird type monsters but never anything like an emu.
.
Pohon BBS