Pre-combat-improvements: Combat animations, flee fixes, corpse logic updates
This commit is contained in:
106
api/database.py
106
api/database.py
@@ -13,6 +13,7 @@ from sqlalchemy import (
|
||||
import time
|
||||
import logging
|
||||
from . import items
|
||||
from .services.constants import PVP_TURN_TIMEOUT
|
||||
|
||||
# Configure logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -194,7 +195,7 @@ pvp_combats = Table(
|
||||
Column("defender_character_id", Integer, ForeignKey("characters.id", ondelete="CASCADE"), nullable=False),
|
||||
Column("turn", String, nullable=False), # "attacker" or "defender"
|
||||
Column("turn_started_at", Float, nullable=False),
|
||||
Column("turn_timeout_seconds", Integer, default=300), # 5 minutes default
|
||||
Column("turn_timeout_seconds", Integer, default=PVP_TURN_TIMEOUT), # Default from constants
|
||||
Column("location_id", String, nullable=False),
|
||||
Column("created_at", Float, nullable=False),
|
||||
Column("attacker_fled", Boolean, default=False),
|
||||
@@ -873,13 +874,13 @@ async def end_combat(player_id: int) -> bool:
|
||||
|
||||
|
||||
# PvP Combat Functions
|
||||
async def create_pvp_combat(attacker_id: int, defender_id: int, location_id: str, turn_timeout: int = 300) -> dict:
|
||||
"""Create a new PvP combat. First turn goes to defender."""
|
||||
async def create_pvp_combat(attacker_id: int, defender_id: int, location_id: str, turn_timeout: int = PVP_TURN_TIMEOUT) -> dict:
|
||||
"""Create a new PvP combat. First turn goes to attacker."""
|
||||
async with DatabaseSession() as session:
|
||||
stmt = insert(pvp_combats).values(
|
||||
attacker_character_id=attacker_id,
|
||||
defender_character_id=defender_id,
|
||||
turn='defender', # Defender goes first
|
||||
turn='attacker', # Attacker goes first
|
||||
turn_started_at=time.time(),
|
||||
turn_timeout_seconds=turn_timeout,
|
||||
location_id=location_id,
|
||||
@@ -1970,6 +1971,61 @@ async def remove_expired_npc_corpses(timestamp_limit: float) -> int:
|
||||
return result.rowcount
|
||||
|
||||
|
||||
async def get_empty_player_corpses() -> List[Dict[str, Any]]:
|
||||
"""Get player corpses with no items remaining."""
|
||||
async with DatabaseSession() as session:
|
||||
stmt = select(player_corpses).where(
|
||||
or_(
|
||||
player_corpses.c.items == '[]',
|
||||
player_corpses.c.items == ''
|
||||
)
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
return [dict(row._mapping) for row in result.fetchall()]
|
||||
|
||||
|
||||
async def get_empty_npc_corpses() -> List[Dict[str, Any]]:
|
||||
"""Get NPC corpses with no loot remaining."""
|
||||
async with DatabaseSession() as session:
|
||||
stmt = select(npc_corpses).where(
|
||||
or_(
|
||||
npc_corpses.c.loot_remaining == '[]',
|
||||
npc_corpses.c.loot_remaining == ''
|
||||
)
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
return [dict(row._mapping) for row in result.fetchall()]
|
||||
|
||||
|
||||
async def remove_empty_player_corpses() -> int:
|
||||
"""Remove player corpses with no items remaining."""
|
||||
async with DatabaseSession() as session:
|
||||
stmt = delete(player_corpses).where(
|
||||
or_(
|
||||
player_corpses.c.items == '[]',
|
||||
player_corpses.c.items == ''
|
||||
)
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
await session.commit()
|
||||
return result.rowcount
|
||||
|
||||
|
||||
async def remove_empty_npc_corpses() -> int:
|
||||
"""Remove NPC corpses with no loot remaining."""
|
||||
async with DatabaseSession() as session:
|
||||
stmt = delete(npc_corpses).where(
|
||||
or_(
|
||||
npc_corpses.c.loot_remaining == '[]',
|
||||
npc_corpses.c.loot_remaining == ''
|
||||
)
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
await session.commit()
|
||||
return result.rowcount
|
||||
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# STATUS EFFECTS FUNCTIONS
|
||||
# ============================================================================
|
||||
@@ -2226,50 +2282,12 @@ async def get_pvp_combat_by_player(character_id: int) -> Optional[Dict[str, Any]
|
||||
return dict(row._mapping) if row else None
|
||||
|
||||
|
||||
async def create_pvp_combat(
|
||||
attacker_id: int,
|
||||
defender_id: int,
|
||||
location_id: str,
|
||||
turn_timeout: int = 300
|
||||
) -> Dict[str, Any]:
|
||||
"""Create a new PVP combat encounter."""
|
||||
import time
|
||||
async with DatabaseSession() as session:
|
||||
current_time = time.time()
|
||||
|
||||
# Get names for denormalization
|
||||
attacker_res = await session.execute(select(characters.c.name).where(characters.c.id == attacker_id))
|
||||
defender_res = await session.execute(select(characters.c.name).where(characters.c.id == defender_id))
|
||||
|
||||
attacker_name = attacker_res.scalar() or "Unknown"
|
||||
defender_name = defender_res.scalar() or "Unknown"
|
||||
|
||||
stmt = insert(pvp_combats).values(
|
||||
attacker_character_id=attacker_id,
|
||||
defender_character_id=defender_id,
|
||||
attacker_name=attacker_name,
|
||||
defender_name=defender_name,
|
||||
location_id=location_id,
|
||||
started_at=current_time,
|
||||
updated_at=current_time,
|
||||
turn='defender', # Defender goes first usually, or random? 'initiator pays price?'
|
||||
# Requirement says: "You have initiated combat... They get the first turn."
|
||||
turn_started_at=current_time,
|
||||
turn_timeout_seconds=turn_timeout,
|
||||
attacker_acknowledged=False,
|
||||
defender_acknowledged=False
|
||||
).returning(pvp_combats)
|
||||
|
||||
result = await session.execute(stmt)
|
||||
await session.commit()
|
||||
return dict(result.fetchone()._mapping)
|
||||
# Note: create_pvp_combat is defined above at line ~876, not duplicated here
|
||||
|
||||
|
||||
async def update_pvp_combat(combat_id: int, updates: Dict[str, Any]) -> bool:
|
||||
"""Update PVP combat state."""
|
||||
import time
|
||||
updates['updated_at'] = time.time()
|
||||
|
||||
# Don't add updated_at - column doesn't exist in table
|
||||
async with DatabaseSession() as session:
|
||||
stmt = update(pvp_combats).where(
|
||||
pvp_combats.c.id == combat_id
|
||||
|
||||
Reference in New Issue
Block a user