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.
lwb5/scripts/game/beta5/ticks/hour/library.inc

911 lines
29 KiB
PHP

<?php
//-------------------------------------------------------------------
// "Hour tick": owner change, production, stuck fleets, HS stand-by,
// revolts, wormholes, sales
//-------------------------------------------------------------------
class beta5_ticks_hour_library {
var $idrInc = array();
var $oChange = array();
public function __construct($lib) {
$this->lib = $lib;
$this->game = $this->lib->game;
$this->db = $this->game->db;
$this->main = $this->game->getLib();
$this->bq = $this->game->getLib('beta5/bq');
$this->fleets = $this->game->getLib('beta5/fleet');
$this->msg = $this->game->getLib('beta5/msg');
$this->planets = $this->game->getLib('beta5/planet');
$this->players = $this->game->getLib('beta5/player');
$this->rankings = $this->game->getLib('main/rankings');
$this->rules = $this->game->getLib('beta5/rules');
$this->sales = $this->game->getLib('beta5/sale');
$this->standby = $this->game->getLib('beta5/standby');
}
public function runTick() {
// Planetary events
l::debug("Handling planetary events");
$handledSystems = 0;
do {
$increase = $this->db->safeTransaction(
array($this, 'handleSystemGroup'), $handledSystems
);
$handledSystems += $increase;
} while ($increase > 0);
// Abandon planets
$this->db->safeTransaction(array($this, "handleAbandon"));
// Stuck fleets
$this->db->safeTransaction(array($this, 'unstickFleets'));
// Fleets waiting in hyperspace
$this->db->safeTransaction(array($this, 'hyperspaceStandby'));
// Fleet sales
$this->db->safeTransaction(array($this, 'fleetSales'));
// Update happiness
$this->db->safeTransaction(array($this, 'updateHappiness'));
// Increase inflicted damage points for WHSN'd fleets
if (count($this->idrInc)) {
$this->db->safeTransaction(array($this, 'updateIDR'));
}
// Check victory status on CTF games
if ($this->game->params['victory'] == 2) {
$this->db->safeTransaction(array($this, 'updateCTF'));
}
// Update rankings
$this->db->safeTransaction(array($this->main, 'call'), 'updateRankings');
}
public function handleSystemGroup($startAt) {
$q = $this->db->query("SELECT id,nebula FROM system ORDER BY id ASC LIMIT 5 OFFSET $startAt");
$n = dbCount($q);
while ($r = dbFetchArray($q)) {
$this->handleSystem($r[0], $r[1]);
}
return $n;
}
public function unstickFleets() {
l::debug("Unsticking fleets");
$this->db->query("UPDATE fleet SET can_move = 'Y' WHERE can_move = 'H'");
}
public function hyperspaceStandby() {
$q = $this->db->query("SELECT id,owner,waiting FROM fleet WHERE waiting IS NOT NULL");
$fWait = array();
while ($r = dbFetchArray($q)) {
$fWait[$r[2]] = array($r[0],$r[1]);
}
if (!count($fWait)) {
return;
}
l::debug("Handling hyperspace stand-by");
$q = $this->db->query(
"SELECT * FROM hs_wait WHERE id IN (" . join(',', array_keys($fWait)) . ")"
);
while ($r = dbFetchHash($q)) {
$r['fleet'] = $fWait[$r['id']][0];
$r['player'] = $fWait[$r['id']][1];
$fWait[$r['id']] = $r;
}
$losses = array();
$planets = array();
foreach ($fWait as $fw) {
if ($this->handleWait($fw, &$losses)) {
array_push($planets, $fw['drop_point']);
}
}
foreach ($planets as $planetID) {
$this->planets->call('detectFleets', $planetID);
}
$tm = time();
foreach ($losses as $pid => $locs) {
foreach ($locs as $plid => $fl) {
$pinf = $this->planets->call('byId', $plid);
$hsLosses = array();
foreach ($fl as $f) {
array_push($hsLosses, array(
"p_id" => $plid,
"p_name" => $pinf['name'],
"f_name" => $f[0],
"gaships" => $f[1],
"fighters" => $f[2],
"cruisers" => $f[3],
"bcruisers" => $f[4],
"power" => $f[5]
));
}
$this->msg->call('send', $pid, 'hsloss', $hsLosses);
}
}
$this->fleets->call('sendMoveMessages');
}
public function fleetSales() {
$q = $this->db->query("SELECT id FROM fleet WHERE sale IS NOT NULL");
if (! dbCount($q)) {
return;
}
l::debug("Handling fleet sales");
while ($r = dbFetchArray($q)) {
$f = $this->fleets->call('get', $r[0]);
l::trace("FSALE: found fleet {$r[0]}");
if (!is_null($f['sale_info']['sale']['planet'])) {
l::trace("FSALE({$r[0]}): fleet is bundled with a planet, skipping");
continue;
}
if ($f['sale'] > 0) {
l::debug("FSALE({$f['id']}): fleet isn't ready yet ({$f['sale']}h remaining)");
$this->db->query("UPDATE fleet SET sale=sale-1 WHERE id={$f['id']}");
continue;
}
$q2 = $this->db->query(
"SELECT id,sold_to FROM sale WHERE player={$f['owner']} AND fleet={$f['id']}"
. " AND finalized IS NOT NULL ORDER BY finalized DESC LIMIT 1"
);
list($oid,$to) = dbFetchArray($q2);
l::trace("FSALE({$f['id']}): offer #$oid, buyer #$to");
// Read data required to send the messages
$fps = $this->fleets->call('getPower', $f['owner'], $f['gaships'], $f['fighters'],
$f['cruisers'], $f['bcruisers']);
$fpb = $this->fleets->call('getPower', $to, $f['gaships'], $f['fighters'], $f['cruisers'],
$f['bcruisers']);
l::trace("FSALE({$f['id']}): fps= $fps, fpb= $fpb");
// Send messages
$this->msg->call('send', $f['owner'], 'sale', array(
'f_name' => $f['name'],
'f_power' => $fps,
'pl_id' => $to,
'pl_name' => $this->players->call('getName', $to),
'is_sale' => 'TRUE'
));
$this->msg->call('send', $to, 'sale', array(
'f_name' => $f['name'],
'f_power' => $fpb,
'pl_id' => $f['owner'],
'pl_name' => $this->players->call('getName', $f['owner']),
'is_sale' => 'FALSE'
));
l::trace("FSALE({$f['id']}): messages sent");
// Transfer control
$this->db->query("UPDATE fleet SET sale=NULL,owner=$to WHERE id={$f['id']}");
$this->fleets->call('invCache', $f['id']);
// FIXME: add history
$this->db->query("DELETE FROM sale WHERE id=$oid");
l::debug("FSALE({$f['id']}): control transfered");
}
}
public function updateIDR() {
l::debug("Updating IDR");
$rt = $this->rankings->call('getType', 'p_idr');
$rl = $this->rankings->call('getAll', $rt);
$idr = array();
foreach ($rl as $r) {
$idr[$r['id']] = $r['points'];
}
foreach ($this->idrInc as $n => $inc) {
$idr[$n] += $inc;
}
$idrR = array();
foreach ($idr as $n => $p) {
if (!is_array($idrR[$p])) {
$idrR[$p] = array();
}
array_push($idrR[$p], $n);
}
$this->rankings->call('update', $rt, $idrR);
}
public function updateCTF() {
if (! $this->game->getLib()->call('isFinished')) {
$this->game->getLib('beta5/ctf')->call('checkTargets');
}
}
public function updateHappiness() {
l::debug("Updating planetary happiness");
$q = $this->db->query("SELECT id,owner FROM planet WHERE status=0");
$destroy = array();
while ($r = dbFetchArray($q)) {
$nHap = $this->planets->call('updateHappiness', $r[0]);
// Handle revolts
if ($nHap < 20 && !in_array($r[0], $this->oChange)) {
if (!is_null($r[1]) && is_null($destroy[$r[1]])) {
$destroy[$r[1]] = array();
}
$pDestr = $this->planetRevolt($r[0], $nHap);
if (!is_null($r[1])) {
array_push($destroy[$r[1]], $pDestr);
}
$this->planets->call('updateHappiness', $r[0]);
}
}
// Send damage reports for revolts
$tm = time() + 1;
foreach ($destroy as $player => $plist) {
$report = array();
foreach ($plist as $data) {
array_push($report, array(
"planet" => $data[0],
"pname" => $data[1],
"ifact" => $data[2],
"mfact" => $data[3],
"turrets" => $data[4]
));
}
$this->msg->call('send', $player, 'revdmg', $report);
}
}
private function buildFleets($plId, $ownId, $g, $f, $c, $b) {
if ($g + $f + $c + $b == 0) {
return;
}
$q = $this->db->query("SELECT id FROM fleet WHERE can_move='Y' AND LOWER(name)='no name' AND location=$plId AND owner=$ownId AND sale IS NULL LIMIT 1");
if (dbCount($q)) {
list($id) = dbFetchArray($q);
$this->db->query("UPDATE fleet SET gaships=gaships+$g,fighters=fighters+$f,cruisers=cruisers+$c,bcruisers=bcruisers+$b WHERE id=$id");
} else {
$qs = "INSERT INTO fleet(owner,location,gaships,fighters,cruisers,bcruisers)VALUES($ownId,$plId,$g,$f,$c,$b)";
$this->db->query($qs);
}
}
private function planetBuildQueue($planet, $rules) {
static $types = array('turret', 'gaship', 'fighter', 'cruiser', 'bcruiser');
$units = $rules['mf_productivity'] * $rules['mf_productivity_factor'] * $planet['mfact'];
$cl = $planet['corruption'] / 32000;
if ($cl > .1) {
$units = $units * (1.1 - $cl);
}
$vac = $this->players->call('isOnVacation', $planet['owner']);
if ($vac) {
$units = $units / 4;
}
$prot = $this->players->call('getProtectionLevel', $planet['owner']);
if ($prot) {
$units = $units * 1.15;
}
$units = round($units);
$bq = $this->bq->call('get', $planet['id']);
$prod = array(0, 0, 0, 0, 0);
$move = 0;
while (count($bq) && $units > 0) {
if ($bq[0]['units'] <= $units) {
$units -= $bq[0]['units'];
$prod[$bq[0]['type']] += $bq[0]['quantity'];
$this->db->query("DELETE FROM buildqueue WHERE planet=".$planet['id']." AND bq_order=$move");
$move ++;
array_shift($bq);
} else {
$units += $bq[0]['workunits'];
$wuCost = $rules['workunits_'.$types[$bq[0]['type']]];
$mod = $units % $wuCost;
$nBuild = ($units - $mod) / $wuCost;
$prod[$bq[0]['type']] += $nBuild;
$nQt = $bq[0]['quantity'] - $nBuild;
$this->db->query("UPDATE buildqueue SET quantity=$nQt,workunits=$mod WHERE planet=".$planet['id']." AND bq_order=$move");
$units = 0;
}
}
if ($move) {
$this->bq->call('reorder', $planet['id']);
}
if ($prod[0] > 0) {
$this->db->query("UPDATE planet SET turrets=turrets+".$prod[0]." WHERE id=".$planet['id']);
$tm = time();
$this->db->query("DELETE FROM turhist WHERE $tm-moment>86400");
$this->db->query("INSERT INTO turhist VALUES({$planet['id']},$tm,$prod[0])");
}
$this->buildFleets($planet['id'], $planet['owner'], $prod[1], $prod[2], $prod[3], $prod[4]);
$this->planets->call('updateMilStatus', $planet['id']);
}
private function planetSale(&$planet) {
l::trace("SALE: handling planet {$planet['id']}");
if ($planet['sale'] > 0) {
l::debug("SALE({$planet['id']}): not ready for sale yet ({$planet['sale']}h remaining)");
$this->db->query("UPDATE planet SET sale=sale-1 WHERE id=".$planet['id']);
$q = $this->db->query(
"SELECT fleet FROM sale WHERE player=".$planet['owner']." AND planet=".$planet['id']
. " AND finalized IS NOT NULL ORDER BY finalized DESC LIMIT 1"
);
list($fleet) = dbFetchArray($q);
if (!is_null($fleet)) {
l::trace("SALE({$planet['id']}): fleet $fleet bundled");
$this->db->query("UPDATE fleet SET sale=sale-1 WHERE id=$fleet");
}
} else {
l::trace("SALE({$planet['id']}): running sale code");
$q = $this->db->query(
"SELECT id,sold_to,fleet FROM sale WHERE player=".$planet['owner']." AND planet=".$planet['id']
. " AND finalized IS NOT NULL ORDER BY finalized DESC LIMIT 1"
);
if (!dbCount($q)) {
l::warn("***** BUG: planet {$planet['id']} has sale field set to 0, but no "
. "sales were found");
$this->db->query("UPDATE planet SET sale=NULL WHERE id={$planet['id']}");
return;
}
list($oid,$to,$fleet) = dbFetchArray($q);
l::trace("SALE({$planet['id']}): offer #$oid, sold to player #$to (bundled fleet: "
. (is_null($fleet) ? "none" : "#$fleet") . ")");
// Read data required to send the messages
$tn = addslashes($this->players->call('getName', $to));
$fn = addslashes($this->players->call('getName', $planet['owner']));
l::trace("SALE({$planet['id']}): original owner '$tn', new owner '$fn'");
if (is_null($fleet)) {
$fqs = $fqb = "NULL,NULL";
} else {
$q = $this->db->query("SELECT * FROM fleet WHERE id=$fleet");
$fd = dbFetchHash($q);
$fps = $this->fleets->call('getPower', $fd['owner'], $fd['gaships'], $fd['fighters'], $fd['cruisers'], $fd['bcruisers']);
$fpb = $this->fleets->call('getPower', $to, $fd['gaships'], $fd['fighters'], $fd['cruisers'], $fd['bcruisers']);
$fqs = "'" . addslashes($fd['name']) . "',$fps";
$fqb = "'" . addslashes($fd['name']) . "',$fpb";
}
l::trace("SALE({$planet['id']}): fqs: $fqs");
l::trace("SALE({$planet['id']}): fqb: $fqb");
// Send messages
// FIXME: message API
$tm = time();
$this->db->query("INSERT INTO message(player,sent_on,mtype,ftype,is_new) VALUES({$planet['owner']},$tm,'sale','INT',TRUE)");
$q = $this->db->query("SELECT id FROM message WHERE player={$planet['owner']} AND sent_on=$tm AND mtype='sale' ORDER BY id DESC LIMIT 1");
list($mid) = dbFetchArray($q);
$this->db->query("INSERT INTO msg_sale VALUES($mid,{$planet['id']},'".addslashes($planet['name'])."',$fqs,$to,'$tn',TRUE)");
$this->db->query("INSERT INTO message(player,sent_on,mtype,ftype,is_new) VALUES($to,$tm,'sale','INT',TRUE)");
$q = $this->db->query("SELECT id FROM message WHERE player=$to AND sent_on=$tm AND mtype='sale' ORDER BY id DESC LIMIT 1");
list($mid) = dbFetchArray($q);
$this->db->query("INSERT INTO msg_sale VALUES($mid,{$planet['id']},'".addslashes($planet['name'])."',$fqb,{$planet['owner']},'$fn',FALSE)");
l::trace("SALE({$planet['id']}): messages sent");
// Check for vacation mode
$vac = $this->players->call('isOnVacation', $to);
if ($vac) {
$q = $this->db->query("SELECT COUNT(*) FROM fleet WHERE location={$planet['id']} AND attacking");
list($c) = dbFetchArray();
if ($c) {
$vm = 'PEND';
} else {
$vm = 'YES';
}
} else {
$vm = 'NO';
}
l::trace("SALE({$planet['id']}): vacation mode for target player: $vm");
// Sell the planet
$this->players->call('losePlanet', $planet['owner'], $planet['id']);
$this->players->call('takePlanet', $to, $planet['id']);
$nVal = $this->planets->call('ownerChange', $planet['id'], $to, $vm);
if ($nVal > 0) {
$planet['max_pop'] = $nVal;
}
$this->db->query("UPDATE player SET bh_unhappiness=bh_unhappiness+1 WHERE id={$planet['owner']} AND bh_unhappiness<15");
if (!is_null($fleet)) {
$this->db->query("UPDATE fleet SET sale=NULL,owner=$to WHERE id=$fleet");
}
$planet['owner'] = $to;
// FIXME: add history
$this->db->query("DELETE FROM sale WHERE id=$oid");
l::debug("SALE({$planet['id']}) completed");
}
}
private function whsnPreparation(&$planet) {
if ($planet['bh_prep'] > 0) {
// WHSN is not ready yet
$this->db->query("UPDATE planet SET bh_prep=bh_prep-1 WHERE id=".$planet['id']);
$this->db->query("UPDATE player SET bh_unhappiness=bh_unhappiness+1 WHERE id={$planet['owner']} AND bh_unhappiness<15");
return false;
}
// Get fleet statistics to send messages
$players = array(
$planet['owner'] => array(
"was_owner" => dbBool(true),
"attacking" => false,
"power" => 0,
"fleets" => array(),
)
);
$q = $this->db->query("SELECT * FROM fleet WHERE location=".$planet['id']);
$aPower = $dPower = 0;
while ($r = dbFetchHash($q)) {
if (is_null($players[$r['owner']])) {
$players[$r['owner']] = array(
"was_owner" => dbBool(false),
"attacking" => ($r['attacking'] == 't'),
"power" => 0,
"fleets" => array(),
);
}
$f = array(
"name" => $r['name'],
"gaships" => $r['gaships'],
"fighters" => $r['fighters'],
"cruisers" => $r['cruisers'],
"bcruisers" => $r['bcruisers'],
);
$power = $this->fleets->call('getPower', $r['owner'], $r['gaships'], $r['fighters'], $r['cruisers'], $r['bcruisers']);
$players[$r['owner']]["power"] += ($f['power'] = $power);
array_push($players[$r['owner']]['fleets'], $f);
if ($players[$r['owner']]['attacking']) {
$aPower += $power;
} else {
$dPower += $power;
}
// Cancel fleet sales
$qfs = $this->db->query("SELECT id,player,finalized FROM sale WHERE fleet={$r['id']}");
if (dbCount($qfs)) {
list($saleId, $seller, $saleFin) = dbFetchArray($qfs);
if (is_null($saleFin)) {
$ga = "cancel";
} else {
$ga = "cancelTransfer";
}
$this->sales->call($ga, $seller, $saleId);
}
}
// Send the messages
// FIXME: message API
$tm = time();
foreach ($players as $pId => $data) {
$this->db->query("INSERT INTO message(player,sent_on,mtype,ftype,is_new) VALUES($pId,$tm,'whsn','INT',TRUE)");
$q = $this->db->query("SELECT id FROM message WHERE player=$pId AND sent_on=$tm AND mtype='whsn' ORDER BY id DESC LIMIT 1");
list($mid) = dbFetchArray($q);
if ($data['attacking']) {
$pow = $aPower - $data['power'];
$fPower = $pow; $ePower = $dPower;
} else {
$pow = $dPower - $data['power'];
$fPower = $pow; $ePower = $aPower;
}
$this->db->query("INSERT INTO msg_whsn VALUES($mid,{$planet['id']},'"
. addslashes($planet['name']) . "'," . $data['was_owner']
. ",$fPower,$ePower)");
foreach ($data['fleets'] as $f)
$this->db->query("INSERT INTO whsn_fleet VALUES($mid,'" . addslashes($f['name'])
. "',{$f['gaships']},{$f['fighters']},{$f['cruisers']},"
. "{$f['bcruisers']},{$f['power']})");
}
// Check for IDR points
$pow = $aPower - $dPower;
if ($pow > 0) {
$pn = $this->players->call('getName', $planet['owner']);
if (is_null($this->idrInc[$pn])) {
$this->idrInc[$pn] = $pow;
} else {
$this->idrInc[$pn] += $pow;
}
}
// Destroy the planet and anything around it
$this->players->call('losePlanet', $planet['owner'], $planet['id']);
$this->bq->call('flush', $planet['id']);
$this->db->query("DELETE FROM fleet WHERE location=".$planet['id']);
do {
$rn = strtoupper(substr(md5(uniqid(rand())), 0, 10));
$q = $this->db->query("SELECT id FROM planet WHERE name='PR-[$rn]'");
} while(dbCount($q));
$this->db->query(
"UPDATE planet "
. "SET pop = 0, max_pop = 0, happiness = 0, mfact = 0, ifact = 0, beacon = 0, "
. "built_probe = FALSE, probe_policy = NULL, bh_prep = NULL, owner = NULL, "
. "sale = NULL, status = 1, bh_unhappiness = 0, vacation = 'NO', "
. "name = 'PR-[$rn]', abandon = NULL "
. "WHERE id = {$planet['id']}"
);
$this->db->query(
"UPDATE planet "
. "SET bh_unhappiness = bh_unhappiness + 4 "
. "WHERE system={$planet['system']} AND id <> {$planet['id']} "
. "AND status = 0 AND bh_unhappiness < 12"
);
$this->db->query("DELETE FROM planet_abandon_time WHERE id = {$planet['id']}");
// Raise the empire-wide unhappiness for the planet's owner
$q = $this->db->query("SELECT bh_unhappiness FROM player WHERE id={$planet['owner']}");
list($bhu) = dbFetchArray($q);
$nuh = max($bhu + 4, 15);
$this->db->query("UPDATE player SET bh_unhappiness=$nuh WHERE id={$planet['owner']}");
return true;
}
private function planetTaken(&$planet) {
if ($planet['turrets'] > 0) {
return false;
}
// Check if the planet was in vacation mode before the attacking ships arrived
// If it was, it can't be taken
if ($planet['vacation'] == 'YES ') {
return false;
}
// List fleets at location
$q = $this->db->query("SELECT owner,gaships,attacking,time_spent FROM fleet WHERE location={$planet['id']}");
$players = array();
while ($r = dbFetchArray($q)) {
// If there are defending fleets, forget it
if ($r[2] == 'f') {
if ($r[3] > 5) {
return false;
}
continue;
} elseif ($r[3] < 15) {
continue;
}
// Count GA Ships per player
$players[$r[0]] += $r[1];
}
// Get the highest GA efficiency
$maxGAPower = $maxGAPlayer = -1;
foreach ($players as $id => $gas) {
$rules = $this->rules->call('get', $id);
$gaPower = $gas * $rules['gaship_pop'];
if ($gaPower > $maxGAPower) {
$maxGAPower = $gaPower;
$maxGAPlayer = $id;
}
}
// Check whether the player can actually take the planet
if ($maxGAPlayer == -1 || $maxGAPower < $planet['pop']) {
return false;
}
// A player has taken control on the planet
if (!is_null($planet['owner'])) {
// If the planet had an owner, flush build queue and cancel sales
$this->bq->call('flush', $planet['id']);
$q = $this->db->query("SELECT id,finalized,sold_to FROM sale WHERE planet={$planet['id']}");
if (dbCount($q)) {
// Cancel sale
list($sId,$fin,$to) = dbFetchArray($q);
if (is_null($fin)) {
$ga = 'cancel';
} else {
$ga = 'cancelTransfer';
// Send message
// FIXME ...
$tm = time();
$this->db->query("INSERT INTO message(player,sent_on,mtype,ftype,is_new) VALUES($to,$tm,'plsc','INT',TRUE)");
$q = $this->db->query("SELECT id FROM message WHERE player=$to AND sent_on=$tm AND mtype='plsc' ORDER BY id DESC LIMIT 1");
list($mid) = dbFetchArray($q);
$this->db->query("INSERT INTO msg_plsc VALUES($mid,{$planet['owner']},$maxGAPlayer,{$planet['id']},'"
. addslashes($planet['name']) . "')");
}
$this->sales->call($ga, $planet['owner'], $sId);
}
$rqs = ",renamed=".time();
} else {
$rqs = "";
}
// Check for vacation mode
$vm = $this->players->call('isOnVacation', $maxGAPlayer) ? 'YES' : 'NO';
// Transfer control
$this->players->call('losePlanet', $planet['owner'], $planet['id']);
$this->players->call('takePlanet', $maxGAPlayer, $planet['id']);
$nVal = $this->planets->call('ownerChange', $planet['id'], $maxGAPlayer, $vm);
if ($nVal > 0) {
$planet['max_pop'] = $nVal;
}
// Update a potential abandon log entry
$tm = time();
$this->db->query("UPDATE abandon_log SET retake_owner=$maxGAPlayer,retake_time=$tm WHERE planet={$planet['id']} AND retake_time IS NULL");
// Get the list of the new owner's enemies
$q = $this->db->query("SELECT enemy FROM enemy_player WHERE player=$maxGAPlayer");
$enemies = array();
while ($r = dbFetchArray($q)) {
array_push($enemies, $r[0]);
}
$q = $this->db->query("SELECT p.id FROM player p,enemy_alliance e WHERE p.alliance=e.alliance AND p.a_status='IN' AND e.player=$maxGAPlayer");
while ($r = dbFetchArray($q)) {
array_push($enemies, $r[0]);
}
$enemies = array_unique($enemies);
// Switch attacking fleets to defense unless they belong to an enemy
$qs = "UPDATE fleet SET attacking=FALSE,can_move='Y' WHERE location={$planet['id']}";
if (count($enemies)) {
$qs .= " AND owner NOT IN (".join(',',$enemies).")";
}
$this->db->query($qs);
// Send messages to the former owner and the new owner
$pn = addslashes($planet['name']);
$noMsg = array($maxGAPlayer);
$mData = array(
'p_id' => $planet['id'],
'p_name' => $planet['name'],
'owner' => $planet['owner'],
'status' => 'TAKE'
);
$this->msg->call('send', $maxGAPlayer, 'ownerch', $mData);
$mData['owner'] = $maxGAPlayer;
if (!is_null($planet['owner'])) {
$mData['status'] = 'LOSE';
array_push($noMsg, $pid = $planet['owner']);
$this->msg->call('send', $pid, 'ownerch', $mData);
}
// Get the list of other players and send them a message as well
$q2 = $this->db->query("SELECT DISTINCT owner FROM fleet WHERE location={$planet['id']} AND owner NOT IN (" . join(',', $noMsg) . ")");
$mData['status'] = 'VIEW';
while ($r = dbFetchArray($q2)) {
$this->msg->call('send', $r[0], 'ownerch', $mData);
}
return true;
}
private function handlePlanet($planet) {
// WHSN preparation
if (!is_null($planet['bh_prep']) && $this->whsnPreparation($planet)) {
return false;
}
// Check for owner change
if ($this->planetTaken($planet)) {
$this->planets->call('updateMilStatus', $planet['id']);
return true;
}
// Planet sale
if (!is_null($planet['sale'])) {
$this->planetSale($planet);
}
// No build queues or revolts on neutral planets
if (is_null($planet['owner'])) {
return false;
}
// Load owner rules
$rules = $this->rules->call('get', $planet['owner']);
// Build queue
$this->planetBuildQueue($planet, $rules);
return false;
}
private function handleSystem($sid, $neb) {
if ($neb) {
return;
}
l::trace("Handling system #$sid");
$q = $this->db->query("SELECT * FROM planet WHERE system=$sid");
while ($planet = dbFetchHash($q)) {
if ($neb || $planet['status'] == 1) {
continue;
}
if ($this->handlePlanet($planet)) {
array_push($this->oChange, $planet['id']);
}
}
}
private function handleWait($fw, &$losses) {
$canDestroy = $this->standby->call('canDestroy', $fw['drop_point'], $fw['player']);
// If we can destroy fleets, find out whether we must do so
if ($canDestroy) {
$prob = $this->standby->call('getLossProb', $fw['time_spent']);
l::debug("HSSB({$fw['fleet']}): at planet #{$fw['drop_point']}, loss probability = "
. "$prob (time spent: {$fw['time_spent']}h)");
if (rand(1,100) <= $prob) {
l::debug("HSSB({$fw['fleet']}): applying fleet losses");
// Destroy a part of the fleet
$amount = rand(5,round(10+$prob/10));
$fleet = $this->fleets->call('get', $fw['fleet']);
$rules = $this->rules->call('get', $fw['player']);
$fcLoss = ceil(($fleet['cruisers'] / 100) * $amount);
$fbLoss = ceil(($fleet['bcruisers'] / 100) * $amount);
l::trace("HSSB({$fw['fleet']}): cruisers lost: $fcLoss; battle cruisers lost: $fbLoss");
// Compute the amount of transported ships to be destroyed
$gaSpace = $fleet['gaships'] * $rules['gaship_space'];
$fSpace = $fleet['fighters'] * $rules['fighter_space'];
$tSpace = $gaSpace + $fSpace;
if ($tSpace > 0) {
$haul = $fleet['cruisers'] * $rules['cruiser_haul']
+ $fleet['bcruisers'] * $rules['bcruiser_haul'];
$haulUsed = $tSpace / $haul;
$lHaul = $fcLoss * $rules['cruiser_haul'] + $fbLoss * $rules['bcruiser_haul'];
$lSpace = $haulUsed * $lHaul;
$gaLSpace = ($lSpace / $tSpace) * $gaSpace;
$fLSpace = ($lSpace / $tSpace) * $fSpace;
$fgLoss = min($fleet['gaships'], ceil($gaLSpace / $rules['gaship_space']));
$ffLoss = min($fleet['fighters'], ceil($fLSpace / $rules['fighter_space']));
} else {
$fgLoss = $ffLoss = 0;
}
l::trace("HSSB({$fw['fleet']}): fighters lost: $ffLoss; GA ships lost: $fgLoss");
// Add details to the $losses array
if (!is_array($losses[$fleet['owner']])) {
$losses[$fleet['owner']] = array();
}
if (!is_array($losses[$fleet['owner']][$fw['drop_point']])) {
$losses[$fleet['owner']][$fw['drop_point']] = array();
}
array_push($losses[$fleet['owner']][$fw['drop_point']], array(
addslashes($fleet['name']), $fgLoss, $ffLoss, $fcLoss, $fbLoss,
$this->fleets->call('getPower', $fleet['owner'], $fgLoss, $ffLoss,
$fcLoss, $fbLoss)
));
if ($fcLoss == $fleet['cruisers'] && $fbLoss == $fleet['bcruisers']
&& $ffLoss == $fleet['fighters'] && $fgLoss == $fleet['gaships']) {
$this->fleets->call('disband',$fw['fleet'],true);
l::trace("HSSB({$fw['fleet']}): fleet disbanded");
} elseif ($fcLoss + $fbLoss + $ffLoss + $fgLoss > 0) {
$this->db->query(
"UPDATE fleet SET gaships = gaships - $fgLoss, "
. "fighters = fighters - $ffLoss, "
. "cruisers = cruisers - $fcLoss, "
. "bcruisers = bcruisers - $fbLoss "
. "WHERE id = {$fw['fleet']}"
);
}
}
}
if ($fw['time_left'] == 1) {
// Fleet arrival
$this->fleets->call('arrival', $fw['fleet'], $fw['drop_point'], $fw['origin']);
// Destroy wait entry
$this->db->query("DELETE FROM hs_wait WHERE id={$fw['id']}");
} else {
// Update wait entry
$this->db->query(
"UPDATE hs_wait SET time_left = time_left - 1, time_spent = time_spent + 1 "
. "WHERE id={$fw['id']}"
);
}
return !($fw['time_left'] == 1);
}
private function planetRevolt($id, $hap) {
$q = $this->db->query("SELECT name,ifact,mfact,turrets FROM planet WHERE id=$id");
list($n, $if, $mf, $tr) = dbFetchArray($q);
$pdestr = 30 - $hap;
$pdestr += rand(-floor($pdestr/2),floor($pdestr/2));
$pdestr /= 150;
$dInd = round($if * $pdestr);
$dMil = round($mf * $pdestr);
$dTur = round($tr * $pdestr);
if ($dInd + $dMil + $dTur != 0) {
$this->db->query(
"UPDATE planet SET ifact = ifact - $dInd, mfact = mfact - $dMil, "
. "turrets = turrets - $dTur "
. "WHERE id = $id"
);
}
return array($id, $n, $dInd, $dMil, $dTur);
}
public function handleAbandon() {
l::debug("Handling planets being abandonned");
// Decrease time to abandon
$this->db->query("UPDATE planet SET abandon = abandon - 1 WHERE abandon IS NOT NULL");
// Get the list of planets to abandon at this tick
$q = $this->db->query("SELECT id, owner FROM planet WHERE abandon = 0");
$oList = array();
while ($r = dbFetchArray($q)) {
if (is_null($r[1])) {
l::warn("****** BUG: planet {$r[0]} is being abandoned and has no owner");
continue;
}
$this->abandonPlanet($r[0], $r[1]);
if (!is_array($oList[$r[1]])) {
$oList[$r[1]] = array();
}
array_push($oList[$r[1]], $r[0]);
}
foreach ($oList as $pid => $aPl) {
// Send the message
$message = array();
foreach ($aPl as $plId) {
$planet = $this->planets->call('byId', $plId);
array_push($message, array("p_id" => $plId, "p_name" => $planet['name']));
}
$this->msg->call('send', $pid, 'abandon', $message);
// Update other planets' happiness
$this->players->call('updateHappiness', $pid);
}
}
private function abandonPlanet($pid, $oid) {
// Insert log entry
$this->db->query(
"INSERT INTO abandon_log(planet,abandon_time,former_owner) "
. "VALUES ($pid," . time() . ",$oid)"
);
// Make the planet neutral
$this->planets->call('ownerChange', $pid);
$this->players->call('losePlanet', $oid, $pid);
}
}
?>