-- 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 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.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;