PHP网页游戏学习之Xnova(ogame)源码解读(十六) |
十九、攻击任务(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 style="FONT-FAMILY: ">" . $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); } } } } |