十九、攻擊任務(MissionCaseAttack.php)
按照艦隊任務的編號,排在第一個的就是攻擊任務。這個代碼很長,看的時候要有耐心。
好在引用的內容並不是很多,並且給出了詳細的注釋,讀者不會暈頭轉向。
function MissionCaseAttack ($FleetRow)
{
global $user, $phpEx, $xnova_root_path, $pricelist, $lang, $resource, $CombatCaps;
// 在艦隊的記錄中,fleet_start_time代表的不是出發時間,而是到達目的地時間
// 代表出發時間的是start_time
// 此外還有fleet_end_time 這個是回到家的時間
// fleet_end_stay 這個是結束逗留的時間(聯合防御和遠征任務會用到)
// 所以下面這個判斷的意思是“艦隊到達了目的地”,而不是“艦隊起飛了”
if ($FleetRow['fleet_start_time'] <= time()) {
// fleet_mess是用來記錄艦隊的狀態的,基本可以理解為是在前進途中還是返航途中
// 但感覺利用得並不好,如果只有兩個狀態,可以用true 和 false來記錄
// 所以我把它設為了0,1,2三個狀態,對於需要停留的任務,停留時就處於第三個狀態
if ($FleetRow['fleet_mess'] == 0) {
// ↓↓ 這個判斷是試探存放戰斗數據的文件是否存在
// 如果文件不存在,就中斷操作,提示聯系管理員
if (!isset($CombatCaps[202]['sd'])) {
message("<span >" . $lang['sys_no_vars'] . "</span>", $lang['sys_error'], "fleet." . $phpEx, 2);
}
// ↓↓ 開始是一系列的數據庫查詢,取得攻防雙方的艦隊數量和科技等級
// 根據艦隊信息取得防守方星球數據
$QryTargetPlanet = "SELECT * FROM {{table}} ";
$QryTargetPlanet .= "WHERE ";
$QryTargetPlanet .= "`galaxy` = '" . $FleetRow['fleet_end_galaxy'] . "' AND ";
$QryTargetPlanet .= "`system` = '" . $FleetRow['fleet_end_system'] . "' AND ";
$QryTargetPlanet .= "`planet` = '" . $FleetRow['fleet_end_planet'] . "' AND ";
$QryTargetPlanet .= "`planet_type` = '" . $FleetRow['fleet_end_type'] . "';";
$TargetPlanet = doquery($QryTargetPlanet, 'planets', true);
$TargetUserID = $TargetPlanet['id_owner'];
// 根據艦隊信息取得攻擊方信息
$QryCurrentUser = "SELECT * FROM {{table}} ";
$QryCurrentUser .= "WHERE ";
$QryCurrentUser .= "`id` = '" . $FleetRow['fleet_owner'] . "';";
$CurrentUser = doquery($QryCurrentUser , 'users', true);
$CurrentUserID = $CurrentUser['id'];
// 由星球數據取得目標星球的所有者的信息
$QryTargetUser = "SELECT * FROM {{table}} ";
$QryTargetUser .= "WHERE ";
$QryTargetUser .= "`id` = '" . $TargetUserID . "';";
$TargetUser = doquery($QryTargetUser, 'users', true);
// 然後取得雙方的科技信息
// 其實下面這兩個完全可以與上面兩個查詢整到一起
$QryTargetTech = "SELECT ";
$QryTargetTech .= "`military_tech`, `defence_tech`, `shield_tech` ";
$QryTargetTech .= "FROM {{table}} ";
$QryTargetTech .= "WHERE ";
$QryTargetTech .= "`id` = '" . $TargetUserID . "';";
$TargetTechno = doquery($QryTargetTech, 'users', true);
$QryCurrentTech = "SELECT ";
$QryCurrentTech .= "`military_tech`, `defence_tech`, `shield_tech` ";
$QryCurrentTech .= "FROM {{table}} ";
$QryCurrentTech .= "WHERE ";
$QryCurrentTech .= "`id` = '" . $CurrentUserID . "';";
$CurrentTechno = doquery($QryCurrentTech, 'users', true);
// ↑↑ 如果有其他的能影響艦隊三圍的項目(比如指揮官等),也應該在這裡一並取出來
// 生成防守方的艦隊(防御)
// 如果考慮聯合防御,在上面還應該把這個星球上聯合防御的艦隊提取出來
// 然後一起計算數量和科技水平
for ($SetItem = 200; $SetItem 0) {
$TargetSet[$SetItem]['count'] = $TargetPlanet[$resource[$SetItem]];
}
}
// 生成攻擊方的艦隊,也是用數組存放。'fleet_array'是不能直接拿來用的
// 這個字段的結構是 編號,數量;編號,數量; ……
// 所以使用時需要用兩次explode把它打散然後存進數組
$TheFleet = explode(";", $FleetRow['fleet_array']);
foreach($TheFleet as $a => $b) {
if ($b != '') {
$a = explode(",", $b);
$CurrentSet[$a[0]]['count'] = $a[1];
}
}
// 包含進戰斗引擎,ready to fight
include_once($xnova_root_path . 'includes/ataki.' . $phpEx);
// 在輸入信息之前采集時間
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
// 將雙方艦隊和科技輸入戰斗引擎,並用$walka來記錄輸出結果
$walka = walka($CurrentSet, $TargetSet, $CurrentTechno, $TargetTechno);
// 再采集時間,得到戰斗過程所用的時間
// 也就是“戰斗報告產生於 x.xxxxxxxxxx 秒”的由來
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
// 分別用一個單獨的數組來記錄攻擊方的剩余艦隊信息、
$CurrentSet = $walka["atakujacy"];
// ……防守方的艦隊信息、
$TargetSet = $walka["wrog"];
// ……戰斗的勝負結果、
$FleetResult = $walka["wygrana"];
// ……每一輪的詳細情況、
$dane_do_rw = $walka["dane_do_rw"];
// 以及雙方的損失和廢墟情況
$zlom = $walka["zlom"];
// 計算攻擊方剩下的單位,順便把裝載量也一並計算進去了
$FleetArray = "";
$FleetAmount = 0;
$FleetStorage = 0;
foreach ($CurrentSet as $Ship => $Count) {
$FleetStorage += $pricelist[$Ship]["capacity"] * $Count['count'];
// 用$FleetArray記載艦隊情況,轉換成數據庫裡字段的格式,准備“入庫”
$FleetArray .= $Ship . "," . $Count['count'] . ";";
$FleetAmount += $Count['count'];
}
$FleetStorage -= $FleetRow["fleet_resource_metal"];
$FleetStorage -= $FleetRow["fleet_resource_crystal"];
$FleetStorage -= $FleetRow["fleet_resource_deuterium"];
// 計算防守星球戰後的情況
$TargetPlanetUpd = "";
if (!is_null($TargetSet)) {
foreach($TargetSet as $Ship => $Count) {
$TargetPlanetUpd .= "`" . $resource[$Ship] . "` = '" . $Count['count'] . "', ";
}
}
// 如果戰斗結果為攻擊方獲勝,則開始計算掠奪資源的情況 ↓↓
// 這裡可以include進PlanetResourceUpdate.php,在掠奪之前先更新目標星球的資源
$Mining['metal'] = 0;
$Mining['crystal'] = 0;
$Mining['deuter'] = 0;
if ($FleetResult == "a") {
if ($FleetStorage > 0) {
$metal = $TargetPlanet['metal'] / 2;
$crystal = $TargetPlanet['crystal'] / 2;
$deuter = $TargetPlanet["deuterium"] / 2;
if (($metal) > $FleetStorage / 3) {
$Mining['metal'] = $FleetStorage / 3;
$FleetStorage = $FleetStorage - $Mining['metal'];
} else {
$Mining['metal'] = $metal;
$FleetStorage = $FleetStorage - $Mining['metal'];
}
if (($crystal) > $FleetStorage / 2) {
$Mining['crystal'] = $FleetStorage / 2;
$FleetStorage = $FleetStorage - $Mining['crystal'];
} else {
$Mining['crystal'] = $crystal;
$FleetStorage = $FleetStorage - $Mining['crystal'];
}
if (($deuter) > $FleetStorage) {
$Mining['deuter'] = $FleetStorage;
$FleetStorage = $FleetStorage - $Mining['deuter'];
} else {
$Mining['deuter'] = $deuter;
$FleetStorage = $FleetStorage - $Mining['deuter'];
}
}
}
// ↑↑ 到這裡為止就計算結束了,但如果星球上金屬巨多,但晶體和重氫幾乎沒有
// 那就會出現裝了1/3倉的金屬,剩下2/3倉全都空著
// 所以可以考慮自己把掠奪方法完善一下,也不是很難
$Mining['metal'] = round($Mining['metal']);
$Mining['crystal'] = round($Mining['crystal']);
$Mining['deuter'] = round($Mining['deuter']);
// ↓↓ 更新數據庫
$QryUpdateTarget = "UPDATE {{table}} SET ";
$QryUpdateTarget .= $TargetPlanetUpd;
$QryUpdateTarget .= "`metal` = `metal` - '" . $Mining['metal'] . "', ";
$QryUpdateTarget .= "`crystal` = `crystal` - '" . $Mining['crystal'] . "', ";
$QryUpdateTarget .= "`deuterium` = `deuterium` - '" . $Mining['deuter'] . "' ";
$QryUpdateTarget .= "WHERE ";
$QryUpdateTarget .= "`galaxy` = '" . $FleetRow['fleet_end_galaxy'] . "' AND ";
$QryUpdateTarget .= "`system` = '" . $FleetRow['fleet_end_system'] . "' AND ";
$QryUpdateTarget .= "`planet` = '" . $FleetRow['fleet_end_planet'] . "' AND ";
$QryUpdateTarget .= "`planet_type` = '" . $FleetRow['fleet_end_type'] . "' ";
$QryUpdateTarget .= "LIMIT 1;";
doquery($QryUpdateTarget , 'planets');
$QryUpdateGalaxy = "UPDATE {{table}} SET ";
$QryUpdateGalaxy .= "`metal` = `metal` + '" . $zlom['metal'] . "', ";
$QryUpdateGalaxy .= "`crystal` = `crystal` + '" . $zlom['crystal'] . "' ";
$QryUpdateGalaxy .= "WHERE ";
$QryUpdateGalaxy .= "`galaxy` = '" . $FleetRow['fleet_end_galaxy'] . "' AND ";
$QryUpdateGalaxy .= "`system` = '" . $FleetRow['fleet_end_system'] . "' AND ";
$QryUpdateGalaxy .= "`planet` = '" . $FleetRow['fleet_end_planet'] . "' ";
$QryUpdateGalaxy .= "LIMIT 1;";
doquery($QryUpdateGalaxy , 'galaxy');
// ↓↓ 計算廢墟和損失的情況
$FleetDebris = $zlom['metal'] + $zlom['crystal'];
$StrAttackerUnits = sprintf ($lang['sys_attacker_lostunits'], pretty_number ($zlom["atakujacy"]));
$StrDefenderUnits = sprintf ($lang['sys_defender_lostunits'], pretty_number ($zlom["wrog"]));
$StrRuins = sprintf ($lang['sys_gcdrunits'], pretty_number ($zlom["metal"]), $lang['Metal'], pretty_number ($zlom['crystal']), $lang['Crystal']);
$DebrisField = $StrAttackerUnits . "" . $StrDefenderUnits . "" . $StrRuins;
// ↓↓ 計算產月概率
$MoonChance = $FleetDebris / 100000;
if ($FleetDebris > 2000000) {
$MoonChance = 20;
}
if ($FleetDebris = 100000) {
$UserChance = mt_rand(1, 100);
$ChanceMoon = sprintf ($lang['sys_moonproba'], $MoonChance);
}
// 如果RP夠好,就能產生月亮了。當然前提是這個坐標上沒有月亮
if (($UserChance > 0) and ($UserChance $MoonChance) {
……
}
// ↓↓ 從這裡開始生成戰斗報告,很長,但並不復雜
$AttackDate = date("r", $FleetRow["fleet_start_time"]);
$title = sprintf ($lang['sys_attack_title'], $AttackDate);
$raport = "" . $title . "";
$zniszczony = false;
$a_zestrzelona = 0;
// ↓↓ 雙方攻防信息。如果有其他能影響艦隊三圍的,也要在這裡加進去
// 當然這裡的數據只是顯示在戰報中而已,是不會影響島實際戰斗的
$AttackTechon['A'] = $CurrentTechno["military_tech"] * 10;
$AttackTechon['B'] = $CurrentTechno["defence_tech"] * 10;
$AttackTechon['C'] = $CurrentTechno["shield_tech"] * 10;
$AttackerData = sprintf ($lang['sys_attack_attacker_pos'], $CurrentUser["username"],$FleetRow['fleet_start_galaxy'], $FleetRow['fleet_start_system'], $FleetRow['fleet_start_planet']);
$AttackerTech = sprintf ($lang['sys_attack_techologies'], $AttackTechon['A'],$AttackTechon['B'], $AttackTechon['C']);
$DefendTechon['A'] = $TargetTechno["military_tech"] * 10;
$DefendTechon['B'] = $TargetTechno["defence_tech"] * 10;
$DefendTechon['C'] = $TargetTechno["shield_tech"] * 10;
$DefenderData = sprintf ($lang['sys_attack_defender_pos'], $TargetUser["username"], $FleetRow['fleet_end_galaxy'], $FleetRow['fleet_end_system'], $FleetRow['fleet_end_planet']);
$DefenderTech = sprintf ($lang['sys_attack_techologies'], $DefendTechon['A'], $DefendTechon['B'], $DefendTechon['C']);
// 根據戰斗中每一輪的詳細情況生成交火的細節,包括每一輪的數量,攻防值,造成和吸收了多少傷害等
// 有一些鍵值可能需要看了戰斗引擎才會明白它代表的什麼,所以看不懂也沒關系 ↓↓
foreach ($dane_do_rw as $a => $b) {
……
}
// ↓↓ 根據勝負結果顯示相應的結尾
switch ($FleetResult) {
……
}
// 戰斗報告生成於 x.xxxxxxxxxxxx 秒
$SimMessage = sprintf ($lang['sys_rapport_build_time'], $totaltime);
$raport .= $SimMessage . "";
// ↓↓ 將戰斗報告編碼,存入數據庫
$dpath = (!$user["dpath"]) ? DEFAULT_SKINPATH : $user["dpath"];
$rid = md5($raport);
$QryInsertRapport = "INSERT INTO {{table}} SET ";
$QryInsertRapport .= "`time` = UNIX_TIMESTAMP(), ";
$QryInsertRapport .= "`id_owner1` = '" . $FleetRow['fleet_owner'] . "', ";
$QryInsertRapport .= "`id_owner2` = '" . $TargetUserID . "', ";
$QryInsertRapport .= "`rid` = '" . $rid . "', ";
$QryInsertRapport .= "`a_zestrzelona` = '" . $a_zestrzelona . "', ";
$QryInsertRapport .= "`raport` = '" . addslashes ($raport) . "';";
doquery($QryInsertRapport , 'rw');
// ↓↓ 這裡才是發給玩家的消息,其中有一個onclick的鏈接到上面的戰報
// 下面這個是發給攻擊方的,根據戰斗結果不同,標題也有不同的顏色
$raport = "";
$raport .= "";
if ($FleetResult == "a") {
$raport .= "";
} elseif ($FleetResult == "r") {
$raport .= "";
} elseif ($FleetResult == "w") {
$raport .= "";
}
$raport .= ……
// ↓ 這裡突然回到計算攻擊艦隊的資源裝載量,其實完全可以挪到上面去
$Mining['metal'] = $Mining['metal'] + $FleetRow["fleet_resource_metal"];
$Mining['crystal'] = $Mining['crystal'] + $FleetRow["fleet_resource_crystal"];
$Mining['deuter'] = $Mining['deuter'] + $FleetRow["fleet_resource_deuterium"];
// 更新艦隊信息
$QryUpdateFleet = "UPDATE {{table}} SET ";
$QryUpdateFleet .= "`fleet_amount` = '" . $FleetAmount . "', ";
$QryUpdateFleet .= "`fleet_array` = '" . $FleetArray . "', ";
$QryUpdateFleet .= "`fleet_mess` = '1', ";
$QryUpdateFleet .= "`fleet_resource_metal` = '" . $Mining['metal'] . "', ";
$QryUpdateFleet .= "`fleet_resource_crystal` = '" . $Mining['crystal'] . "', ";
$QryUpdateFleet .= "`fleet_resource_deuterium` = '" . $Mining['deuter'] . "' ";
$QryUpdateFleet .= "WHERE fleet_id = '" . $FleetRow['fleet_id'] . "' ";
$QryUpdateFleet .= "LIMIT 1 ;";
doquery($QryUpdateFleet , 'fleets');
// 發送戰斗消息給攻擊方
SendSimpleMessage ($CurrentUserID, '', $FleetRow['fleet_start_time'], 3, $lang['sys_mess_tower'], $lang['sys_mess_attack_report'], $raport);
// ↓ 又突然插進來開始計算戰斗經驗和戰斗次數
// 嚴重懷疑coder寫這個文件時是不是喝高了
$AddPoint = $CurrentUser['xpraid'] + 1;
$QryUpdateOfficier = "UPDATE {{table}} SET ";
$QryUpdateOfficier .= "`xpraid` = '" . $AddPoint . "' ";
$QryUpdateOfficier .= "WHERE id = '" . $CurrentUserID . "' ";
$QryUpdateOfficier .= "LIMIT 1 ;";
doquery($QryUpdateOfficier, 'users');
$RaidsTotal = $CurrentUser['raids'] + 1;
if ($FleetResult == "a") {
$RaidsWin = $CurrentUser['raidswin'] + 1;
$QryUpdateRaidsCompteur = "UPDATE {{table}} SET ";
$QryUpdateRaidsCompteur .= "`raidswin` ='" . $RaidsWin . "', ";
$QryUpdateRaidsCompteur .= "`raids` ='" . $RaidsTotal . "' ";
$QryUpdateRaidsCompteur .= "WHERE id = '" . $CurrentUserID . "' ";
$QryUpdateRaidsCompteur .= "LIMIT 1 ;";
doquery($QryUpdateRaidsCompteur, 'users');
} elseif ($FleetResult == "r" || $FleetResult == "w") {
$RaidsLoose = $CurrentUser['raidsloose'] + 1;
$QryUpdateRaidsCompteur = "UPDATE {{table}} SET ";
$QryUpdateRaidsCompteur .= "`raidswin` ='" . $RaidsLoose . "', ";
$QryUpdateRaidsCompteur .= "`raids` ='" . $RaidsTotal . "' ";
$QryUpdateRaidsCompteur .= "WHERE id = '" . $CurrentUserID . "' ";
$QryUpdateRaidsCompteur .= "LIMIT 1 ;";
doquery($QryUpdateRaidsCompteur, 'users');
}
// ↓↓ 終於又回來了,開始寫發給防御方的消息
$raport2 = "";
$raport2 .= "";
if ($FleetResult == "a") {
$raport2 .= "";
} elseif ($FleetResult == "r") {
$raport2 .= "";
} elseif ($FleetResult == "w") {
$raport2 .= "";
}
$raport2 .= $lang['sys_mess_attack_report'] . " [" . $FleetRow['fleet_end_galaxy'] . ":" . $FleetRow['fleet_end_system'] . ":" . $FleetRow['fleet_end_planet'] . "]";
SendSimpleMessage ($TargetUserID, '', $FleetRow['fleet_start_time'], 3, $lang['sys_mess_tower'], $lang['sys_mess_attack_report'], $raport2);
}
// ↓↓ 如果艦隊回到出發地了,就開始卸貨,然後飛機入庫
$fquery = "";
if ($FleetRow['fleet_end_time'] $Count) {
$fquery .= "`" . $resource[$Ship] . "` = `" . $resource[$Ship] . "` + '" . $Count['count'] . "', ";
}
} else {
$fleet = explode(";", $FleetRow['fleet_array']);
foreach($fleet as $a => $b) {
if ($b != '') {
$a = explode(",", $b);
$fquery .= "{$resource[$a[0]]}={$resource[$a[0]]} + {$a[1]}, \n";
}
}
}
// → 到最後別忘了刪除這一條艦隊記錄,不然會一直占用航道。對其他艦隊任務也是一樣
doquery ("DELETE FROM {{table}} WHERE `fleet_id` = " . $FleetRow["fleet_id"], 'fleets');
if (!($FleetResult == "w")) {
$QryUpdatePlanet = "UPDATE {{table}} SET ";
$QryUpdatePlanet .= $fquery;
$QryUpdatePlanet .= "`metal` = `metal` + " . $FleetRow['fleet_resource_metal'] . ", ";
$QryUpdatePlanet .= "`crystal` = `crystal` + " . $FleetRow['fleet_resource_crystal'] . ", ";
$QryUpdatePlanet .= "`deuterium` = `deuterium` + " . $FleetRow['fleet_resource_deuterium'] . " ";
$QryUpdatePlanet .= "WHERE ";
$QryUpdatePlanet .= "`galaxy` = " . $FleetRow['fleet_start_galaxy'] . " AND ";
$QryUpdatePlanet .= "`system` = " . $FleetRow['fleet_start_system'] . " AND ";
$QryUpdatePlanet .= "`planet` = " . $FleetRow['fleet_start_planet'] . " AND ";
$QryUpdatePlanet .= "`planet_type` = " . $FleetRow['fleet_start_type'] . " LIMIT 1 ;";
doquery($QryUpdatePlanet, 'planets');
}
}
}
}