Emmanuel BENOîT
56eddcc4f0
* Added a set of tables which define game updates and their targets. These definitions replace the old enumerate type. Added a set of triggers which automatically create specific update tables, insert missing entries, etc... when game update types are being manipulated. * Removed manual insertion of game updates from empire creation function and universe generator. * Added registration of core update targets (i.e. planets and empires), updated all existing game update processing functions and added type registrations * Created Maven project for game updates control components, moved existing components from the -simple project, rewritten most of what they contained, added new components for server-side update batch processing
196 lines
No EOL
6.6 KiB
PL/PgSQL
196 lines
No EOL
6.6 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_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.planets_updates vu
|
|
USING ( update_id , updtype_id , updtgt_id )
|
|
INNER JOIN verse.planets p
|
|
USING ( name_id )
|
|
LEFT OUTER JOIN battles.battles b
|
|
ON b.location_id = p.name_id AND b.last_tick IS NULL
|
|
WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
|
|
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;
|
|
|
|
SELECT sys.register_update_type( 'Planets' , 'BattleStart' ,
|
|
'Battles are being started.' ,
|
|
'process_battle_start_updates'
|
|
);
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION sys.process_battle_main_updates( c_tick BIGINT )
|
|
RETURNS VOID
|
|
STRICT VOLATILE
|
|
SECURITY INVOKER
|
|
AS $$
|
|
DECLARE
|
|
ttfi INT;
|
|
initi REAL;
|
|
dbonus REAL;
|
|
dmg REAL;
|
|
rdmg REAL;
|
|
rec RECORD;
|
|
a_power BIGINT;
|
|
d_power BIGINT;
|
|
p_power BIGINT;
|
|
bmod REAL;
|
|
a_dmg REAL;
|
|
d_dmg REAL;
|
|
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 )::REAL AS happiness
|
|
FROM sys.updates su
|
|
INNER JOIN verse.planets_updates vu
|
|
USING ( update_id , updtype_id , updtgt_id )
|
|
INNER JOIN verse.planets p
|
|
USING ( 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.update_last = c_tick AND su.update_state = 'PROCESSING'
|
|
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;
|
|
|
|
SELECT sys.register_update_type( 'Planets' , 'BattleCompute' ,
|
|
'In-progress battles are being updated.' ,
|
|
'process_battle_main_updates'
|
|
);
|
|
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION sys.process_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.planets_updates vu
|
|
USING ( update_id , updtype_id , updtgt_id )
|
|
INNER JOIN verse.planets p
|
|
USING ( name_id )
|
|
INNER JOIN battles.battles b
|
|
ON b.location_id = p.name_id AND b.last_tick IS NULL
|
|
WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
|
|
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;
|
|
|
|
SELECT sys.register_update_type( 'Planets' , 'BattleEnd' ,
|
|
'Finished battles are being ended.' ,
|
|
'process_battle_end_updates'
|
|
); |