This repository has been archived on 2024-07-18. You can view files and clone it, but cannot push or open issues or pull requests.
lwb6/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/060-planet-battle.sql

181 lines
6.3 KiB
PL/PgSQL

-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Game updates - battles (start, main computation, end)
--
-- Copyright(C) 2004-2010, DeepClone Development
-- --------------------------------------------------------
CREATE OR REPLACE FUNCTION sys.process_planet_battle_start_updates( c_tick BIGINT )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $$
DECLARE
p_id INT;
BEGIN
FOR p_id IN SELECT p.name_id
FROM sys.updates su
INNER JOIN verse.updates vu ON vu.update_id = su.id
INNER JOIN verse.planets p ON vu.planet_id = p.name_id
LEFT OUTER JOIN battles.battles b
ON b.location_id = p.name_id AND b.last_tick IS NULL
WHERE su.last_tick = c_tick AND su.status = 'PROCESSING'
AND su.gu_type = 'PLANET_BATTLE_START' AND b.location_id IS NULL
FOR UPDATE OF p
LOOP
IF battles.check_start( p_id ) THEN
PERFORM events.battle_start_event( battles.initialise( p_id , c_tick ) );
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION sys.process_planet_battle_main_updates( c_tick BIGINT )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $$
DECLARE
ttfi INT;
initi DOUBLE PRECISION;
dbonus DOUBLE PRECISION;
dmg DOUBLE PRECISION;
rdmg DOUBLE PRECISION;
rec RECORD;
a_power BIGINT;
d_power BIGINT;
p_power BIGINT;
bmod DOUBLE PRECISION;
a_dmg DOUBLE PRECISION;
d_dmg DOUBLE PRECISION;
BEGIN
ttfi := floor( sys.get_constant( 'game.battle.timeToFullIntensity' ) )::INT;
initi := sys.get_constant( 'game.battle.initialIntensity' );
dbonus := sys.get_constant( 'game.battle.defenceBonus');
dmg := sys.get_constant( 'game.battle.damage' );
rdmg := sys.get_constant( 'game.battle.randomDamage' );
FOR rec IN SELECT b.id AS battle , b.first_tick AS first_tick ,
b.location_id AS location , ph.current / p.population AS happiness
FROM sys.updates su
INNER JOIN verse.updates vu ON vu.update_id = su.id
INNER JOIN verse.planets p ON vu.planet_id = p.name_id
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
INNER JOIN battles.battles b
ON b.location_id = p.name_id AND b.last_tick IS NULL
WHERE su.last_tick = c_tick AND su.status = 'PROCESSING'
AND su.gu_type = 'PLANET_BATTLE_MAIN'
FOR UPDATE OF p , b
LOOP
PERFORM sys.write_log( 'BattleUpdate' , 'DEBUG'::log_level , 'Handling battle #' || rec.battle
|| ' at planet #' || rec.location );
-- Get stationary defence power
p_power := floor( verse.adjust_production( verse.get_raw_production( rec.location , 'DEF' ) , rec.happiness ) );
-- Get fleets power
a_power := battles.get_fleets_power( rec.battle , c_tick , TRUE );
d_power := battles.get_fleets_power( rec.battle , c_tick , FALSE );
IF a_power = 0 OR d_power + p_power = 0
THEN
PERFORM battles.set_defence_power( rec.battle , c_tick , p_power );
CONTINUE;
END IF;
PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Attack: ' || a_power
|| '; planetary defences: ' || p_power || '; defence: ' || d_power );
-- Compute battle intensity
IF c_tick - rec.first_tick < ttfi THEN
bmod := initi + ( 1 - initi ) * ( c_tick - rec.first_tick ) / ttfi;
ELSE
bmod := 1.0;
END IF;
PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Intensity modifier: ' || bmod );
-- Compute damage
d_dmg := bmod * ( d_power * ( 1 + dbonus ) + p_power ) * dmg * ( 1 - rdmg + 2.0 * rdmg * random() );
a_dmg := bmod * a_power * dmg * ( 1 - rdmg + 2.0 * rdmg * random() );
PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Damage - to defence: ' || a_dmg
|| '; to attack: ' || d_dmg );
-- Inflict damage
PERFORM battles.inflict_damage( rec.battle , a_dmg , FALSE , c_tick );
PERFORM battles.inflict_damage( rec.battle , d_dmg , TRUE , c_tick );
-- Update defence power
p_power := floor( verse.adjust_production( verse.get_raw_production( rec.location , 'DEF' ) , rec.happiness ) );
PERFORM battles.set_defence_power( rec.battle , c_tick , p_power );
END LOOP;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION sys.process_planet_battle_end_updates( c_tick BIGINT )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $$
DECLARE
rec RECORD;
n_owner INT;
BEGIN
FOR rec IN SELECT b.id AS battle , b.location_id AS location
FROM sys.updates su
INNER JOIN verse.updates vu ON vu.update_id = su.id
INNER JOIN verse.planets p ON vu.planet_id = p.name_id
INNER JOIN battles.battles b
ON b.location_id = p.name_id AND b.last_tick IS NULL
WHERE su.last_tick = c_tick AND su.status = 'PROCESSING'
AND su.gu_type = 'PLANET_BATTLE_END'
FOR UPDATE OF p , b
LOOP
IF battles.get_fleets_power( rec.battle , c_tick , TRUE ) = 0 THEN
-- Attack is dead/gone, end the battle
UPDATE battles.battles SET last_tick = c_tick
WHERE id = rec.battle;
PERFORM events.battle_end_event( rec.battle );
ELSEIF battles.get_fleets_power( rec.battle , c_tick , FALSE ) + battles.get_defence_power( rec.battle , c_tick ) = 0 THEN
-- Defence is dead/gone, transfer planet ownership to biggest fleet owner
n_owner := battles.get_biggest_fleet_owner( rec.battle , c_tick );
PERFORM events.planet_ochange_events( rec.location , n_owner );
PERFORM emp.leave_planet( rec.location );
INSERT INTO emp.planets( planet_id , empire_id )
VALUES( rec.location , n_owner );
-- End the battle
UPDATE battles.battles SET last_tick = c_tick
WHERE id = rec.battle;
PERFORM events.battle_end_event( rec.battle );
-- Set fleets in orbit to defence if they're not on the new owner's enemy list
UPDATE fleets.fleets f SET attacking = ( ele.empire IS NOT NULL )
FROM fleets.fleets f2
LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f2.id
LEFT OUTER JOIN emp.enemies ele ON ele.enemy = f2.owner_id AND ele.empire = n_owner
WHERE f.id = f2.id AND f.location_id = rec.location AND m.fleet_id IS NULL;
-- Check if the battle needs to be restarted
IF battles.check_start( rec.location ) THEN
PERFORM events.battle_start_event( battles.initialise( rec.location , c_tick ) );
END IF;
ELSE
CONTINUE;
END IF;
-- Mark the end of the battle
INSERT INTO battles.finished_battles_list
SELECT empire, battle, planet, x, y, orbit, name, first_tick, last_tick, last_update
FROM battles.full_battles_list
WHERE battle = rec.battle;
END LOOP;
END;
$$ LANGUAGE plpgsql;