-- 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 DOUBLE PRECISION; dest_work DOUBLE PRECISION; dest_rec DOUBLE PRECISION; cur_empire INT; cur_cash DOUBLE PRECISION; cur_planet INT; p_finished BOOLEAN; cur_wus DOUBLE PRECISION; cur_acc_c DOUBLE PRECISION; n_found INT; n_removed INT; i_work DOUBLE PRECISION; i_cost DOUBLE PRECISION; can_do DOUBLE PRECISION; 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 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.updates vu ON vu.update_id = su.id INNER JOIN verse.planets p ON vu.planet_id = p.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.last_tick = c_tick AND su.status = 'PROCESSING' AND su.gu_type = 'PLANET_CONSTRUCTION' 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 , 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;