This repository has been archived on 2025-01-04. You can view files and clone it, but cannot push or open issues or pull requests.
lwb6/legacyworlds-server-data/db-structure/parts/050-updates/080-planet-construction.sql
Emmanuel BENOîT 56eddcc4f0 Game updates improvements
* 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
2012-02-03 16:25:03 +01:00

223 lines
No EOL
6.5 KiB
PL/PgSQL

-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Game updates - buildings construction and destruction
--
-- Copyright(C) 2004-2010, DeepClone Development
-- --------------------------------------------------------
CREATE OR REPLACE FUNCTION sys.process_planet_construction_updates( c_tick BIGINT )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $$
DECLARE
rec RECORD;
wu_per_pop REAL;
dest_work REAL;
dest_rec REAL;
cur_empire INT;
cur_cash REAL;
cur_planet INT;
p_finished BOOLEAN;
cur_wus REAL;
cur_acc_c REAL;
n_found INT;
n_removed INT;
i_work REAL;
i_cost REAL;
can_do REAL;
must_do INT;
BEGIN
-- Get constants
wu_per_pop := sys.get_constant( 'game.work.wuPerPopUnit' );
dest_work := sys.get_constant( 'game.work.destructionWork' );
dest_rec := - sys.get_constant( 'game.work.destructionRecovery' );
-- Enter update loop
cur_empire := NULL;
cur_planet := NULL;
FOR rec IN SELECT p.name_id AS id , p.population AS pop ,
( ph.current / p.population )::REAL AS happiness ,
e.name_id AS owner , e.cash AS cash ,
q.money AS acc_cash , q.work AS acc_work ,
qi.queue_order AS qorder , qi.amount AS amount ,
qi.destroy AS destroy , qi.building_id AS building ,
b.work AS req_work , b.cost AS req_cost
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 emp.planets ep ON ep.planet_id = p.name_id
INNER JOIN emp.empires e ON e.name_id = ep.empire_id
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id
INNER JOIN verse.bld_items qi ON qi.queue_id = q.planet_id
INNER JOIN tech.buildables b ON b.name_id = qi.building_id
INNER JOIN naming.empire_names en ON en.id = e.name_id
LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id
WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
AND ( v.account_id IS NULL OR v.status <> 'PROCESSED' )
ORDER BY e.name_id , p.name_id , qi.queue_order
FOR UPDATE OF p , e , q , qi
LOOP
-- Update accumulated work and money for the previous planet
IF cur_planet IS NOT NULL AND cur_planet <> rec.id THEN
IF n_found = n_removed THEN
cur_wus := 0;
cur_acc_c := 0;
PERFORM events.empty_queue_events( cur_empire , cur_planet , FALSE , c_tick );
END IF;
UPDATE verse.bld_queues
SET money = cur_acc_c , work = cur_wus
WHERE planet_id = cur_planet;
cur_cash := cur_cash - cur_acc_c;
IF cur_cash < 0 THEN
cur_cash := 0;
END IF;
cur_planet := NULL;
END IF;
-- Update cash of the previous empire
IF cur_empire IS NOT NULL AND cur_empire <> rec.owner
THEN
UPDATE emp.empires SET cash = cur_cash
WHERE name_id = cur_empire;
cur_empire := NULL;
END IF;
-- If this is the first record or if the empire changed...
IF cur_empire IS NULL THEN
cur_empire := rec.owner;
cur_cash := rec.cash;
END IF;
-- If this is the first record or if the planet changed...
IF cur_planet IS NULL THEN
cur_planet := rec.id;
cur_cash := cur_cash + rec.acc_cash;
cur_wus := rec.acc_work + verse.adjust_production(
( rec.pop * wu_per_pop )::REAL ,
rec.happiness
);
n_found := 1;
n_removed := 0;
cur_acc_c := 0;
p_finished := FALSE;
ELSE
n_found := n_found + 1;
END IF;
-- If we're done updating this planet but there were more items...
IF p_finished THEN
IF n_removed > 0 THEN
UPDATE verse.bld_items
SET queue_order = rec.qorder - n_removed
WHERE queue_order = rec.qorder AND queue_id = rec.id;
END IF;
CONTINUE;
END IF;
-- Compute the actual cost and required work of the item
i_cost := rec.req_cost * ( CASE WHEN rec.destroy THEN dest_rec ELSE 1.0 END );
i_work := rec.req_work * ( CASE WHEN rec.destroy THEN dest_work ELSE 1.0 END );
-- Compute how many items can be completed
can_do := cur_wus / i_work;
IF i_cost > 0 AND cur_cash / i_cost < can_do THEN
can_do := cur_cash / i_cost;
cur_wus := i_work * can_do;
END IF;
-- If we can't build anything at this point...
IF can_do < 1 THEN
-- Set accumulated cash
IF i_cost > 0 THEN
cur_acc_c := can_do * i_cost;
END IF;
-- Still update queue item if some items were removed
IF n_removed > 0 THEN
UPDATE verse.bld_items
SET queue_order = rec.qorder - n_removed
WHERE queue_order = rec.qorder AND queue_id = rec.id;
END IF;
-- Done with this planet
p_finished := TRUE;
CONTINUE;
END IF;
-- Compute how many actual items can be built
must_do := floor( can_do );
IF must_do >= rec.amount THEN
must_do := rec.amount;
can_do := 0;
n_removed := n_removed + 1;
END IF;
-- Handle construction / destruction
IF rec.destroy THEN
must_do := verse.do_destroy_buildings( rec.id , rec.building , must_do );
PERFORM battles.remove_buildings( rec.id , rec.building , must_do , FALSE , c_tick + 1 );
ELSE
PERFORM verse.do_construct_buildings( rec.id , rec.building , must_do );
PERFORM battles.add_buildings( rec.id , rec.building , must_do , c_tick + 1 );
END IF;
cur_cash := cur_cash - must_do * i_cost;
cur_wus := cur_wus - must_do * i_work;
-- Check whether we're done with this queue
IF rec.qorder < n_removed THEN
-- Delete queue item
DELETE FROM verse.bld_items
WHERE queue_order = rec.qorder AND queue_id = rec.id;
ELSE
-- Update queue item
UPDATE verse.bld_items
SET queue_order = queue_order - n_removed ,
amount = amount - floor( can_do )
WHERE queue_order = rec.qorder AND queue_id = rec.id;
-- Set accumulated cash
IF i_cost > 0 THEN
cur_acc_c := ( can_do - floor( can_do ) ) * i_cost;
END IF;
p_finished := TRUE;
END IF;
END LOOP;
-- If a planet was being procesed, update it and the empire
IF cur_planet IS NOT NULL THEN
IF n_found = n_removed THEN
cur_wus := 0;
cur_acc_c := 0;
PERFORM events.empty_queue_events( cur_empire , cur_planet , FALSE , c_tick );
END IF;
UPDATE verse.bld_queues
SET money = cur_acc_c , work = cur_wus
WHERE planet_id = cur_planet;
cur_cash := cur_cash - cur_acc_c;
IF cur_cash < 0 THEN
cur_cash := 0;
END IF;
UPDATE emp.empires SET cash = cur_cash
WHERE name_id = cur_empire;
cur_empire := NULL;
END IF;
END;
$$ LANGUAGE plpgsql;
SELECT sys.register_update_type( 'Planets' , 'CivilianConstruction' ,
'Civilian build queues are being processed.' ,
'process_planet_construction_updates'
);