feat: implement complete Phase 2 frontend foundation with React 18
Major milestone: Frontend implementation complete for Shattered Void MMO FRONTEND IMPLEMENTATION: - React 18 + TypeScript + Vite development environment - Tailwind CSS with custom dark theme for sci-fi aesthetic - Zustand state management with authentication persistence - Socket.io WebSocket client with auto-reconnection - Protected routing with authentication guards - Responsive design with mobile-first approach AUTHENTICATION SYSTEM: - Login/register forms with comprehensive validation - JWT token management with localStorage persistence - Password strength validation and user feedback - Protected routes and authentication guards CORE GAME INTERFACE: - Colony management dashboard with real-time updates - Resource display with live production tracking - WebSocket integration for real-time game events - Navigation with connection status indicator - Toast notifications for user feedback BACKEND ENHANCEMENTS: - Complete Research System with technology tree (23 technologies) - Fleet Management System with ship designs and movement - Enhanced Authentication with email verification and password reset - Complete game tick integration for all systems - Advanced WebSocket events for real-time updates ARCHITECTURE FEATURES: - Type-safe TypeScript throughout - Component-based architecture with reusable UI elements - API client with request/response interceptors - Error handling and loading states - Performance optimized builds with code splitting Phase 2 Status: Frontend foundation complete (Week 1-2 objectives met) Ready for: Colony management, fleet operations, research interface Next: Enhanced gameplay features and admin interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8d9ef427be
commit
d41d1e8125
130 changed files with 33588 additions and 14817 deletions
|
|
@ -3,290 +3,290 @@
|
|||
* Adds comprehensive combat tables and enhancements for production-ready combat system
|
||||
*/
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema
|
||||
// Combat types table - defines different combat resolution types
|
||||
.createTable('combat_types', (table) => {
|
||||
table.increments('id').primary();
|
||||
table.string('name', 100).unique().notNullable();
|
||||
table.text('description');
|
||||
table.string('plugin_name', 100); // References plugins table
|
||||
table.jsonb('config');
|
||||
table.boolean('is_active').defaultTo(true);
|
||||
|
||||
table.index(['is_active']);
|
||||
table.index(['plugin_name']);
|
||||
})
|
||||
|
||||
// Main battles table - tracks all combat encounters
|
||||
.createTable('battles', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.string('battle_type', 50).notNullable(); // 'fleet_vs_fleet', 'fleet_vs_colony', 'siege'
|
||||
table.string('location', 20).notNullable();
|
||||
table.integer('combat_type_id').references('combat_types.id');
|
||||
table.jsonb('participants').notNullable(); // Array of fleet/player IDs
|
||||
table.string('status', 20).notNullable().defaultTo('pending'); // 'pending', 'active', 'completed', 'cancelled'
|
||||
table.jsonb('battle_data'); // Additional battle configuration
|
||||
table.jsonb('result'); // Final battle results
|
||||
table.timestamp('started_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('completed_at').nullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['location']);
|
||||
table.index(['status']);
|
||||
table.index(['completed_at']);
|
||||
table.index(['started_at']);
|
||||
})
|
||||
|
||||
// Combat encounters table for detailed battle tracking
|
||||
.createTable('combat_encounters', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('battle_id').references('battles.id').onDelete('CASCADE');
|
||||
table.integer('attacker_fleet_id').references('fleets.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('defender_fleet_id').references('fleets.id').onDelete('CASCADE');
|
||||
table.integer('defender_colony_id').references('colonies.id').onDelete('CASCADE');
|
||||
table.string('encounter_type', 50).notNullable(); // 'fleet_vs_fleet', 'fleet_vs_colony', 'siege'
|
||||
table.string('location', 20).notNullable();
|
||||
table.jsonb('initial_forces').notNullable(); // Starting forces for both sides
|
||||
table.jsonb('final_forces').notNullable(); // Remaining forces after combat
|
||||
table.jsonb('casualties').notNullable(); // Detailed casualty breakdown
|
||||
table.jsonb('combat_log').notNullable(); // Round-by-round combat log
|
||||
table.decimal('experience_gained', 10, 2).defaultTo(0);
|
||||
table.jsonb('loot_awarded'); // Resources/items awarded to winner
|
||||
table.string('outcome', 20).notNullable(); // 'attacker_victory', 'defender_victory', 'draw'
|
||||
table.integer('duration_seconds').notNullable(); // Combat duration
|
||||
table.timestamp('started_at').notNullable();
|
||||
table.timestamp('completed_at').notNullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['battle_id']);
|
||||
table.index(['attacker_fleet_id']);
|
||||
table.index(['defender_fleet_id']);
|
||||
table.index(['defender_colony_id']);
|
||||
table.index(['location']);
|
||||
table.index(['outcome']);
|
||||
table.index(['started_at']);
|
||||
})
|
||||
|
||||
// Combat logs for detailed event tracking
|
||||
.createTable('combat_logs', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.bigInteger('encounter_id').references('combat_encounters.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('round_number').notNullable();
|
||||
table.string('event_type', 50).notNullable(); // 'damage', 'destruction', 'ability_use', 'experience_gain'
|
||||
table.jsonb('event_data').notNullable(); // Detailed event information
|
||||
table.timestamp('timestamp').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['encounter_id', 'round_number']);
|
||||
table.index(['event_type']);
|
||||
table.index(['timestamp']);
|
||||
})
|
||||
|
||||
// Combat statistics for analysis and balancing
|
||||
.createTable('combat_statistics', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('player_id').references('players.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('battles_initiated').defaultTo(0);
|
||||
table.integer('battles_won').defaultTo(0);
|
||||
table.integer('battles_lost').defaultTo(0);
|
||||
table.integer('ships_lost').defaultTo(0);
|
||||
table.integer('ships_destroyed').defaultTo(0);
|
||||
table.bigInteger('total_damage_dealt').defaultTo(0);
|
||||
table.bigInteger('total_damage_received').defaultTo(0);
|
||||
table.decimal('total_experience_gained', 15, 2).defaultTo(0);
|
||||
table.jsonb('resources_looted').defaultTo('{}');
|
||||
table.timestamp('last_battle').nullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['player_id']);
|
||||
table.index(['battles_won']);
|
||||
table.index(['last_battle']);
|
||||
})
|
||||
|
||||
// Ship combat experience and veterancy
|
||||
.createTable('ship_combat_experience', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('fleet_id').references('fleets.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('ship_design_id').references('ship_designs.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('battles_survived').defaultTo(0);
|
||||
table.integer('enemies_destroyed').defaultTo(0);
|
||||
table.bigInteger('damage_dealt').defaultTo(0);
|
||||
table.decimal('experience_points', 15, 2).defaultTo(0);
|
||||
table.integer('veterancy_level').defaultTo(1);
|
||||
table.jsonb('combat_bonuses').defaultTo('{}'); // Experience-based bonuses
|
||||
table.timestamp('last_combat').nullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.unique(['fleet_id', 'ship_design_id']);
|
||||
table.index(['fleet_id']);
|
||||
table.index(['veterancy_level']);
|
||||
table.index(['last_combat']);
|
||||
})
|
||||
|
||||
// Combat configurations for different combat types
|
||||
.createTable('combat_configurations', (table) => {
|
||||
table.increments('id').primary();
|
||||
table.string('config_name', 100).unique().notNullable();
|
||||
table.string('combat_type', 50).notNullable(); // 'instant', 'turn_based', 'real_time'
|
||||
table.jsonb('config_data').notNullable(); // Combat-specific configuration
|
||||
table.boolean('is_active').defaultTo(true);
|
||||
table.string('description', 500);
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['combat_type']);
|
||||
table.index(['is_active']);
|
||||
})
|
||||
|
||||
// Combat modifiers for temporary effects
|
||||
.createTable('combat_modifiers', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.string('entity_type', 50).notNullable(); // 'fleet', 'colony', 'player'
|
||||
table.integer('entity_id').notNullable();
|
||||
table.string('modifier_type', 50).notNullable(); // 'attack_bonus', 'defense_bonus', 'speed_bonus'
|
||||
table.decimal('modifier_value', 8, 4).notNullable();
|
||||
table.string('source', 100).notNullable(); // 'technology', 'event', 'building', 'experience'
|
||||
table.timestamp('start_time').defaultTo(knex.fn.now());
|
||||
table.timestamp('end_time').nullable();
|
||||
table.boolean('is_active').defaultTo(true);
|
||||
table.jsonb('metadata'); // Additional modifier information
|
||||
|
||||
table.index(['entity_type', 'entity_id']);
|
||||
table.index(['modifier_type']);
|
||||
table.index(['is_active']);
|
||||
table.index(['end_time']);
|
||||
})
|
||||
|
||||
// Fleet positioning for tactical combat
|
||||
.createTable('fleet_positions', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('fleet_id').references('fleets.id').onDelete('CASCADE').notNullable();
|
||||
table.string('location', 20).notNullable();
|
||||
table.decimal('position_x', 8, 2).defaultTo(0);
|
||||
table.decimal('position_y', 8, 2).defaultTo(0);
|
||||
table.decimal('position_z', 8, 2).defaultTo(0);
|
||||
table.string('formation', 50).defaultTo('standard'); // 'standard', 'defensive', 'aggressive', 'flanking'
|
||||
table.jsonb('tactical_settings').defaultTo('{}'); // Formation-specific settings
|
||||
table.timestamp('last_updated').defaultTo(knex.fn.now());
|
||||
|
||||
table.unique(['fleet_id']);
|
||||
table.index(['location']);
|
||||
table.index(['formation']);
|
||||
})
|
||||
|
||||
// Combat queue for processing battles
|
||||
.createTable('combat_queue', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.bigInteger('battle_id').references('battles.id').onDelete('CASCADE').notNullable();
|
||||
table.string('queue_status', 20).defaultTo('pending'); // 'pending', 'processing', 'completed', 'failed'
|
||||
table.integer('priority').defaultTo(100);
|
||||
table.timestamp('scheduled_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('started_processing').nullable();
|
||||
table.timestamp('completed_at').nullable();
|
||||
table.integer('retry_count').defaultTo(0);
|
||||
table.text('error_message').nullable();
|
||||
table.jsonb('processing_metadata');
|
||||
|
||||
table.index(['queue_status']);
|
||||
table.index(['priority', 'scheduled_at']);
|
||||
table.index(['battle_id']);
|
||||
})
|
||||
|
||||
// Extend battles table with additional fields
|
||||
.alterTable('battles', (table) => {
|
||||
table.integer('combat_configuration_id').references('combat_configurations.id');
|
||||
table.jsonb('tactical_settings').defaultTo('{}');
|
||||
table.integer('spectator_count').defaultTo(0);
|
||||
table.jsonb('environmental_effects'); // Weather, nebulae, asteroid fields
|
||||
table.decimal('estimated_duration', 8, 2); // Estimated battle duration in seconds
|
||||
})
|
||||
|
||||
// Extend fleets table with combat-specific fields
|
||||
.alterTable('fleets', (table) => {
|
||||
table.decimal('combat_rating', 10, 2).defaultTo(0); // Calculated combat effectiveness
|
||||
table.integer('total_ship_count').defaultTo(0);
|
||||
table.jsonb('fleet_composition').defaultTo('{}'); // Ship type breakdown
|
||||
table.timestamp('last_combat').nullable();
|
||||
table.integer('combat_victories').defaultTo(0);
|
||||
table.integer('combat_defeats').defaultTo(0);
|
||||
})
|
||||
|
||||
// Extend ship_designs table with detailed combat stats
|
||||
.alterTable('ship_designs', (table) => {
|
||||
table.integer('hull_points').defaultTo(100);
|
||||
table.integer('shield_points').defaultTo(0);
|
||||
table.integer('armor_points').defaultTo(0);
|
||||
table.decimal('attack_power', 8, 2).defaultTo(10);
|
||||
table.decimal('attack_speed', 6, 2).defaultTo(1.0); // Attacks per second
|
||||
table.decimal('movement_speed', 6, 2).defaultTo(1.0);
|
||||
table.integer('cargo_capacity').defaultTo(0);
|
||||
table.jsonb('special_abilities').defaultTo('[]');
|
||||
table.jsonb('damage_resistances').defaultTo('{}');
|
||||
})
|
||||
|
||||
// Colony defense enhancements
|
||||
.alterTable('colonies', (table) => {
|
||||
table.integer('defense_rating').defaultTo(0);
|
||||
table.integer('shield_strength').defaultTo(0);
|
||||
table.boolean('under_siege').defaultTo(false);
|
||||
table.timestamp('last_attacked').nullable();
|
||||
table.integer('successful_defenses').defaultTo(0);
|
||||
table.integer('times_captured').defaultTo(0);
|
||||
});
|
||||
exports.up = function (knex) {
|
||||
return knex.schema
|
||||
// Combat types table - defines different combat resolution types
|
||||
.createTable('combat_types', (table) => {
|
||||
table.increments('id').primary();
|
||||
table.string('name', 100).unique().notNullable();
|
||||
table.text('description');
|
||||
table.string('plugin_name', 100); // References plugins table
|
||||
table.jsonb('config');
|
||||
table.boolean('is_active').defaultTo(true);
|
||||
|
||||
table.index(['is_active']);
|
||||
table.index(['plugin_name']);
|
||||
})
|
||||
|
||||
// Main battles table - tracks all combat encounters
|
||||
.createTable('battles', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.string('battle_type', 50).notNullable(); // 'fleet_vs_fleet', 'fleet_vs_colony', 'siege'
|
||||
table.string('location', 20).notNullable();
|
||||
table.integer('combat_type_id').references('combat_types.id');
|
||||
table.jsonb('participants').notNullable(); // Array of fleet/player IDs
|
||||
table.string('status', 20).notNullable().defaultTo('pending'); // 'pending', 'active', 'completed', 'cancelled'
|
||||
table.jsonb('battle_data'); // Additional battle configuration
|
||||
table.jsonb('result'); // Final battle results
|
||||
table.timestamp('started_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('completed_at').nullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['location']);
|
||||
table.index(['status']);
|
||||
table.index(['completed_at']);
|
||||
table.index(['started_at']);
|
||||
})
|
||||
|
||||
// Combat encounters table for detailed battle tracking
|
||||
.createTable('combat_encounters', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('battle_id').references('battles.id').onDelete('CASCADE');
|
||||
table.integer('attacker_fleet_id').references('fleets.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('defender_fleet_id').references('fleets.id').onDelete('CASCADE');
|
||||
table.integer('defender_colony_id').references('colonies.id').onDelete('CASCADE');
|
||||
table.string('encounter_type', 50).notNullable(); // 'fleet_vs_fleet', 'fleet_vs_colony', 'siege'
|
||||
table.string('location', 20).notNullable();
|
||||
table.jsonb('initial_forces').notNullable(); // Starting forces for both sides
|
||||
table.jsonb('final_forces').notNullable(); // Remaining forces after combat
|
||||
table.jsonb('casualties').notNullable(); // Detailed casualty breakdown
|
||||
table.jsonb('combat_log').notNullable(); // Round-by-round combat log
|
||||
table.decimal('experience_gained', 10, 2).defaultTo(0);
|
||||
table.jsonb('loot_awarded'); // Resources/items awarded to winner
|
||||
table.string('outcome', 20).notNullable(); // 'attacker_victory', 'defender_victory', 'draw'
|
||||
table.integer('duration_seconds').notNullable(); // Combat duration
|
||||
table.timestamp('started_at').notNullable();
|
||||
table.timestamp('completed_at').notNullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['battle_id']);
|
||||
table.index(['attacker_fleet_id']);
|
||||
table.index(['defender_fleet_id']);
|
||||
table.index(['defender_colony_id']);
|
||||
table.index(['location']);
|
||||
table.index(['outcome']);
|
||||
table.index(['started_at']);
|
||||
})
|
||||
|
||||
// Combat logs for detailed event tracking
|
||||
.createTable('combat_logs', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.bigInteger('encounter_id').references('combat_encounters.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('round_number').notNullable();
|
||||
table.string('event_type', 50).notNullable(); // 'damage', 'destruction', 'ability_use', 'experience_gain'
|
||||
table.jsonb('event_data').notNullable(); // Detailed event information
|
||||
table.timestamp('timestamp').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['encounter_id', 'round_number']);
|
||||
table.index(['event_type']);
|
||||
table.index(['timestamp']);
|
||||
})
|
||||
|
||||
// Combat statistics for analysis and balancing
|
||||
.createTable('combat_statistics', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('player_id').references('players.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('battles_initiated').defaultTo(0);
|
||||
table.integer('battles_won').defaultTo(0);
|
||||
table.integer('battles_lost').defaultTo(0);
|
||||
table.integer('ships_lost').defaultTo(0);
|
||||
table.integer('ships_destroyed').defaultTo(0);
|
||||
table.bigInteger('total_damage_dealt').defaultTo(0);
|
||||
table.bigInteger('total_damage_received').defaultTo(0);
|
||||
table.decimal('total_experience_gained', 15, 2).defaultTo(0);
|
||||
table.jsonb('resources_looted').defaultTo('{}');
|
||||
table.timestamp('last_battle').nullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['player_id']);
|
||||
table.index(['battles_won']);
|
||||
table.index(['last_battle']);
|
||||
})
|
||||
|
||||
// Ship combat experience and veterancy
|
||||
.createTable('ship_combat_experience', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('fleet_id').references('fleets.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('ship_design_id').references('ship_designs.id').onDelete('CASCADE').notNullable();
|
||||
table.integer('battles_survived').defaultTo(0);
|
||||
table.integer('enemies_destroyed').defaultTo(0);
|
||||
table.bigInteger('damage_dealt').defaultTo(0);
|
||||
table.decimal('experience_points', 15, 2).defaultTo(0);
|
||||
table.integer('veterancy_level').defaultTo(1);
|
||||
table.jsonb('combat_bonuses').defaultTo('{}'); // Experience-based bonuses
|
||||
table.timestamp('last_combat').nullable();
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.unique(['fleet_id', 'ship_design_id']);
|
||||
table.index(['fleet_id']);
|
||||
table.index(['veterancy_level']);
|
||||
table.index(['last_combat']);
|
||||
})
|
||||
|
||||
// Combat configurations for different combat types
|
||||
.createTable('combat_configurations', (table) => {
|
||||
table.increments('id').primary();
|
||||
table.string('config_name', 100).unique().notNullable();
|
||||
table.string('combat_type', 50).notNullable(); // 'instant', 'turn_based', 'real_time'
|
||||
table.jsonb('config_data').notNullable(); // Combat-specific configuration
|
||||
table.boolean('is_active').defaultTo(true);
|
||||
table.string('description', 500);
|
||||
table.timestamp('created_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['combat_type']);
|
||||
table.index(['is_active']);
|
||||
})
|
||||
|
||||
// Combat modifiers for temporary effects
|
||||
.createTable('combat_modifiers', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.string('entity_type', 50).notNullable(); // 'fleet', 'colony', 'player'
|
||||
table.integer('entity_id').notNullable();
|
||||
table.string('modifier_type', 50).notNullable(); // 'attack_bonus', 'defense_bonus', 'speed_bonus'
|
||||
table.decimal('modifier_value', 8, 4).notNullable();
|
||||
table.string('source', 100).notNullable(); // 'technology', 'event', 'building', 'experience'
|
||||
table.timestamp('start_time').defaultTo(knex.fn.now());
|
||||
table.timestamp('end_time').nullable();
|
||||
table.boolean('is_active').defaultTo(true);
|
||||
table.jsonb('metadata'); // Additional modifier information
|
||||
|
||||
table.index(['entity_type', 'entity_id']);
|
||||
table.index(['modifier_type']);
|
||||
table.index(['is_active']);
|
||||
table.index(['end_time']);
|
||||
})
|
||||
|
||||
// Fleet positioning for tactical combat
|
||||
.createTable('fleet_positions', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.integer('fleet_id').references('fleets.id').onDelete('CASCADE').notNullable();
|
||||
table.string('location', 20).notNullable();
|
||||
table.decimal('position_x', 8, 2).defaultTo(0);
|
||||
table.decimal('position_y', 8, 2).defaultTo(0);
|
||||
table.decimal('position_z', 8, 2).defaultTo(0);
|
||||
table.string('formation', 50).defaultTo('standard'); // 'standard', 'defensive', 'aggressive', 'flanking'
|
||||
table.jsonb('tactical_settings').defaultTo('{}'); // Formation-specific settings
|
||||
table.timestamp('last_updated').defaultTo(knex.fn.now());
|
||||
|
||||
table.unique(['fleet_id']);
|
||||
table.index(['location']);
|
||||
table.index(['formation']);
|
||||
})
|
||||
|
||||
// Combat queue for processing battles
|
||||
.createTable('combat_queue', (table) => {
|
||||
table.bigIncrements('id').primary();
|
||||
table.bigInteger('battle_id').references('battles.id').onDelete('CASCADE').notNullable();
|
||||
table.string('queue_status', 20).defaultTo('pending'); // 'pending', 'processing', 'completed', 'failed'
|
||||
table.integer('priority').defaultTo(100);
|
||||
table.timestamp('scheduled_at').defaultTo(knex.fn.now());
|
||||
table.timestamp('started_processing').nullable();
|
||||
table.timestamp('completed_at').nullable();
|
||||
table.integer('retry_count').defaultTo(0);
|
||||
table.text('error_message').nullable();
|
||||
table.jsonb('processing_metadata');
|
||||
|
||||
table.index(['queue_status']);
|
||||
table.index(['priority', 'scheduled_at']);
|
||||
table.index(['battle_id']);
|
||||
})
|
||||
|
||||
// Extend battles table with additional fields
|
||||
.alterTable('battles', (table) => {
|
||||
table.integer('combat_configuration_id').references('combat_configurations.id');
|
||||
table.jsonb('tactical_settings').defaultTo('{}');
|
||||
table.integer('spectator_count').defaultTo(0);
|
||||
table.jsonb('environmental_effects'); // Weather, nebulae, asteroid fields
|
||||
table.decimal('estimated_duration', 8, 2); // Estimated battle duration in seconds
|
||||
})
|
||||
|
||||
// Extend fleets table with combat-specific fields
|
||||
.alterTable('fleets', (table) => {
|
||||
table.decimal('combat_rating', 10, 2).defaultTo(0); // Calculated combat effectiveness
|
||||
table.integer('total_ship_count').defaultTo(0);
|
||||
table.jsonb('fleet_composition').defaultTo('{}'); // Ship type breakdown
|
||||
table.timestamp('last_combat').nullable();
|
||||
table.integer('combat_victories').defaultTo(0);
|
||||
table.integer('combat_defeats').defaultTo(0);
|
||||
})
|
||||
|
||||
// Extend ship_designs table with detailed combat stats
|
||||
.alterTable('ship_designs', (table) => {
|
||||
table.integer('hull_points').defaultTo(100);
|
||||
table.integer('shield_points').defaultTo(0);
|
||||
table.integer('armor_points').defaultTo(0);
|
||||
table.decimal('attack_power', 8, 2).defaultTo(10);
|
||||
table.decimal('attack_speed', 6, 2).defaultTo(1.0); // Attacks per second
|
||||
table.decimal('movement_speed', 6, 2).defaultTo(1.0);
|
||||
table.integer('cargo_capacity').defaultTo(0);
|
||||
table.jsonb('special_abilities').defaultTo('[]');
|
||||
table.jsonb('damage_resistances').defaultTo('{}');
|
||||
})
|
||||
|
||||
// Colony defense enhancements
|
||||
.alterTable('colonies', (table) => {
|
||||
table.integer('defense_rating').defaultTo(0);
|
||||
table.integer('shield_strength').defaultTo(0);
|
||||
table.boolean('under_siege').defaultTo(false);
|
||||
table.timestamp('last_attacked').nullable();
|
||||
table.integer('successful_defenses').defaultTo(0);
|
||||
table.integer('times_captured').defaultTo(0);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema
|
||||
// Remove added columns first
|
||||
.alterTable('colonies', (table) => {
|
||||
table.dropColumn('defense_rating');
|
||||
table.dropColumn('shield_strength');
|
||||
table.dropColumn('under_siege');
|
||||
table.dropColumn('last_attacked');
|
||||
table.dropColumn('successful_defenses');
|
||||
table.dropColumn('times_captured');
|
||||
})
|
||||
|
||||
.alterTable('ship_designs', (table) => {
|
||||
table.dropColumn('hull_points');
|
||||
table.dropColumn('shield_points');
|
||||
table.dropColumn('armor_points');
|
||||
table.dropColumn('attack_power');
|
||||
table.dropColumn('attack_speed');
|
||||
table.dropColumn('movement_speed');
|
||||
table.dropColumn('cargo_capacity');
|
||||
table.dropColumn('special_abilities');
|
||||
table.dropColumn('damage_resistances');
|
||||
})
|
||||
|
||||
.alterTable('fleets', (table) => {
|
||||
table.dropColumn('combat_rating');
|
||||
table.dropColumn('total_ship_count');
|
||||
table.dropColumn('fleet_composition');
|
||||
table.dropColumn('last_combat');
|
||||
table.dropColumn('combat_victories');
|
||||
table.dropColumn('combat_defeats');
|
||||
})
|
||||
|
||||
.alterTable('battles', (table) => {
|
||||
table.dropColumn('combat_configuration_id');
|
||||
table.dropColumn('tactical_settings');
|
||||
table.dropColumn('spectator_count');
|
||||
table.dropColumn('environmental_effects');
|
||||
table.dropColumn('estimated_duration');
|
||||
})
|
||||
|
||||
// Drop new tables
|
||||
.dropTableIfExists('combat_queue')
|
||||
.dropTableIfExists('fleet_positions')
|
||||
.dropTableIfExists('combat_modifiers')
|
||||
.dropTableIfExists('combat_configurations')
|
||||
.dropTableIfExists('ship_combat_experience')
|
||||
.dropTableIfExists('combat_statistics')
|
||||
.dropTableIfExists('combat_logs')
|
||||
.dropTableIfExists('combat_encounters')
|
||||
.dropTableIfExists('battles')
|
||||
.dropTableIfExists('combat_types');
|
||||
};
|
||||
exports.down = function (knex) {
|
||||
return knex.schema
|
||||
// Remove added columns first
|
||||
.alterTable('colonies', (table) => {
|
||||
table.dropColumn('defense_rating');
|
||||
table.dropColumn('shield_strength');
|
||||
table.dropColumn('under_siege');
|
||||
table.dropColumn('last_attacked');
|
||||
table.dropColumn('successful_defenses');
|
||||
table.dropColumn('times_captured');
|
||||
})
|
||||
|
||||
.alterTable('ship_designs', (table) => {
|
||||
table.dropColumn('hull_points');
|
||||
table.dropColumn('shield_points');
|
||||
table.dropColumn('armor_points');
|
||||
table.dropColumn('attack_power');
|
||||
table.dropColumn('attack_speed');
|
||||
table.dropColumn('movement_speed');
|
||||
table.dropColumn('cargo_capacity');
|
||||
table.dropColumn('special_abilities');
|
||||
table.dropColumn('damage_resistances');
|
||||
})
|
||||
|
||||
.alterTable('fleets', (table) => {
|
||||
table.dropColumn('combat_rating');
|
||||
table.dropColumn('total_ship_count');
|
||||
table.dropColumn('fleet_composition');
|
||||
table.dropColumn('last_combat');
|
||||
table.dropColumn('combat_victories');
|
||||
table.dropColumn('combat_defeats');
|
||||
})
|
||||
|
||||
.alterTable('battles', (table) => {
|
||||
table.dropColumn('combat_configuration_id');
|
||||
table.dropColumn('tactical_settings');
|
||||
table.dropColumn('spectator_count');
|
||||
table.dropColumn('environmental_effects');
|
||||
table.dropColumn('estimated_duration');
|
||||
})
|
||||
|
||||
// Drop new tables
|
||||
.dropTableIfExists('combat_queue')
|
||||
.dropTableIfExists('fleet_positions')
|
||||
.dropTableIfExists('combat_modifiers')
|
||||
.dropTableIfExists('combat_configurations')
|
||||
.dropTableIfExists('ship_combat_experience')
|
||||
.dropTableIfExists('combat_statistics')
|
||||
.dropTableIfExists('combat_logs')
|
||||
.dropTableIfExists('combat_encounters')
|
||||
.dropTableIfExists('battles')
|
||||
.dropTableIfExists('combat_types');
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue