· 9 years ago · Nov 08, 2016, 03:59 AM
1<?
2$debug=0;
3require_once("db.inc");
4require_once("functions.inc");
5//ini_set('display_errors','On');
6
7/* variables import */
8int_register("World","FullTurn");
9/* variables import complete */
10
11if (!isset($World)) {
12 echo "Error: World required<br>\n";
13 exit;
14}
15db_world_select($World);
16
17if ($debug>15) echo "$PHP_SELF on World $World - Start: ".strftime("%T")."<br>\n";
18
19/* turn checking/verification */
20$turn = "Turn_".basename($PHP_SELF, ".php");
21db_query("update Globals set Value='' where Var='$turn'");
22$status = db_fetch_single("select Value from Globals where Var='$turn'");
23db_query("delete from Globals where Var='$turn'");
24$status = db_fetch_single("select Value from Globals where Var='$turn'");
25if ($status) {
26 echo "ERROR: Script status not cleared. Status: $status<br>\n";
27 db_query("update Globals set Value='failed' where Var='$turn'");
28 exit;
29}
30db_query("insert into Globals set Var='$turn', Value='running'");
31
32
33$CombatLines=5; //we go from -5 to 5
34
35$OvercrowdingLimit=4;
36
37// IMPORTANT NOTE: Front line of defenders is 1, front line of attackers is -1
38// Line 1 is behind fortifications; line 0 is not
39
40/* ========================================================================
41 Combat Preparations
42 ======================================================================== */
43if ($debug>15) { echo "<br><br>==> Combat Preparations<br>\n"; }
44
45/* Catch people fleeing - go through all travels that have 3 or less hours
46 in away and check back into their regions */
47
48$res = db_query("select T.ID,T.From_ID,T.Away,U.ID,U.Commander,U.Realm from Travel T, Troops U where T.Away<4 and T.Special='no' and U.Travel=T.ID and U.Location=T.From_ID and U.Commander is not NULL");
49while ($row = db_fetch_array($res)) {
50 /* we make a first chance run here, to save on the next steps */
51 if (rand(0,$row["Away"])==0) {
52 /* possible capture */
53 $Enemies = db_get_list("select Left_ID from Diplomacy where Top_ID=$row[Realm] and Status in ('War','Hatred')");
54 if ($Enemies) {
55 $InBackRegion = db_fetch_single("select sum(Strength) from Troops where Location=$row[From_ID] and Realm in ($Enemies) and Position not in ('scattered','retreated','rallying','dug in')");
56 if ($InBackRegion>0) {
57 /* There are enemy troops back from where we came. If they are few, we may still have a chance */
58 if ($row["Away"]==0||rand(0,200*$row["Away"])<$InBackRegion) {
59 /* got us */
60 $RegName = db_fetch_single("select Name from Regions where ID=$row[From_ID]");
61 $msg = "Even though you were trying to leave $RegName, you did not have many hours reserved for travel ";
62 $msg.= "and did not get far enough to avoid the enemy troops. You are forced to do battle.";
63 message($row["Commander"],"Forced into battle",$msg,"Personal");
64 db_query("update Troops set Travel=NULL where Commander=$row[Commander]");
65 db_query("update Players set Travel=NULL where ID=$row[Commander]");
66 db_query("delete from Travel where ID=$row[ID]");
67 if ($debug>10) echo "Travel interrupted for $row[Commander] (was $row[Away] hours from $RegName)<br>\n";
68 }
69 }
70 }
71 }
72}
73
74/* ========================================================================
75 War
76 ======================================================================== */
77if ($debug>15) echo "<br><br>==> War<br>\n";
78
79/* TODO: ban rebels */
80
81$armyBanners = array();
82$bannerQ = db_query( "Select Owner, Shape, Colors from MiniBanners where Type='army'" );
83while ( $banner = db_fetch_array( $bannerQ ) ) {
84 $imageAddr = "banner_image.php?shape=$banner[Shape]";
85 $colors = explode(',',$banner['Colors']);
86 foreach ( $colors as $color ) {
87 $imageAddr.="&color[]=$color";
88 }
89 $armyBanners[$banner['Owner']] = "<img src=\"$imageAddr\" /> ";
90}
91
92function new_addtag($text,$id=-1) {
93 if ( $id < 1 ) {
94 return $text;
95 }
96 $hisArmy = db_fetch_single( "Select Army from Players where ID=$id" );
97 return "<span class=\"UID_$id\">".$armyBanners[$hisArmy].$text."</span>";
98}
99
100function marshal_setup($Side, $Army, $ArmyName, $Marshal, $Formation) {
101 global $armyBanners;
102
103 $txt=$armyBanners[$Army].player_title($Marshal,false,true)." takes command of ". g('his', -1, $Marshal)." army.";
104 $cond = "CombatRole='$Side' and Army=$Army";
105 $LeaderSkill = skill_get($Marshal, "Leadership");
106 $LeaderBonus = 1+round(rand(0,$LeaderSkill)/10);
107 // Org Bonus depends on army size. Smaller armies get more bonus (to prevent realms from simply putting everyone into one army)
108 $OrgBonus=30;
109 $ArmyMembers = db_get_list("select ID from Players where Army=$Army");
110 $Armysize = db_fetch_single("select sum(Strength) from Troops where Commander in ($ArmyMembers)");
111 if ($ArmySize<250) $OrgBonus+=20;
112 else if ($ArmySize<500) $OrgBonus+=10;
113 else if ($ArmySize>2000) $OrgBonus-=5;
114
115 db_query("update RunCombat set CommanderSkill=CommanderSkill+$LeaderBonus, Morale=LEAST(100,Morale+$LeaderBonus), Organisation=Organisation+$OrgBonus+$LeaderBonus where CombatRole='$Side' and Army=$Army");
116 if ($Formation) {
117 $FName=$Formation;
118 if ($Formation!='none') {
119 db_query("update RunCombat set Organisation=Organisation+25, MarshalFormation='$Formation' where CombatRole='$Side' and Army=$Army");
120 }
121 switch ($Formation) {
122 case 'none':
123 $FName='no particular';
124 break;
125 case 'InfCharge':
126 $FName='Infantry Charge';
127 db_query("update RunCombat set CombatLine=1 where $cond and Type in ('Infantry','Mixed Infantry')");
128 db_query("update RunCombat set CombatLine=2 where $cond and Type='Archers'");
129 db_query("update RunCombat set CombatLine=3 where $cond and Type='Cavalry'");
130 break;
131 case 'CavCharge':
132 $FName='Cavalry Charge';
133 db_query("update RunCombat set CombatLine=1 where $cond and Type='Cavalry'");
134 db_query("update RunCombat set CombatLine=2 where $cond and Type='Infantry'");
135 db_query("update RunCombat set CombatLine=3 where $cond and Type in ('Mixed Infantry','Archers')");
136 break;
137 case "Archery":
138 $FName='Archer Opening';
139 db_query("update RunCombat set CombatLine=1 where $cond and Type in ('Mixed Infantry','Archers')");
140 db_query("update RunCombat set CombatLine=2 where $cond and Type='Infantry'");
141 db_query("update RunCombat set CombatLine=4 where $cond and Type='Cavalry'");
142 break;
143 case "Waves":
144 $units = db_fetch_single("select count(*) from RunCombat where $cond");
145 if ($units<8) $lines=2; else if ($units<15) $lines=3; else $lines=4;
146 $cur=1;
147 $fres = db_query("select ID from RunCombat where CombatRole='$Side'");
148 while ($frow=db_fetch_array($fres)) {
149 db_query("update RunCombat set CombatLine=$cur where ID=$frow[ID]");
150 $cur++; if ($cur>$lines) $cur=1;
151 }
152 break;
153 case "Soften":
154 $FName='Soften and Charge';
155 db_query("update RunCombat set CombatLine=2 where $cond");
156 db_query("update RunCombat set CombatLine=2 where $cond and Type='Archers'");
157 db_query("update RunCombat set CombatLine=3, Tactic='wedge' where $cond and Type='Cavalry'");
158 break;
159 case 'Careful':
160 $FName='Careful Attack';
161 db_query("update RunCombat set CombatLine=2, Tactic='line' where $cond and Type in ('Archers','Special Forces')");
162 $avg = db_fetch_single("select AVG(Strength) from RunCombat where $cond and Type='Infantry'");
163 db_query("update RunCombat set CombatLine=1, Tactic='wedge' where $cond and Type='Infantry' and Strength<=$avg");
164 db_query("update RunCombat set CombatLine=2, Tactic='box' where $cond and Type='Infantry' and Strength>$avg");
165 db_query("update RunCombat set CombatLine=2, Tactic='line' where $cond and Type='Mixed Infantry'");
166 db_query("update RunCombat set CombatLine=3, Tactic='wedge' where $cond and Type='Cavalry'");
167 break;
168 case 'Weaken':
169 $FName='Weakening Skirmish';
170 $units = db_fetch_single("select count(*) from RunCombat where $cond");
171 if ($units<7) $lines=2; else if ($units<12) $lines=3; else $lines=4;
172 $cur=1;
173 $fres = db_query("select ID from RunCombat where $cond");
174 while ($frow=db_fetch_array($fres)) {
175 db_query("update RunCombat set CombatLine=$cur where ID=$frow[ID]");
176 $cur++; if ($cur>$lines) $cur=1;
177 }
178 db_query("update RunCombat set Withdraw=20, Tactic='wedge' where $cond");
179 break;
180 /* Defensive Formations below */
181 case "InfWall":
182 $FName='Infantry Wall';
183 db_query("update RunCombat set CombatLine=1 where $cond and Type in ('Infantry','Mixed Infantry')");
184 db_query("update RunCombat set CombatLine=2 where $cond and Type='Archers'");
185 db_query("update RunCombat set CombatLine=4 where $cond and Type='Cavalry'");
186 break;
187 case "FortDep":
188 $FName='Fortification Defense';
189 db_query("update RunCombat set CombatLine=1 where $cond and Type!='Cavalry'");
190 db_query("update RunCombat set CombatLine=3 where $cond and Type='Cavalry'");
191 db_query("update RunCombat set CombatWait=CombatWait+1 where $cond");
192 break;
193 case "Mixed":
194 $FName='Mixed Lines';
195 $units = db_fetch_single("select count(*) from RunCombat where $cond");
196 if ($units<8) $lines=2; else if ($units<15) $lines=3; else $lines=4;
197 $cur=1;
198 $fres = db_query("select ID from RunCombat where $cond");
199 while ($frow=db_fetch_array($fres)) {
200 db_query("update RunCombat set CombatLine=$cur where ID=$frow[ID]");
201 $cur++; if ($cur>$lines) $cur=1;
202 }
203 db_query("update RunCombat set CombatLine=CombatLine-1 where $cond and Type='Infantry' and CombatLine>1");
204 db_query("update RunCombat set CombatLine=CombatLine+1 where $cond and Type='Archers' and CombatLine<4");
205 break;
206 case "Delay":
207 $FName='Delay and Wound';
208 $avgsize = db_fetch_single("select AVG(Strength) from RunCombat where $cond");
209 db_query("update RunCombat set CombatLine=2 where $cond and Type in ('Archers','Mixed Infantry')");
210 db_query("update RunCombat set CombatLine=3 where $cond and Type in ('Cavalry','Special Forces')");
211 db_query("update RunCombat set CombatLine=4 where $cond and Type='Infantry'");
212 db_query("update RunCombat set CombatLine=CombatLine+1 where $cond and Strength<$avgsize and CombatLine<4");
213 db_query("update RunCombat set CombatLine=3 where $cond and Strength<$avgsize and Type='Infantry'");
214 $smallest = db_fetch_single("select ID from RunCombat where $cond and Type in ('Infantry','Mixed Infantry') order by Strength ASC");
215 db_query("update RunCombat set CombatLine=1 where ID=$smallest");
216 db_query("update RunCombat set CombatWait=CombatWait+1 where $cond");
217 break;
218 case "NoPass";
219 $FName='They Shall Not Pass';
220 db_query("update RunCombat set Tactic='box', CombatWait=CombatWait+2 where $cond");
221 db_query("update RunCombat set CombatLine=3 where $cond and Type in ('Infantry','Mixed Infantry','Special Forces')");
222 db_query("update RunCombat set CombatLine=4 where $cond and Type in ('Cavalry','Archers')");
223 break;
224 case "Retreat";
225 $FName="Strategic Withdrawl";
226 db_query("update RunCombat set CombatLine=4, Withdraw=20, Tactic='box' where $cond");
227 db_query("update RunCombat set CombatLine=2 where $cond and Type in ('Archers','Mixed Infantry')");
228 $avgsize = round(0.8*db_fetch_single("select MAX(Strength) from RunCombat where $cond"));
229 db_query("update RunCombat set CombatLine=4 where $cond and Strength>$avgsize");
230 $avgsize = db_fetch_single("select AVG(Strength) from RunCombat where $cond");
231 db_query("update RunCombat set CombatLine=4, Withdraw=25 where $cond and Strength>$avgsize");
232 break;
233 case "HoldLine":
234 $FName="Hold The Line";
235 db_query("update RunCombat set CombatLine=1, Withdraw=80, CombatWait=10 where $cond");
236 break;
237 case "Shieldwall":
238 $FName="Shieldwall";
239 db_query("Update RunCombat set CombatLine=1 where $cond and Type='Cavalry'");
240 db_query("Update RunCombat set CombatLine=2, Tactic='box' where $cond and Type!='Cavalry' and WpnRange=0");
241 db_query("Update RunCombat set CombatLine=3 where $cond and WpnRange>0");
242 break;
243 }
244 $txt.=" They deploy in $FName formation.";
245 }
246 $txt.="<br>\n";
247 return $txt;
248}
249
250function battle_setupsides($Owner,$TORealm=-1) {
251 global $debug;
252 global $Hunters,$Evading;
253 global $Here;
254
255 $OwnerName = db_fetch_single("select Name from Realms where ID=$Owner");
256 $msg = "";
257
258 /* init: troops that have nobody combat-ready are neutral */
259 $ares = db_query("select * from RunCombat where CombatRole is NULL and Strength=0");
260 while ($arow=db_fetch_array($ares)) {
261 db_query("update RunCombat set CombatRole='neutral' where ID=$arow[ID]");
262 $msg.=stripslashes($arow["Name"])." have no combat-ready men and thus stay out of the battle.<br>\n";
263 }
264
265 /* evasive troops vs. too superior opponents */
266 $HunterMod=0;
267 if ($Hunters<100) $HunterMod=2;
268 else if ($Hunters<200) $HunterMod=5;
269 else if ($Hunters<500) $HunterMod=10;
270 else if ($Hunters<1000) $HunterMod=20;
271 else $HunterMod=25;
272 $ares = db_query("select * from RunCombat where CombatRole is NULL and Encounter='Evade'");
273 while ($arow=db_fetch_array($ares)) {
274 if ( $arow['Commander'] ) {
275 $engines = db_fetch_single( "Select Number from PlayerExtras where Player_ID=$arow[Commander] and Extra_ID=5" );
276 $encumbranceMod = $engines*4;
277 }
278 /* the smaller they are, the larger their chance */
279 /* TODO: should probably take region type into account? */
280 if (rand(0,50)-$HunterMod-$encumbranceMod>max(10,$arow["Strength"]+$arow["Wounded"])) {
281 $Evading=true;
282 db_query("update RunCombat set CombatRole='neutral',Position='evading' where ID=$arow[ID]");
283 /* And update it here since neutral troop are not written back */
284 db_query("update Troops set Position='evading' where ID=$arow[ID]");
285 $msg.=stripslashes($arow["Name"])." successfully evade the foreign troops.<br>\n";
286 } else {
287 $msg.=stripslashes($arow["Name"])." tried to evade foreign troops, but were spotted.<br>\n";
288 }
289 }
290
291 $realms_present = db_get_array("Select distinct Realm from RunCombat where CombatRole is NULL");
292 if (count($realms_present) == 1 && $realms_present[0] == 0) {
293 $humans = db_get_array("Select ID from RunCombat where Type not in ('Monsters','Undead','Daimons') and Position not in ('evading', 'ambush', 'retreated', 'scattered', 'rallying') and CombatRole is NULL");
294 $nonhumans = db_get_array("Select ID from RunCombat where Type in ('Monsters','Undead','Daimons') and Position not in ('evading', 'ambush', 'retreated', 'scattered', 'rallying') and CombatRole is NULL");
295 if (count($humans) > 0 && count($nonhumans) > 0) {
296 // Humans and nonhumans fight each other even when both rogue--but only when no non-rogues are around
297 $humansInControl = db_fetch_single( "Select Sum(Strength) from RunCombat where Type not in ('Monsters','Undead','Daimons') and Position in ('normal','dug in') and CombatRole is NULL" );
298 $nonhumansInControl = db_fetch_single( "Select Sum(Strength) from RunCombat where Type in ('Monsters','Undead','Daimons') and Position in ('normal','dug in') and CombatRole is NULL" );
299 if ($humansInControl > $nonhumansInControl) {
300 db_query("Update RunCombat set CombatRole='defender' where Type not in ('Monsters','Undead','Daimons') and CombatRole is NULL");
301 db_query("Update RunCombat set CombatRole='attacker' where Type in ('Monsters','Undead','Daimons') and CombatRole is NULL");
302 $msg.="The humans present set up defenses because they control the battlefield.<br/>\n";
303 $msg.="The nonhuman forces present attack.<br/>\n";
304 } else {
305 db_query( "Update RunCombat set CombatRole='defender' where Type in ('Monsters','Undead','Daimons') and CombatRole is NULL" );
306 db_query( "Update RunCombat set CombatRole='attacker' where Type not in ('Monsters','Undead','Daimons') and CombatRole is NULL" );
307 $msg.="The nonhuman forces present set up defenses because they control the battlefield.<br/>\n";
308 $msg.="The humans present attack.<br/>\n";
309 }
310 }
311 return $msg;
312 }
313
314 /* If a takeover is running, the TO realm is automatically defender,
315 with their allies only joining in later */
316 if ($TORealm!=-1) {
317 $present = db_fetch_single("select sum(Strength) from RunCombat where Realm=$TORealm");
318 if ($present>0) {
319 /* set up the TO forces as defenders */
320 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm=$TORealm");
321 $TOName = db_fetch_single("select Name from Realms where ID=$TORealm");
322 $msg.="The forces from $TOName brace as they prepare to defend their ongoing takeover.<br>\n";
323 $Allies = db_get_list("select Left_ID from Diplomacy where Top_ID=$Owner and Status in ('Alliance','Federation')");
324 if ($Allies!="") {
325 $msg.="The region owner $OwnerName and their allies attack the takeover forces.<br>\n";
326 }
327 } else {
328 $TORealm=-1;
329 }
330 }
331
332 if ($TORealm==-1) {
333 /* If anyone from the owner realm or allied with it is here, they are defenders this is easy because every realm is allied with itself */
334 $Allies = db_get_list("select Left_ID from Diplomacy where Top_ID=$Owner and Status in ('Alliance','Federation')");
335 if ($Allies!="") {
336 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm in ($Allies) and Position in ('normal', 'dug in') and Type!='Peasants'");
337 if (db_affected_rows()>0) {
338 $msg.="The region owner $OwnerName and their allies defend.<br>\n";
339 /* put the remaining (fresh) troops in as well */
340 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm in ($Allies)");
341 } else {
342 $StationaryNonPeasants = db_fetch_single( "Select count(*) from RunCombat where CombatRole is NULL and Realm in ($Allies) and Position in ('normal', 'dug in') and Type != 'Peasants'" );
343 $NonStationaryNonPeasants = db_fetch_single( "Select count(*) from RunCombat where CombatRole is NULL and Realm in ($Allies) and Position not in ('normal', 'dug in') and Type != 'Peasants'" );
344 $StationaryPeasants = db_fetch_single( "Select count(*) from RunCombat where CombatRole is NULL and Realm in ($Allies) and Position in ('normal', 'dug in') and Type='Peasants'" );
345 if ( ($NonStationaryNonPeasants == 0 || $StationaryNonPeasants > 0) && $StationaryPeasants > 0 ) {
346 /* If there are *only* peasants of our realm(s) in the region, and no one freshly arrived or rallying, make them defenders */
347 db_query( "Update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm in ($Allies)" );
348 $msg.="The peasants of $OwnerName and their allies defend.<br>\n";
349 } else {
350 /* no owner or allied troops here -
351 choose the realm with the highest past presence as defenders */
352 $fres = db_query("select Realm,sum(Strength) from RunCombat where Position in ('normal', 'dug in') and Type != 'Peasants' group by Realm order by 2 DESC");
353 $PrimDef =db_fetch_row($fres);
354
355 if ($PrimDef[1]>0) {
356 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm=$PrimDef[0]");
357 $RN = db_fetch_single("select Name from Realms where ID=$PrimDef[0]");
358 $msg.="The troops from $RN set up defenses because they control the battlefield.<br>\n";
359 } else {
360 /* no owner or allied troops here or old troop from a realm -
361 choose the realm with the highest presence as defenders */
362 $fres = db_query("select Realm,sum(Strength) from RunCombat group by Realm order by 2 DESC");
363 $PrimDef =db_fetch_row($fres);
364
365 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm=$PrimDef[0]");
366 $RN = db_fetch_single("select Name from Realms where ID=$PrimDef[0]");
367 $msg.="The troops from $RN set up defenses.<br>\n";
368 }
369 }
370 }
371 }
372 }
373
374 /* At this point, we have some defenders, so let's go through everyone else */
375 $Defenders=db_get_list("select Realm from RunCombat where CombatRole='defender' group by Realm");
376 if ($Defenders=="") {
377 /* we have no defenders? weird. */
378 $msg.="No defenders.";
379 return $msg;
380 }
381
382 /* Federations */
383 $ares = db_query("select * from RunCombat where CombatRole is NULL group by Realm");
384 while ($arow=db_fetch_array($ares)) {
385 $Feds = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status='Federation'");
386 if ($Feds>0) {
387 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
388 $msg.= "The confederates from $myRN join the defense.<br>\n";
389 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm=$arow[Realm]");
390 }
391 }
392
393 /* groups based on diplomacy */
394 $ares = db_query("select * from RunCombat where CombatRole is NULL group by Realm");
395 while ($arow=db_fetch_array($ares)) {
396 $Allied = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('Alliance','Federation')");
397 $Peace = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status='Peace'");
398 $War = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('War','Hatred')");
399
400 if ($War&&!$Allied&&!$Peace) {
401 /* we are at war with someone, and no allies/peace are with him - attack */
402 db_query("update RunCombat set CombatRole='attacker' where CombatRole is NULL and Realm=$arow[Realm]");
403 $Partner = db_fetch_single("select Top_ID from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('War','Hatred')");
404 $RN = db_fetch_single("select Name from Realms where ID=$Partner");
405 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
406 $msg.= "The $myRN troops attack because they are at war with $RN.<br>\n";
407 continue;
408 }
409 if ($War&&$Allied) {
410 /* at war with one and allied with another defender. check your diplomacy */
411 db_query("update RunCombat set CombatRole='neutral' where CombatRole is NULL and Realm=$arow[Realm]");
412 $Partner = db_fetch_single("select Top_ID from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('War','Hatred')");
413 $RN = db_fetch_single("select Name from Realms where ID=$Partner");
414 $Partner = db_fetch_single("select Top_ID from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('Alliance','Federation')");
415 $RNb= db_fetch_single("select Name from Realms where ID=$Partner");
416 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
417 $msg.= "The $myRN forces remain neutral - they are at war with $RN, but allied with $RNb. What was their ruler thinking?<br>\n";
418 continue;
419 }
420 }
421
422 /* first round - easy cases */
423 $ares = db_query("select * from RunCombat where CombatRole is NULL");
424 while ($arow=db_fetch_array($ares)) {
425 $Allied = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('Alliance','Federation')");
426 $Peace = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status='Peace'");
427 $War = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('War','Hatred')");
428
429 if ($Allied==0&&$arow["Encounter"]=="Murder") {
430 /* murderous troops disregard peace treaties */
431 db_query("update RunCombat set CombatRole='attacker' where ID=$arow[ID]");
432 if ($War) {
433 $Partner = db_fetch_single("select Top_ID from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('War','Hatred')");
434 $RN = db_fetch_single("select Name from Realms where ID=$Partner");
435 $msg.=stripslashes($arow["Name"])." attack because they are out for blood and at war with $RN.<br>\n";
436 } else {
437 $msg.=stripslashes($arow["Name"])." attack because they are out for blood.<br>\n";
438 }
439 continue;
440 }
441 if ($Allied==0&&$Peace==0&&($arow["Encounter"]=="Murder"||$arow["Encounter"]=="Attack")) {
442 db_query("update RunCombat set CombatRole='attacker' where ID=$arow[ID]");
443 $msg.=stripslashes($arow["Name"])." have attack orders.<br>\n";
444 continue;
445 }
446 }
447
448 /* second round - allies */
449 $Attackers=db_get_list("select Realm from RunCombat where CombatRole='attacker' group by Realm");
450 if ($Attackers=="") {
451 $msg.= "No Attackers => No Battle<br>\n";
452 return $msg;
453 }
454
455 /* Federations */
456 $ares = db_query("select * from RunCombat where CombatRole is NULL group by Realm");
457 while ($arow=db_fetch_array($ares)) {
458 $Feds = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Attackers) and Status='Federation'");
459 if ($Feds>0) {
460 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
461 $msg.= "The confederates from $myRN join the attacking forces.<br>\n";
462 db_query("update RunCombat set CombatRole='attacker' where CombatRole is NULL and Realm=$arow[Realm]");
463 }
464 }
465
466 $ares = db_query("select * from RunCombat where CombatRole is NULL group by Realm");
467 while ($arow=db_fetch_array($ares)) {
468 $AlliedAtt = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Attackers) and Status in ('Alliance','Federation')");
469 $PeaceAtt = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Attackers) and Status='Peace'");
470 $PeaceDef = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status='Peace'");
471 $AlliedDef = db_fetch_single("select count(*) from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('Alliance','Federation')");
472
473 if ($AlliedAtt&&!$AlliedDef&&!$PeaceDef) {
474 db_query("update RunCombat set CombatRole='attacker' where CombatRole is NULL and Realm=$arow[Realm]");
475 if ($arow["Realm"]==$AlliedAtt) /* allied with ourselves - silent join */
476 continue;
477 $Partner = db_fetch_single("select Top_ID from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Attackers) and Status in ('Alliance','Federation')");
478 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
479 if ($Partner==$arow["Realm"]) {
480 $msg.= "The $myRN units join in to support their realm-mates.<br>\n";
481 } else {
482 $RN = db_fetch_single("select Name from Realms where ID=$Partner");
483 }
484 continue;
485 }
486 if ($AlliedDef&&!$AlliedAtt&&!$PeaceAtt) {
487 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Realm=$arow[Realm]");
488 if ($arow["Realm"]==$AlliedDef) /* allied with ourselves - silent join */
489 continue;
490 $Partner = db_fetch_single("select Top_ID from Diplomacy where Left_ID=$arow[Realm] and Top_ID in ($Defenders) and Status in ('Alliance','Federation')");
491 $RN = db_fetch_single("select Name from Realms where ID=$Partner");
492 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
493 $msg.= "The troops from $myRN join the defense because of their alliance with $RN.<br>\n";
494 continue;
495 }
496 if (($AlliedDef||$PeaceDef)&&($AlliedAtt||$PeaceAtt)) {
497 db_query("update RunCombat set CombatRole='neutral' where CombatRole is NULL and Realm=$arow[Realm]");
498 $myRN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
499 $msg.= "The $myRN forces stay neutral because they have friends on both sides.<br>\n";
500 continue;
501 }
502 }
503
504 /* everyone else is a bit confused */
505 $ares = db_query("select * from RunCombat where CombatRole is NULL");
506 while ($arow=db_fetch_array($ares)) {
507 $msg.=stripslashes($arow["Name"])." don't know what to do and stay out of the battle.<br>\n";
508 db_query("update RunCombat set CombatRole='neutral' where ID=$arow[ID]");
509 }
510 return $msg;
511}
512
513
514function battle_setuprebelcombat($Owner) {
515 global $debug;
516 global $Evading;
517
518 $OwnerName = db_fetch_single("select Name from Realms where ID=$Owner");
519
520 /* Reset the CombatRole */
521 db_query("update RunCombat set CombatRole=NULL");
522
523 /* init: troops that have nobody combat-ready are neutral */
524 $ares = db_query("select * from RunCombat where CombatRole is NULL and Strength=0");
525 while ($arow=db_fetch_array($ares)) {
526 db_query("update RunCombat set CombatRole='neutral' where ID=$arow[ID]");
527 $msg.=stripslashes($arow["Name"])." have no combat-ready men and thus stay out of the battle.<br>\n";
528 }
529
530 /* neutral if your commander isn't there */
531 $ares = db_query("select * from RunCombat where CombatRole is NULL and Commander is not NULL and CommanderPresent='no'");
532 while ($arow=db_fetch_array($ares)) {
533 db_query("update RunCombat set CombatRole='neutral' where ID=$arow[ID]");
534 $msg.=stripslashes($arow["Name"])." are without their commander and therefore stay out of the fighting.<br>\n";
535 }
536
537
538 /* Loyal troops defend */
539 $ares = db_query("select ID from Players where active='yes' and Loyalty='loyalist' and Realm=$Owner");
540 while ($arow=db_fetch_array($ares)) {
541 db_query("update RunCombat set CombatRole='defender' where CombatRole is NULL and Commander=$arow[ID]");
542 }
543
544 /* militia chooses sides based on morale */
545 $ares = db_query("select * from RunCombat where CombatRole is NULL and Commander is NULL and Realm=$Owner");
546 while ($arow=db_fetch_array($ares)) {
547 $Roll = rand(0,100);
548 if ($Roll>$arow["Morale"]+10) {
549 $msg.="The militia unit ".stripslashes($arow["Name"])." joins the rebels.<br>\n";
550 db_query("update RunCombat set CombatRole='attacker' where ID=$arow[ID]");
551 } else if ($Roll<$arow["Morale"]-10) {
552 $msg.="The militia unit ".stripslashes($arow["Name"])." joins the loyalists.<br>\n";
553 db_query("update RunCombat set CombatRole='defender' where ID=$arow[ID]");
554 } else {
555 $msg.="The militia unit ".stripslashes($arow["Name"])." stays out of the fighting.<br>\n";
556 db_query("update RunCombat set CombatRole='neutral' where ID=$arow[ID]");
557 }
558 }
559
560 /* Rebels attack */
561 $ares = db_query("select ID from Players where active='yes' and Realm=$Owner and Loyalty in ('rebel','rebelleader','kicked','failed')");
562 while ($arow=db_fetch_array($ares)) {
563 db_query("update RunCombat set CombatRole='attacker' where Commander=$arow[ID]");
564 $UName = db_fetch_single("select Name from RunCombat where Commander=$arow[ID]");
565 if ($UName) $msg.="$UName are with the rebels and attack.<br>\n";
566 }
567
568
569 /* Secret underground members stand down */
570 $ares = db_query("select ID from Players where active='yes' and Loyalty='opposition' and Realm=$Owner");
571 while ($arow=db_fetch_array($ares)) {
572 db_query("update RunCombat set CombatRole='neutral' where Commander=$arow[ID]");
573 $UName = db_fetch_single("select Name from RunCombat where Commander=$arow[ID]");
574 if ($UName) $msg.="$UName surprisingly stand down and remain neutral.<br>\n";
575 }
576 $msg.="Loyal troops from $OwnerName set up defenses.<br>\n";
577
578 /* everyone else stays neutral */
579 $ares = db_query("select * from RunCombat where CombatRole is NULL");
580 while ($arow=db_fetch_array($ares)) {
581 $msg.=stripslashes($arow["Name"])." stand down and abstain from the battle.<br>\n";
582 db_query("update RunCombat set CombatRole='neutral' where ID=$arow[ID]");
583 }
584
585 /* DEBUG */
586 //echo "$msg<br>\n";
587
588 return $msg;
589}
590
591
592function suicide_attack($AttNames, $RealmList, $Here, $RegName, $Owner, $StartDS) {
593 $msg = "Small forces from ".stripslashes($AttNames)." attacked $RegName, ";
594 $msg.= "but were quickly surrounded by overwhelming defending units. Vastly outnumbered, ";
595 $msg.= "the attackers surrendered and were all captured.";
596 message(db_get_array("select ID from Players where active='yes' and Realm in ($RealmList) and Location!=$Here"), "Skirmish in $RegName", $msg, "Report");
597
598 $msg = "The following units attacked $RegName:<ul>";
599 $ares = db_query("select * from RunCombat where CombatRole='attacker'");
600 $Prisoners=0;
601 $WeAreHome = db_fetch_single("select ID from RunCombat where CombatRole='defender' and Realm=$Owner");
602 if ($WeAreHome) { /* region owner */
603 $Taker=$Owner;
604 } else { /* largest defender */
605 list($Taker,$TStrength) = db_fetch_single("select Realm,sum(CombatStrength) from RunCombat where CombatRole='defender' group by Realm order by 2 DESC");
606 }
607
608 $tmsg = "Your small troop that attacked $RegName was quickly surrounded by overwhelming defending units. Vastly outnumbered, ";
609 $tncmsg = $tmsg."your men surrendered and were captured.";
610 $tmsg.= "your men surrendered and you were captured.";
611
612 while ($arow=db_fetch_array($ares)) {
613 $msg.="<li>\"".stripslashes($arow["Name"])."\" ";
614 if ($arow["Commander"]) {
615 $HisRealm = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
616 if ($arow["CommanderPresent"]=="yes") {
617 $msg.="(".player_title($arow["Commander"]).", $HisRealm)</li>";
618 $Prisoners++;
619 Prison($arow['Commander'],"",$Taker,"battle",$Here);
620 character_gone($arow["Commander"],"","",'Absence'); /* remove without message */
621 message($arow["Commander"], "Battle Results", $tmsg, "Personal");
622 } else {
623 $msg.="(commander not present)</li>";
624 message($arow["Commander"], "Battle Results", $tncmsg, "Personal");
625 }
626 } else $msg.="(militia unit)</li>";
627 db_query("delete from Troops where ID=$arow[ID]");
628 }
629 $msg.= "</ul><br>\n";
630 $msg.= "Due to the overwhelming odds, however ($StartDS CS defending forces), ";
631 $msg.= "the attackers were quickly surrounded and forced to surrender.<br>";
632 $msg.= "The attacking units were dissolved";
633 if ($Prisoners>0) {
634 $msg.= ", and their commanders taken into ";
635 $TRN = db_fetch_single("select Name from Realms where ID=$Taker");
636 $msg.= "custody in $TRN.";
637 message(db_get_array("select Player_ID from Government where Realm=$Taker and Position in ('Ruler','Judge')"),"New Prisoner","Prisoners from the skirmish in $RegName have arrived in your dungeons.");
638 } else $msg.=".";
639 message(db_get_array("select ID from Players where active='yes' and Location=$Here"), "Skirmish in $RegName", $msg, "Report");
640}
641
642
643/* =================================================================
644 Functions
645 ================================================================= */
646
647function unroll_textarray($TxtArray, $text) {
648 global $armyBanners;
649
650 $elems=count($TxtArray);
651 if ($elems==1) {
652 foreach ($TxtArray as $Com => $AName) {
653 $army = db_fetch_single( "Select Army from Players where ID=$Com" );
654 return addtag($armyBanners[$army]."$AName $text",$Com);
655 }
656 } else if ($elems>1) {
657 $cur=0; $line="";
658 foreach ($TxtArray as $Com => $AName) {
659 $cur++;
660 if ($cur==$elems) $line.=" and ";
661 else if ($cur>1) $line.=", ";
662 $line.=$AName;
663 }
664 $line.=" ".$text;
665 foreach ($TxtArray as $Com => $AName) $line=addtag($line, $Com);
666 return $line;
667 }
668 return "";
669}
670
671
672
673function artillery_fire($Weather, $Fortification, $FortBreach) {
674 global $debug;
675 global $msg, $armyBanners;
676
677 db_query( "Update RunCombat set RangedTarget=NULL" );
678
679 /* archers fire on nearest enemy if they can (i.e. no close combat) */
680 $ares = db_query("select * from RunCombat where WpnRange > 0 and CombatLine is not NULL order by Serial ASC");
681 $hitsAttackers=0; $hitsDefenders=0;
682 while ($thisUnit = db_fetch_array($ares)) {
683 if ($thisUnit["CombatRole"]=="attacker") $enemyRole="defender"; else $enemyRole="attacker";
684 $AName=stripslashes($thisUnit["Name"])." ($thisUnit[CombatNr])";
685 $enemies = db_fetch_single("select count(ID) from RunCombat where CombatRole='$enemyRole' and CombatLine=$thisUnit[CombatLine]");
686 if ($thisUnit["Type"]=="Mixed Infantry"||$thisUnit['Type']=='Daimons') {
687 $enemyarchers = db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='$enemyRole' and CombatLine is not NULL and Type='Archers'");
688 $enemyarchers+= round(db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='$enemyRole' and CombatLine is not NULL and Type in ('Cavalry','Daimons')")/2);
689 }
690 if ($enemies==0) {
691 /* free to fire, acquire target */
692 if ($thisUnit["CombatRole"]=='attacker') {
693 $targ="defender"; $sort="ASC";
694 } else {
695 $targ="attacker"; $sort="DESC";
696 }
697 $bres = db_query("select * from RunCombat where CombatRole='$targ' and CombatLine is not NULL order by CombatLine $sort, CombatStrength-RangedHits*2 DESC");
698 $brow = null; // to prevent a bug below, when it still has the old brow from the previous unit
699 $found=0;
700 while (!$found&&$brow=db_fetch_array($bres)) {
701 /* strip out close-combat lines */
702 $friends = db_fetch_single("select count(ID) from RunCombat where CombatRole='$thisUnit[CombatRole]' and CombatLine=$brow[CombatLine]");
703 if ($friends==0) {
704 $found=1;
705 }
706 }
707 if ($found) { $Distance=abs($thisUnit["CombatLine"]-$brow["CombatLine"]); } else { $Distance=99; }
708
709 /* more intelligence */
710 if ($thisUnit["CombatRole"]=='attacker') {
711 $pre="+"; $next=$thisUnit["CombatLine"]+1; $nextnext=$thisUnit["CombatLine"]+2;
712 } else {
713 $pre="-"; $next=$thisUnit["CombatLine"]-1; $nextnext=$thisUnit["CombatLine"]-2;
714 }
715 /* For MI, there's a 20% chance to trigger this. For Archers, if the closest enemy is more than 2 rows away, there is a 10% chance to trigger this. */
716 //if (($thisUnit["WpnRange"]>0&&$thisUnit["Type"]!="Archers"&&rand(0,10)<2)||($thisUnit["Type"]=="Archers"&&$Distance>2&&rand(0,10)<1)) {
717 // Belay that: If the closest enemy is farther away than our range, we move
718 $done = false;
719 if (!$found || $Distance > $thisUnit['WpnRange']) {
720 $next_line_enemies=db_fetch_single("select count(*) from RunCombat where CombatRole='$enemyRole' and CombatLine=$next");
721
722 // A1) First of all, if there's nobody in range *right now*, we wait if we are generally set up to wait, based on CombatWait
723 if ($next_line_enemies==0&&(($thisUnit["CombatWait"]>3)||($thisUnit["CombatWait"]>0&&$thisUnit["Position"]=="dug in"))) {
724 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName have no enemy in range and hold their fire.<br>\n",$thisUnit["Commander"]);
725 $done = 'stay';
726 }
727
728 // A2) There are enemies in the next line, and we can fire at them, carefully
729 if ( !$done && $next_line_enemies>0 ) {
730 $Distance = 1;
731 if ( $thisUnit['Type'] == 'Archers' ) {
732 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName fire carefully into the close combat near them.<br>\n",$thisUnit["Commander"]);
733 $done = 'fire';
734 } else {
735 if ($thisUnit['Encounter'] == 'Attack') {
736 $closeIn = true;
737 } else if ($thisUnit['Encounter'] == 'Defend') {
738 $closeIn = false;
739 } else {
740 if ($thisUnit['CombatWait'] > 3 && rand(1,10) < 2 || rand(1,10) < 8) {
741 $closeIn = true;
742 }
743 }
744 if ( $closeIn ) {
745 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName move into the close combat just ahead.<br>\n",$thisUnit["Commander"]);
746 $done = 'move';
747 db_query("update RunCombat set Position='normal', CombatLine=CombatLine $pre 1, CombatStrength=CombatStrength*0.9 where ID=$thisUnit[ID]");
748 } else {
749 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName fire carefully into the close combat near them.<br>\n",$thisUnit["Commander"]);
750 $done = 'fire';
751 }
752 }
753 }
754
755 // A3) There are no enemies in the next line, but there are enemies in the one after it. We can move into that line if we're not scheduled to
756 // sit tight (as in A1)
757 $next_next_line_enemies=db_fetch_single("select count(*) from RunCombat where CombatRole='$enemyRole' and CombatLine=$nextnext");
758 if ( !$done && $next_next_line_enemies>0 ) {
759 if ( $thisUnit["CombatRole"]=='defender' && ($Fortification>0&&!$FortBreach) && $thisUnit["CombatLine"]==1 ) {
760 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName wait on top of the fortifications for the attack.<br/>\n",$thisUnit["Commander"]);
761 $done = 'stay';
762 } else {
763 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName move closer so they can fire safely into the melee.<br>\n",$thisUnit["Commander"]);
764 $done = 'move';
765 db_query("update RunCombat set Position='normal', CombatLine=CombatLine $pre 1, CombatStrength=CombatStrength*0.9 where ID=$thisUnit[ID]");
766 }
767 }
768
769 // A4) There are no enemies within range this turn or next turn, so either we wait on the wall, or we move closer
770 if (!$done) {
771 if ( $thisUnit["CombatRole"]=='defender' && ($Fortification>0&&!$FortBreach) && $thisUnit["CombatLine"]==1 ) {
772 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName wait on top of the fortifications for the attack.<br/>\n",$thisUnit["Commander"]);
773 $done = 'stay';
774 } else {
775 $msg.=addtag($armyBanners[$thisUnit['Army']]."$AName move closer to get better shots.<br>\n",$thisUnit["Commander"]);
776 $done = 'move';
777 db_query("update RunCombat set Position='normal', CombatLine=CombatLine $pre 1, CombatStrength=CombatStrength*0.9 where ID=$thisUnit[ID]");
778 }
779 }
780 }
781
782 if ($done=='fire') {
783 $bres = db_query("select * from RunCombat where CombatRole='$targ' and CombatLine=$next order by CombatStrength-RangedHits*2 DESC");
784 $brow = db_fetch_array($bres);
785 $hitMod = 0.75;
786 } else {
787 $hitMod = 1;
788 }
789
790 if ($brow && !in_array($done,array('move','stay'))) {
791 /* if we have a target, fire away */
792 $DMod=max(1,$Distance/2);
793 switch ($thisUnit['Type']) {
794 case 'Archers':
795 $Hits=round($thisUnit["CombatStrength"]/$DMod);
796 $Hits+=round(rand(0,$thisUnit["CombatStrength"]/$DMod));
797 break;
798 case 'Special Forces':
799 $Hits=round(rand($thisUnit["CombatStrength"]/($DMod*2),$thisUnit["CombatStrength"]/($DMod/2)));
800 $Hits+=round(rand(0,($thisUnit["CombatStrength"]/$DMod)*0.6));
801 break;
802 case 'Peasants':
803 case 'Mixed Infantry':
804 $Hits=round(($thisUnit["CombatStrength"]/$DMod)*0.75);
805 $Hits+=round(rand(0,($thisUnit["CombatStrength"]/$DMod)*0.75));
806 break;
807 case 'Daimons':
808 $Hits=round(($thisUnit["CombatStrength"]/$DMod)*0.5);
809 $Hits+=round(rand(0,($thisUnit["CombatStrength"]/$DMod)));
810 break;
811 default:
812 // any other unit that might somehow have ranged capabilities
813 $Hits=round(($thisUnit["CombatStrength"]/$DMod)*0.5);
814 $Hits+=round(rand(0,($thisUnit["CombatStrength"]/$DMod)*0.5));
815 }
816 /* weapons */
817 $Hits = round($hitMod*$Hits*$thisUnit['Weapons']/100);
818
819 /* cavalry and daimons are more difficult to hit */
820 if ($brow['Type']=='Cavalry'||$brow['Type']=='Daimons') $Hits=round($Hits*0.75);
821
822 /* general reduction of hits for ranged fire */
823 $randomloss=min(75,rand($Weather/5,($Weather*$DMod)/3));
824 $Hits=round($Hits*(100-$randomloss)/150);
825 if ($debug>20) { echo "$Hits<br>\n"; }
826
827 /* reduced damage for targets in skirmish formations */
828 if ($brow["Tactic"]=="skirmish") $Hits=round($Hits*rand(6,8)/10);
829
830 /* increased damage for targets in box formations */
831 if ($brow["Tactic"]=="box") $Hits=round($Hits*rand(12,14)/10);
832
833 $msg.=addtag(addtag($armyBanners[$thisUnit['Army']]."$AName fire on ".stripslashes($brow["Name"])." ($brow[CombatNr]), scoring $Hits hits.<br>\n",$thisUnit["Commander"]),$brow["Commander"]);
834 db_query("update RunCombat set RangedHits=RangedHits+$Hits where ID=$brow[ID]");
835 db_query("update RunCombat set HitsCaused=HitsCaused+$Hits,CombatStrength=CombatStrength/2,CommanderXP=CommanderXP+1,RangedTarget=$brow[ID] where ID=$thisUnit[ID]");
836 if ($enemyRole=='attacker') {
837 $hitsAttackers += $Hits;
838 } else {
839 $hitsDefenders += $Hits;
840 }
841 }
842 }
843 }
844 if ($hitsAttackers>0||$hitsDefenders>0) {
845 $msg.="<span style=\"color: white;\"><b>Total ranged hits suffered: Attackers: ";
846 $msg.="$hitsAttackers";
847 $msg.=", Defenders: ";
848 $msg.="$hitsDefenders";
849 $msg.="</b></span><br>\n";
850 }
851}
852
853
854
855function cavalry_charge($Fortification, $FortificationBreached) {
856 global $debug;
857 global $msg, $armyBanners;
858
859 $ARide=array(); $DRide=array();
860 $AFly=array(); $DFly=array();
861 $ACharge=array(); $DCharge=array();
862 $AChargeB=array(); $DChargeB=array();
863 $ABreach=array(); $ADistance=array(); $AHelpless=array();
864
865 $ares = db_query("select * from RunCombat where WpnRange=0 and CombatLine is not NULL and Type in ('Cavalry', 'Daimons') order by Serial ASC");
866 while ($arow = db_fetch_array($ares)) {
867 /* recheck enemy positions, just to make sure not earlier advances
868 cause us to bypass the enemy */
869 if ($arow["CombatRole"]=="attacker") $role="defender"; else $role="attacker";
870 $AName=stripslashes($arow['Name'])." ($arow[CombatNr])";
871 if ($arow['Commander']) $Com=$arow['Commander']; else $Com=-$arow['ID'];
872
873 $charge=false;
874 $enemies = db_fetch_single("select count(ID) from RunCombat where CombatRole='$role' and CombatLine=$arow[CombatLine]");
875
876 if (!$arow['CloseWith']) {
877 /* cavalry can advance 2 lines and charge (temporarily raising combat strength) */
878 if ($arow["CombatRole"]=="attacker") {
879 $targ="defender"; $sort="ASC"; $pre="+"; $comp=">";
880 } else {
881 $targ="attacker"; $sort="DESC"; $pre="-"; $comp="<";
882 }
883 /* check for fortifications */
884 if ($arow["CombatRole"]=="attacker"&&$Fortification&&($arow["CombatLine"]==0||$arow["CombatLine"]==-1)&&$arow['Type']!='Daimons'
885 /* ...and check to see if there's any enemy *in front of* the fortifications (assuming we're more than 1 row away from the walls) */
886 && ($arow['CombatLine']==0||db_fetch_single( "Select count(*) from RunCombat where CombatRole='defender' and CombatLine<1")==0) ) {
887 /* damn, they are behind fortifications */
888 if ($FortificationBreached>rand(0,5)) {
889 /* breached already */
890 $ABreach[$Com] = $AName;
891 $advance = 1 - $arow["CombatLine"];
892 } else {
893 if ($arow['CombatLine']==-1) {
894 $ADistance[$Com] = $AName;
895 $advance=0;
896 } else {
897 $AHelpless[$Com] = $AName;
898 $advance=0;
899 }
900 }
901 } else {
902 $nextenemies = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and Type not in ( 'Monsters', 'Daimons' ) and CombatLine=$arow[CombatLine] $pre 1");
903 $nextenemies += 3*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and Type='Monsters' and CombatLine=$arow[CombatLine] $pre 1");
904 $nextenemies += 5*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and Type='Daimons' and CombatLine=$arow[CombatLine] $pre 1");
905 $nextfriends = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type not in ( 'Monsters', 'Daimons' ) and CombatLine=$arow[CombatLine] $pre 1");
906 $nextfriends += 3*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type='Monsters' and CombatLine=$arow[CombatLine] $pre 1");
907 $nextfriends += 5*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type='Daimons' and CombatLine=$arow[CombatLine] $pre 1");
908 if ($nextenemies>0&&$nextfriends>$nextenemies*4&&($nextenemies+$nextfriends>50)) {
909 /* next line overcrowded */
910 $msg.=addtag($armyBanners[$arow['Army']]."$AName are eager to charge, but the melee is too crowded already.<br>\n",$Com);
911 $advance=0;
912 } else {
913 if (db_fetch_single("select count(*) from RunCombat where CombatRole='$targ' and CombatLine=$arow[CombatLine] $pre 1")>0) {
914 /* enemy near, charge into next line */
915 if ($arow["Position"]=="dug in") $msg.=addtag($armyBanners[$arow['Army']]."$AName leave their fortified positions and attack<br>\n",$Com);
916 else $DCharge[$Com] = $AName;
917 $advance=1; $charge=true;
918 } else if (db_fetch_single("select count(*) from RunCombat where CombatRole='$targ' and CombatLine=$arow[CombatLine] $pre 2")>0) {
919 /* enemy in reach, charge */
920 if ($arow["Position"]=="dug in") $msg.=addtag($armyBanners[$arow['Army']]."$AName leave their fortified positions and attack the enemy<br>\n",$Com);
921 else if ($arow['CombatRole']=='attacker') $AChargeB[$Com] = $AName; else $DChargeB[$Com] = $AName;
922 $advance=2; $charge=true;
923 } else if (!$enemies&&db_fetch_single("Select count(*) from RunCombat where CombatRole='$targ' and CombatLine $comp $arow[CombatLine] $pre 1")) {
924 /* no enemy in reach, check if we want to advance */
925 /* TODO: check if enemy 2 lines away. if so, advance only 1 (to keep charge option) */
926 if (($arow["CombatWait"]>3)||($arow["CombatWait"]>0&&$arow["Position"]=='dug in')) {
927 $msg.=addtag($armyBanners[$arow['Army']]."$AName stay in their defensive position, awaiting an opportunity to charge.<br>\n",$Com);
928 $advance=0;
929 } else {
930 if ($arow['Type']=='Daimons') {
931 if ($arow['CombatRole']=='attacker') $AFly[$Com] = $AName; else $DFly[$Com] = $AName;
932 } else {
933 if ($arow['CombatRole']=='attacker') $ARide[$Com] = $AName; else $DRide[$Com] = $AName;
934 }
935 $advance=2;
936 }
937 }
938 }
939 }
940 if ($advance>0) {
941 $bquery = "update RunCombat set Position='normal', CombatLine=CombatLine $pre $advance ";
942 if ($charge) {
943 /* CS increased */
944 switch ($arow["Tactic"]) {
945 case "wedge": $div=300; break;
946 case "skirmish": $div=500; break;
947 default: $div=400;
948 }
949 $bquery.= ", CombatStrength=CombatStrength*(600+Weapons+Training)/$div ";
950 }
951 $bquery.= " where ID=$arow[ID]";
952 db_query($bquery);
953 }
954 }
955 }
956
957 /* now unroll the arrays */
958 $msg.=unroll_textarray($ARide, "ride on, closing in on the defenders.<br>\n");
959 $msg.=unroll_textarray($DRide, "ride on, closing in on the enemy.<br>\n");
960 $msg.=unroll_textarray($AFly, "fly towards the defenders.<br>\n");
961 $msg.=unroll_textarray($DFly, "fly towards their enemies.<br>\n");
962 $msg.=unroll_textarray($ACharge, "charge into battle.<br>\n");
963 $msg.=unroll_textarray($DCharge, "charge forward.<br>\n");
964 $msg.=unroll_textarray($ADistance, "keep their distance to the fortifications, waiting for other troops to breach them first.<br>\n");
965 $msg.=unroll_textarray($AHelpless, "canter up and down helplessly in front of the fortifications, waiting for friendly troops to breach them.<br>\n");
966 $msg.=unroll_textarray($ABreach, "ride carefully through the breached fortifications.<br>\n");
967 $msg.=unroll_textarray($AChargeB, "charge ahead, into the defenders\' ranks.<br>\n");
968 $msg.=unroll_textarray($DChargeB, "charge ahead, into the attackers\' ranks.<br>\n");
969}
970
971
972//
973// whoops_move_back
974// Created 2008-12-20 by Timothy
975// Checks every unit on the battlefield to make sure they haven't gone past the enemies, and if they have, move them back
976// Parameters: none
977// Returns: nothing
978//
979// TODO: Apply the mods to the units; ensure that a unit that's already moving back doesn't do anything else
980//
981function whoops_move_back() {
982 global $msg,$CombatLines;
983 /* We have to check *every* unit on the battlefield */
984 $ares = db_query("select * from RunCombat where CombatLine is not NULL order by Serial ASC");
985 while ($arow = db_fetch_array($ares)) {
986 if ($arow["CombatRole"]=="attacker") {
987 $pre="-";
988 $pastenemies = intval(db_fetch_single("select sum(Strength) from RunCombat where CombatRole='defender' and CombatLine < $arow[CombatLine]"));
989 $futureenemies = intval(db_fetch_single("select sum(Strength) from RunCombat where CombatRole='defender' and CombatLine > $arow[CombatLine]"));
990 } else {
991 $pre="+";
992 $pastenemies = intval(db_fetch_single("select sum(Strength) from RunCombat where CombatRole='attacker' and CombatLine > $arow[CombatLine]"));
993 $futureenemies = intval(db_fetch_single("select sum(Strength) from RunCombat where CombatRole='attacker' and CombatLine < $arow[CombatLine]"));
994 }
995
996 $AName=stripslashes($arow["Name"])." ($arow[CombatNr])";
997 if ($arow['Commander']) {
998 $Com=$arow['Commander'];
999 } else {
1000 $Com=-$arow['ID'];
1001 }
1002
1003 if ($futureenemies==0&&$pastenemies>0) {
1004 /* nobody ahead anymore - turn around */
1005 $msg.=addtag($armyBanners[$arow['Army']]."$AName move back towards the melee.<br>\n",$Com);
1006 db_query("update RunCombat set Position='normal', CombatLine=CombatLine $pre 1 where ID=$arow[ID]"); /*, Action='back'*/
1007 }
1008 }
1009}
1010
1011//
1012// check_melee
1013// Created 2009-12-17 by Timothy
1014// Checks every unit with the possibility of close combat, and if there are any enemy units left to fight, assigns one to it
1015// Parameters: none
1016// Returns: nothing
1017//
1018function check_melee( $ANoCombat, $DNoCombat ) {
1019 global $msg,$OvercrowdingLimit,$CombatLines;
1020
1021 $HasMonsters = db_fetch_single( "Select Count(ID) from RunCombat where Type='Monsters'" );
1022 $HasDaimons = db_fetch_single( "Select Count(ID) from RunCombat where Type='Daimons'" );
1023
1024 for ( $i=-1*$CombatLines; $i<=$CombatLines; $i++ ) {
1025
1026 //echo "Checking line $i...<br/>";
1027 /* First, check which side has more troops in the line. */
1028
1029 $ares = db_query("select count(ID),sum(Strength) from RunCombat where CombatRole='attacker' and CombatLine=$i");
1030 $arow = db_fetch_row($ares);
1031 $AttackerCount=$arow[0]; $AttackerStrength=$arow[1];
1032 $ares = db_query("select count(ID),sum(Strength) from RunCombat where CombatRole='defender' and CombatLine=$i");
1033 $arow = db_fetch_row($ares);
1034 $DefenderCount=$arow[0]; $DefenderStrength=$arow[1];
1035
1036 /* Don't go any further if this line is all one side or the other */
1037 if ( $AttackerCount == 0 || $DefenderCount == 0 ) {
1038 continue;
1039 }
1040
1041 /* Whoever has more units gets to pick first, for logistical reasons. */
1042 if ( $AttackerCount > $DefenderCount ) {
1043 $order = 'DESC';
1044 } else {
1045 $order = 'ASC';
1046 }
1047
1048 /* Go through the units of the two sides in the line. */
1049
1050 $unitQ = db_query( "Select ID, CombatRole, Name, CombatNr, Commander from RunCombat where CombatLine=$i and CloseWith is NULL order by CombatRole $order, Serial ASC" );
1051 while ( $unit = db_fetch_array( $unitQ ) ) {
1052
1053 if ( $unit['Commander'] ) {
1054 $Com=$unit['Commander'];
1055 } else {
1056 $Com=-1*$unit['ID'];
1057 }
1058
1059 /* For each one, check to see if there are units already attacking him; if so, pick the smallest of them to fight */
1060
1061 $attackerQ = db_query( "Select ID, CombatStrength, Name, CombatNr from RunCombat where CombatLine=$i and CloseWith=$unit[ID]" );
1062 $attacker = -1;
1063 $attackerStrength = -1;
1064 while ( $attackers = db_fetch_array( $attackerQ ) ) {
1065 //echo "$attacker[Name] is attacking $unit[Name]<br/>";
1066 if ( $attackers['CombatStrength'] < $attackerStrength || $attackerStrength == -1 ) {
1067 $attacker = $attackers['ID'];
1068 $attackerStrength = $attackers['CombatStrength'];
1069 }
1070 }
1071 if ( $attacker != -1 ) {
1072 db_query( "Update RunCombat set CloseWith=$attacker where ID=$unit[ID]" );
1073 list( $VicName, $VicNum ) = db_fetch_single( "Select Name, CombatNr from RunCombat where ID=$attacker" );
1074 //$msg.="$unit[Name] ($unit[CombatNr]) fights with $VicName ($VicNum) in close combat.<br/>";
1075 //echo "$unit[Name] ($unit[CombatNr]) fights with $VicName ($VicNum) in close combat.<br/>";
1076 continue;
1077 }
1078
1079 /* Otherwise, look through the enemy line and find the first person with the least number of units already attacking him */
1080
1081 $Limit = $OvercrowdingLimit;
1082 if ( $HasDaimons ) {
1083 $Limit*=5;
1084 } else if ( $HasMonsters ) {
1085 $Limit*=3;
1086 }
1087
1088 $victim = false;
1089
1090 for ( $j=0; $j<=$Limit; $j++ ) {
1091 //echo "Looking for units with no more than $j times the strength attacking them...<br/>";
1092
1093 if ( !$victim ) {
1094 //echo "Checking if $j is less than $OvercrowdingLimit...<br/>";
1095 if ( $j < $OvercrowdingLimit ) {
1096 //echo "Still looking for all types<br/>";
1097 //$victim = db_fetch_single( "Select A.ID from RunCombat A left join RunCombat B on A.CloseWith=B.ID where Sum(B.Strength)<($j*A.Strength) and A.CombatRole!='$unit[CombatRole]' group by A.CloseWith order by A.ID" );
1098 $victimQ = db_query( "Select A.ID, A.Strength as VicStr, B.Strength as AtkStr from RunCombat A left join RunCombat B on A.ID=B.CloseWith where A.CombatRole!='$unit[CombatRole]' and A.CombatLine=$i order by A.ID" );
1099 $vicID = -1;
1100 while ( $victims=db_fetch_array( $victimQ ) ) {
1101 //echo "Looking at enemy ID $victims[ID], with strength $victims[VicStr], fighting against an enemy with strength $victims[AtkStr]<br/>";
1102 //echo "Previous VicID: $vicID; Attacker Str: $atkStr; Vic Str: $vicStr<br/>";
1103 if ( $vicID == -1 ) {
1104 $vicID=$victims['ID'];
1105 $atkStr=$victims['AtkStr'];
1106 $vicStr=$victims['VicStr'];
1107 } else if ( $vicID != $victims['ID'] ) {
1108 if ( $atkStr <= $j*$vicStr ) {
1109 //echo "Picking vic $vicID<br/>";
1110 $victim=$vicID;
1111 break;
1112 }
1113 $vicID=$victims['ID'];
1114 $atkStr=$victims['AtkStr'];
1115 $vicStr=$victims['VicStr'];
1116 } else {
1117 $atkStr+=$victims['AtkStr'];
1118 }
1119 }
1120 if ( $atkStr <= $j*$vicStr ) {
1121 $victim=$vicID;
1122 break;
1123 }
1124 } else if ( $j < 3*$OvercrowdingLimit ) {
1125 //echo "Just looking for monsters and Daimons<br/>";
1126 //$victim = db_fetch_single( "Select A.ID from RunCombat A left join RunCombat B on A.CloseWith=B.ID where Sum(B.Strength)<($j*A.Strength) and A.CombatRole!='$unit[CombatRole]' and A.Type in ('Monsters','Daimons') group by A.CloseWith order by A.ID" );
1127 $victimQ = db_query( "Select A.ID, A.Strength as VicStr, B.Strength as AtkStr from RunCombat A left join RunCombat B on A.ID=B.CloseWith where A.CombatRole!='$unit[CombatRole]' and A.CombatLine=$i and A.Type in ('Monsters','Daimons') order by A.ID" );
1128 $vicID = -1;
1129 while ( $victims=db_fetch_array( $victimQ ) ) {
1130 if ( $vicID == -1 ) {
1131 $vicID=$victims['ID'];
1132 $atkStr=$victims['AtkStr'];
1133 $vicStr=$victims['VicStr'];
1134 } else if ( $vicID != $victims['ID'] ) {
1135 if ( $atkStr < $j*$vicStr ) {
1136 $victim=$vicID;
1137 break;
1138 }
1139 $vicID=$victims['ID'];
1140 $atkStr=$victims['AtkStr'];
1141 $vicStr=$victims['VicStr'];
1142 } else {
1143 $atkStr+=$victims['AtkStr'];
1144 }
1145 if ( $atkStr < $j*$vicStr ) {
1146 $victim=$vicID;
1147 break;
1148 }
1149 }
1150 } else {
1151 //echo "Only looking for Daimons<br/>";
1152 //$victim = db_fetch_single( "Select A.ID from RunCombat A left join RunCombat B on A.CloseWith=B.ID where Sum(B.Strength)<($j*A.Strength) and A.CombatRole!='$unit[CombatRole]' and A.Type='Daimons' group by A.CloseWith order by A.ID" );
1153 $victimQ = db_query( "Select A.ID, A.Strength as VicStr, B.Strength as AtkStr from RunCombat A left join RunCombat B on A.ID=B.CloseWith where A.CombatRole!='$unit[CombatRole]' and A.CombatLine=$i and A.Type='Daimons' order by A.ID" );
1154 $vicID = -1;
1155 while ( $victims=db_fetch_array( $victimQ ) ) {
1156 if ( $vicID == -1 ) {
1157 $vicID=$victims['ID'];
1158 $atkStr=$victims['AtkStr'];
1159 $vicStr=$victims['VicStr'];
1160 } else if ( $vicID != $victims['ID'] ) {
1161 if ( $atkStr < $j*$vicStr ) {
1162 $victim=$vicID;
1163 break;
1164 }
1165 $vicID=$victims['ID'];
1166 $atkStr=$victims['AtkStr'];
1167 $vicStr=$victims['VicStr'];
1168 } else {
1169 $atkStr+=$victims['AtkStr'];
1170 }
1171 if ( $atkStr < $j*$vicStr ) {
1172 $victim=$vicID;
1173 break;
1174 }
1175 }
1176 }
1177 }
1178
1179 if ( $victim ) {
1180 break;
1181 }
1182
1183 }
1184
1185 if ( $victim ) {
1186 db_query( "Update RunCombat set CloseWith=$victim where ID=$unit[ID]" );
1187 list( $VicName, $VicNum ) = db_fetch_single( "Select Name, CombatNr from RunCombat where ID=$victim" );
1188 //$msg.="$unit[Name] ($unit[CombatNr]) fights with $VicName ($VicNum) in close combat.<br/>";
1189 //echo "$unit[Name] ($unit[CombatNr]) fights with $VicName ($VicNum) in close combat.<br/>";
1190 if ( $ANoCombat[$Com] ) {
1191 unset($ANoCombat[$Com]);
1192 } else if ( $DNoCombat[$Com] ) {
1193 unset($DNoCombat[$Com]);
1194 }
1195 continue;
1196 }
1197
1198 /* If there are no enemy units with less than the overcrowding limit attacking them,
1199 this unit doesn't get to fight in melee this round. */
1200
1201 db_query( "Update RunCombat set CloseWith=NULL where ID=$unit[ID]" );
1202 if ( $unit['CombatRole']=='attacker' ) {
1203 $ANoCombat[$Com] = stripslashes($unit['Name'])." ($unit[CombatNr])";
1204 } else {
1205 $DNoCombat[$Com] = stripslashes($unit['Name'])." ($unit[CombatNr])";
1206 }
1207
1208 }
1209
1210 }
1211
1212 return array( $ANoCombat, $DNoCombat );
1213
1214}
1215
1216function units_advance($Fortification, $SE, $count) {
1217 global $debug;
1218 global $msg, $armyBanners;
1219
1220 $AAdvance=array(); $DAdvance=array(); $DPostake=array(); $DWait=array(); $AHold=array(); $DHold=array(); $AdvWait=array(); $SAAdvance=array(); $SDAdvance=array();
1221
1222 $ares = db_query("select * from RunCombat where WpnRange=0 and CombatLine is not NULL and Type not in ('Cavalry','Daimons') order by Serial ASC");
1223 while ($arow = db_fetch_array($ares)) {
1224 if ($arow["CombatRole"]=="attacker") {
1225 $role="defender"; $pre="+"; $comp=">";
1226 } else {
1227 $role="attacker"; $pre="-"; $comp="<";
1228 }
1229
1230 $AName=stripslashes($arow["Name"])." ($arow[CombatNr])";
1231 if ($arow['Commander']) $Com=$arow['Commander']; else $Com=-$arow['ID'];
1232
1233 $enemies = db_fetch_single("select count(ID) from RunCombat where CombatRole='$role' and CombatLine=$arow[CombatLine]");
1234
1235 $unpaired_enemies = db_fetch_single("select count(ID) from RunCombat where CombatRole='$role' and CombatLine=$arow[CombatLine] and CloseWith is NULL");
1236
1237 if (!$arow['CloseWith']&&!$unpaired_enemies) {
1238 /* not in melee, we may want to advance */
1239 if (!$Fortification&&$arow["CombatWait"]>0&&$arow["Position"]=='dug in') {
1240 $msg.=addtag($armyBanners[$arow['Army']]."$AName stay behind their camp fortifications.<br>\n",$Com);
1241 } else {
1242 $nextenemies = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and Type not in ( 'Monsters', 'Daimons' ) and CombatLine=$arow[CombatLine] $pre 1");
1243 $nextenemies += 3*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and Type='Monsters' and CombatLine=$arow[CombatLine] $pre 1");
1244 $nextenemies += 5*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and Type='Daimons' and CombatLine=$arow[CombatLine] $pre 1");
1245
1246 $nextfriends = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type not in ( 'Monsters', 'Daimons' ) and CombatLine=$arow[CombatLine] $pre 1");
1247 $nextfriends += 3*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type='Monsters' and CombatLine=$arow[CombatLine] $pre 1");
1248 $nextfriends += 5*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type='Daimons' and CombatLine=$arow[CombatLine] $pre 1");
1249
1250 $herefriends = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type not in ( 'Monsters', 'Daimons' ) and CombatLine=$arow[CombatLine] and CloseWith is NULL");
1251 $herefriends += 3*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type='Monsters' and CombatLine=$arow[CombatLine] and CloseWith is NULL");
1252 $herefriends += 5*db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$arow[CombatRole]' and Type='Daimons' and CombatLine=$arow[CombatLine] and CloseWith is NULL");
1253 $Mod=""; $QueryMod="";
1254
1255 // For people in the same row as a melee, they *will* wait if moving forward is likely to just get them slaughtered
1256
1257 if ( $enemies > 0 && $nextfriends == 0 && $nextenemies > $herefriends*5 ) {
1258 if ( $arow['CombatRole'] == 'attacker' ) {
1259 $AHold[$Com]=$AName;
1260 } else {
1261 $DHold[$Com]=$DName;
1262 }
1263 $Mod="stay";
1264 } else if ($Fortification&&$arow["CombatLine"]==0&&$arow["CombatRole"]=="attacker") {
1265 /* we must scale the walls */
1266 if ($SE>0) {
1267 /* we have siege engines */
1268 $SEMen=db_fetch_single("select sum(Strength) from RunCombat where CombatLine=0 and CombatRole='attacker'");
1269 if ($SE*25>=$SEMen) {
1270 /* enough siege engines for everyone, full effect */
1271 $msg.=addtag($armyBanners[$arow['Army']]."$AName attack the fortifications with siege engines!<br>\n",$Com);
1272 $div=1+$Fortification/10;
1273 } else {
1274 /* not enough, reduced effect */
1275 if ($SE*35>=$SEMen) $msg.=addtag($armyBanners[$arow['Army']]."$AName attack the walls with slightly overcrowded siege engines.<br>\n",$Com);
1276 elseif ($SE*50>=$SEMen) $msg.=addtag($armyBanners[$arow['Army']]."$AName climb up through the overcrowded siege engines.<br>\n",$Com);
1277 else $msg.=addtag($armyBanners[$arow['Army']]."$AName squeeze through the heavily overcrowded siege engines.<br>\n",$Com);
1278 $Eff=($SE*20/$SEMen)*10;
1279 $div=1+$Fortification/$Eff;
1280 }
1281 } else {
1282 /* must scale the walls manually */
1283 $msg.=addtag($armyBanners[$arow['Army']]."$AName scale the fortifications (reduced combat effectiveness for this turn).<br>\n",$Com);
1284 $div=1+$Fortification;
1285 }
1286 if ($debug>15) echo "Scaling fortifications: div = $div<br>\n";
1287 /* honour and prestige bonus for storming a fortification */
1288 $QueryMod=", CombatStrength=CombatStrength/$div, CommanderHonour=CommanderHonour+1, CommanderPrestige=CommanderPrestige+5, CommanderXP=CommanderXP+1 ";
1289 } else if ($Fortification&&$arow["CombatRole"]=="defender") {
1290 /* we are the defenders - might want to wait behind the walls */
1291 if ($arow["CombatLine"]>1) {
1292 $DPostake[$Com]=$AName;
1293 } else if ($arow["CombatLine"]==1) {
1294 $Foot=db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='attacker' and CombatLine<1 and WpnRange=0");
1295 $OurFoot=db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='defender' and CombatLine>0 and WpnRange=0");
1296 if ($Foot&&$arow["Encounter"]!="Murder"&&$arow["Encounter"]!="Attack"&&$arow["CombatWait"] > 0) {
1297 $DWait[$Com]=$AName;
1298 $Mod="stay";
1299 $WaitLess=0;
1300 while ( $OurFoot > $Foot * 2 ) {
1301 $OurFoot = $OurFoot/2;
1302 $WaitLess++;
1303 }
1304 db_query( "Update RunCombat set CombatWait=CombatWait-$WaitLess where ID=$arow[ID]" );
1305 } else {
1306 if ($nextenemies>0&&$nextfriends>$nextenemies*5&&($nextenemies+$nextfriends>50)) {
1307 /* next line overcrowded */
1308 $msg.=addtag($armyBanners[$arow['Army']]."$AName are eager to attack, but the melee is too crowded already.<br>\n",$Com);
1309 $Mod="stay";
1310 } else $msg.=addtag($armyBanners[$arow['Army']]."$AName leave the fortification, attacking the enemy.<br>\n",$Com);
1311 }
1312 }
1313 } else {
1314 /* TODO: See if this plus the whoops_move_back function causes people to move back twice... */
1315 $futureenemies = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and CombatLine ${comp} $arow[CombatLine]");
1316 if ($futureenemies>0) {
1317 if ( $arow['MarshalFormation']=='Shieldwall' ) {
1318 // advance at half speed in shieldwall formation
1319 if ($arow['CombatRole']=='attacker') $SAAdvance[$Com]=$AName; else $SDAdvance[$Com]=$AName;
1320 if ( $count%2==1 ) {
1321 $Mod='stay';
1322 }
1323 } else {
1324 if ($arow['CombatRole']=='attacker') $AAdvance[$Com]=$AName; else $DAdvance[$Com]=$AName;
1325 }
1326 } else if ( !$enemies ) {
1327 /* nobody ahead anymore - turn around */
1328 $msg.=addtag($armyBanners[$arow['Army']]."$AName move back towards the melee.<br>\n",$Com);
1329 if ($pre=="-") $pre="+"; else $pre="-";
1330 } else {
1331 $Mod="stay";
1332 //$AdvWait[$Com]=$AName;
1333 }
1334 }
1335 if ($Mod!="stay") {
1336 db_query("update RunCombat set Position='normal', CombatLine=CombatLine $pre 1 $QueryMod where ID=$arow[ID]");
1337 }
1338 }
1339 } else {
1340 /* we might be able to break through the melee */
1341 if ($arow['CombatRole']=='defender'&&$arow['CombatLine']>0&&$Fortification) {
1342 /* nah, let's stay at the walls */
1343 } else if ($arow['CombatRole']=='attacker'&&$arow['CombatLine']==0&&$Fortification) {
1344 /* nope, we are at the walls */
1345 } else {
1346 $EnemyCS = db_fetch_single("select sum(CombatStrength+Training) from RunCombat where CombatRole='$role' and CombatLine=$arow[CombatLine]");
1347 $OurCS = db_fetch_single("select sum(CombatStrength+Training) from RunCombat where CombatRole='$arow[CombatRole]' and CombatLine=$arow[CombatLine]");
1348 if ($OurCS>$EnemyCS*4) {
1349 $futureenemies = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='$role' and CombatLine $comp $arow[CombatLine]");
1350 if ($futureenemies>rand(20,50)) {
1351 /* break through! */
1352 $msg.=addtag($armyBanners[$arow['Army']]."$AName break through the frontlines!<br>\n",$Com);
1353 db_query("update RunCombat set Position='normal', CombatLine=CombatLine $pre 1 where ID=$arow[ID]");
1354 }
1355 }
1356 }
1357 }
1358 }
1359
1360 /* now unroll the arrays */
1361 $msg.=unroll_textarray($AHold, "wait for more reinforcements before they join the melee.<br>\n");
1362 $msg.=unroll_textarray($DHold, "wait for more reinforcements before they join the melee.<br>\n");
1363 $msg.=unroll_textarray($AAdvance, "advance towards the enemy.<br>\n");
1364 $msg.=unroll_textarray($DAdvance, "advance towards the enemy.<br>\n");
1365 $msg.=unroll_textarray($SAAdvance, "advance slowly towards the enemy in formation.<br>\n");
1366 $msg.=unroll_textarray($SDAdvance, "advance slowly towards the enemy in formation.<br>\n");
1367 $msg.=unroll_textarray($DPostake, "move forward to take up positions at the outer wall.<br>\n");
1368 $msg.=unroll_textarray($DWait, "hold their positions at the outer wall, waiting for the attack.<br>\n");
1369 //$msg.=unroll_textarray($AdvWait, "hold their positions and wait for the approaching enemy.<br>\n"); We may want this, but let's see if it's obvious enough first
1370}
1371
1372function close_combat() {
1373 global $debug;
1374 global $msg, $armyBanners;
1375 global $OverkillAttackers, $OverkillDefenders;
1376
1377 /* recheck battle lines, because of the advances/charges above */
1378 for ($i=-5;$i<6;$i++) {
1379 $ares = db_query("select count(ID),sum(Strength) from RunCombat where CombatRole='attacker' and CombatLine=$i and CloseWith is not NULL");
1380 $arow = db_fetch_row($ares);
1381 $AL=$arow[0]; $AS=$arow[1];
1382 $ares = db_query("select count(ID),sum(Strength) from RunCombat where CombatRole='defender' and CombatLine=$i and CloseWith is not NULL");
1383 $arow = db_fetch_row($ares);
1384 $DL=$arow[0]; $DS=$arow[1];
1385 if ($AL>0&&$DL>0) {
1386 $msg.="<br><span style=\"color: white;\">Close Combat";
1387 if ( $i < 0 ) {
1388 $msg.=" (Attacker Line ".(-1*$i).")";
1389 } else if ( $i > 0 ) {
1390 $msg.=" (Defender Line $i)";
1391 } else {
1392 $msg.=" (Center Line)";
1393 }
1394 $msg.=":</span><br>\n";
1395
1396 db_query("update RunCombat set CloseCount=CloseCount+1 where CombatLine=$i and CloseWith is not NULL");
1397
1398 /* Banners */
1399 $ares = db_query("select Realm, sum(Strength), sum(Banners) from RunCombat where CombatLine=$i and CloseWith is not NULL group by Realm");
1400 while ($arow = db_fetch_row($ares)) {
1401 if ($arow[2]>0) {
1402 $Realm=db_fetch_single("select Name from Realms where ID=$arow[0]");
1403 $msg.="<span style=\"color: #E0E0FF;\">$arow[2] $Realm banners are visible in the melee.</span><br>\n";
1404 $Eff=min(10,round($arow[2]*250/$arow[1]));
1405 $CSBonus=1+($Eff/100);
1406 if ($debug>20) echo "BannerBonus for Realm $Realm: $CSBonus<br>\n";
1407 db_query("update RunCombat set CombatStrength=Combatstrength*$CSBonus where Realm=$arow[0] and CombatLine=$i and CloseWith is not NULL");
1408 }
1409 }
1410
1411 /* honour for commanders in close combat */
1412 db_query("update RunCombat set CommanderHonour=CommanderHonour+2 where CombatLine=$i and CloseWith is not NULL");
1413 /* people not in close combat get only half the honour ... */
1414 db_query("update RunCombat set CommanderHonour=CommanderHonour+1 where CombatLine=$i and CloseWith is NULL");
1415 $HitsAttackers=0; $HitsDefenders=0;
1416 $ActualHitsAttackers=0; $ActualHitsDefenders=0;
1417 $MaxPossibleAttackers=0; $MaxPossibleDefenders=0;
1418 $OverkillAttackers=0; $OverkillDefenders=0;
1419
1420 $ares = db_query("select * from RunCombat where CombatLine=$i and CloseWith is not NULL order by Serial ASC");
1421 while ($arow=db_fetch_array($ares)) {
1422 list( $oppName, $oppNr ) = db_fetch_single( "Select Name, CombatNr from RunCombat where ID=$arow[CloseWith]" );
1423 //echo "Currently working on close combat of $arow[Name] ($arow[CombatNr]), who is fighting with $oppName ($oppNr)<br/>";
1424 db_query("update RunCombat set CommanderHonour=CommanderHonour+2, CommanderPrestige=CommanderPrestige+2 where ID=$arow[ID]");
1425 switch ($arow["Type"]) {
1426 case "Peasants":
1427 case "Archers": /* very weak close combat unit */
1428 $Min=$arow["CombatStrength"]*0.4;
1429 $Max=$arow["CombatStrength"]*0.5;
1430 break;
1431 case "Mixed Infantry": /* somewhat weak close combat unit */
1432 $Min=$arow["CombatStrength"]*0.65;
1433 $Max=$arow["CombatStrength"]*0.9;
1434 break;
1435 case "Special Forces": /* large random factor - can be > 1 */
1436 $Min=$arow["CombatStrength"]*0.5;
1437 $Max=$arow["CombatStrength"]*1.25;
1438 break;
1439 case 'Daimons': /* fearsome enemies - good damage, and cause large morale loss */
1440 $Min=$arow["CombatStrength"]*0.8;
1441 $Max=$arow["CombatStrength"]*1.25;
1442 if ($arow['CombatRole']=='attacker') $fear='defender'; else $fear='attacker';
1443 db_query("update RunCombat set Morale=GREATEST(5,Morale-3), Cohesion=GREATEST(1,Cohesion-1) where CombatRole='$fear' and Type not in ('Monsters', 'Undead')");
1444 db_query("update RunCombat set Morale=GREATEST(1,Morale-5), Cohesion=GREATEST(1,Cohesion-2) where CombatRole='$fear' and CombatLine=$arow[CombatLine] and Type not in ('Monsters', 'Undead')");
1445 break;
1446 default:
1447 $Min=$arow["CombatStrength"]*0.75;
1448 $Max=$arow["CombatStrength"];
1449 }
1450 switch ($arow["Tactic"]) {
1451 case "box": $Min*=0.9; $Max*=0.95; break;
1452 case "wedge": $Min*=1.1; $Max*=1.2; break;
1453 case "skirmish": $Min*=0.5; $Max*=0.75; break;
1454 }
1455 $Hits=round(rand(round($Min),round($Max))*$arow['Weapons']/100);
1456 if ($Hits<1) { echo "Error in hits calculation, 0 hits caused. Min/Max=$Min/$Max.<br>arow: "; var_dump($arow); echo "<br><hr/>\n"; $Hits=$arow['Strength']; }
1457 if ($Hits>$Max) { echo "Error in hits calculation, more than max hits caused. Min/Max=$Min/$Max.<br>arow: "; var_dump($arow); echo "<br><hr/>\n"; $Hits=$arow['Strength']; }
1458
1459 if ($arow["CombatRole"]=="attacker") {
1460 $MaxPossibleDefenders+=$Max;
1461 } else {
1462 $MaxPossibleAttackers+=$Max;
1463 }
1464
1465 /* Assign hits based on who you're fighting
1466 The unit you're attacking takes most of the hits,
1467 but if there are other units attacking you, they get some, too. */
1468
1469 $HitsLeft=$Hits;
1470
1471 /*
1472 * We count all the opponents including your target and those targetting you.
1473 * The goal is to distribute your hits among them according to their relative size (Strength)
1474 */
1475 $DefCount = db_fetch_single( "Select Count(ID) from RunCombat where (CloseWith=$arow[ID] or ID=$arow[CloseWith])" );
1476 $DefOKStr = db_fetch_single( "Select Sum(Strength) from RunCombat where (CloseWith=$arow[ID] or ID=$arow[CloseWith])" );
1477 /* Monsters count as 2x for overkill purposes */
1478 $DefOKStr+= db_fetch_single( "Select Sum(Strength) from RunCombat where (CloseWith=$arow[ID] or ID=$arow[CloseWith]) and Type in ('Monsters','Daimons')" );
1479 /* Daimons count as 4x for overkill purposes */
1480 $DefOKStr+=2*db_fetch_single( "Select Sum(Strength) from RunCombat where (CloseWith=$arow[ID] or ID=$arow[CloseWith]) and Type='Daimons'" );
1481 $opponentTotalStr = $DefOKStr;
1482
1483 $AtkCount = db_fetch_single( "Select Count(ID) from RunCombat where CloseWith=$arow[CloseWith]" );
1484 $AtkOKStr = db_fetch_single( "Select Sum(Strength) from RunCombat where CloseWith=$arow[CloseWith]" );
1485 /* Monsters count as 2x for overkill purposes */
1486 $AtkOKStr+= db_fetch_single( "Select Sum(Strength) from RunCombat where CloseWith=$arow[CloseWith] and Type in ('Monsters','Daimons')" );
1487 /* Daimons count as 4x for overkill purposes */
1488 $AtkOKStr+=2*db_fetch_single( "Select Sum(Strength) from RunCombat where CloseWith=$arow[CloseWith] and Type='Daimons'" );
1489
1490 $OverkillThem=1;
1491 if ( $AtkOKStr > $DefOKStr*5 ) {
1492 $Pen=round(($AtkOKStr*2)/$DefOKStr)/$AtkCount;
1493 $OverkillThem=max(1,sqrt($Pen)-2);
1494 db_query("update RunCombat set Overkill=Overkill+$Pen where (CloseWith=$arow[ID] or ID=$arow[CloseWith])");
1495 }
1496
1497 if ( $OverkillThem != 1 ) {
1498 if ( $arow['CombatRole'] == 'attacker' ) {
1499 $OverkillDefenders+=$OverkillThem;
1500 } else {
1501 $OverkillAttackers+=$OverkillThem;
1502 }
1503 }
1504
1505 $OverkillHits = $HitsLeft = $Hits;
1506 $summedOpponentStr = 0;
1507
1508 $opponentCount = db_fetch_single( "Select Count(ID) from RunCombat where (CloseWith=$arow[ID] or ID=$arow[CloseWith])" );
1509 if ( $opponentCount >= 1 ) {
1510 $opponentQ = db_query( "Select ID, Name, CombatNr, Strength, Type from RunCombat where (CloseWith=$arow[ID] or ID=$arow[CloseWith])" );
1511 while ( $opponent = db_fetch_array( $opponentQ ) ) {
1512 // echo "Hello. My name is Inigo Montoya (a.k.a $arow[Name]), you killed my father, prepared to die, $opponent[name]!<br>";
1513 $opponentStr = $opponent['Strength'];
1514 if (stripslashes($opponent['Type']) == 'Daimons') {
1515 $opponentStr *= 4;
1516 } else if (stripslashes($opponent['Type']) == 'Monsters') {
1517 $opponentStr *= 2;
1518 }
1519 // echo "Your strength is $opponentStr<br>";
1520 $summedOpponentStr += $opponentStr;
1521 $HisHits=floor($Hits*$opponentStr/$opponentTotalStr);
1522 if ( $HisHits > $HitsLeft ) {
1523 // This should now never happen.
1524 echo "Error in individual hits calculation, ind:$HisHits>left:$HitsLeft.<br>arow: "; var_dump($arow); echo "<br><hr/>\n";
1525 $HisHits=$HitsLeft/2;
1526 }
1527 $HitsLeft-=$HisHits;
1528 // Randomize the hits a little bit
1529 $HisHits+=rand(min(-2,$HisHits*-0.2),max(2,$HisHits*0.2));
1530 if ($HisHits<0) {
1531 $HisHits = 0;
1532 }
1533 $ActualHits=$HisHits;
1534 if ( $OverkillThem != 1 ) {
1535 $ActualHits=round($HisHits/$OverkillThem);
1536 $BeforeHits = round($HisHits);
1537 $msg.=addtag($armyBanners[$arow['Army']].stripslashes($arow["Name"])." ($arow[CombatNr]) score $ActualHits hits on $opponent[Name] ($opponent[CombatNr]) ($BeforeHits before overkill).<br>\n",$arow["Commander"]);
1538 //echo stripslashes($arow["Name"])." ($arow[CombatNr]) score $HisHits hits on $opponent[Name] ($opponent[CombatNr]) ($BeforeHits before overkill).<br>";
1539 } else {
1540 $msg.=addtag($armyBanners[$arow['Army']].stripslashes($arow["Name"])." ($arow[CombatNr]) score $HisHits hits on $opponent[Name] ($opponent[CombatNr]).<br>\n",$arow["Commander"]);
1541 db_query("update RunCombat set CommanderXP=CommanderXP+2 where ID=$arow[ID]");
1542 //echo stripslashes($arow["Name"])." ($arow[CombatNr]) score $HisHits hits on $opponent[Name] ($opponent[CombatNr]).<br>\n";
1543 }
1544
1545 /*
1546 * Count the actual hits inflicted on attackers or defenders.
1547 * Counting here eliminates any text errors that might have occurred.
1548 */
1549 if ($arow["CombatRole"]=="attacker") {
1550 $ActualHitsDefenders+=$ActualHits; $HitsDefenders+=round($HisHits);
1551 } else {
1552 $ActualHitsAttackers+=$ActualHits; $HitsAttackers+=round($HisHits);
1553 }
1554 db_query( "Update RunCombat set CloseHits=CloseHits+$ActualHits where ID=$opponent[ID]" );
1555 }
1556 }
1557 if ($summedOpponentStr!=$opponentTotalStr) { echo "Error in opponent str calculation, sum:$summedOpponentStr!=os:$opponentTotalStr.<br>arow: "; var_dump($arow); echo "<br><hr/>\n"; }
1558 //$msg.=addtag(stripslashes($arow["Name"])." ($arow[CombatNr]) score $OverkillHits hits.<br>\n",$arow["Commander"]);
1559 //echo stripslashes($arow["Name"])." ($arow[CombatNr]) score $OverkillHits hits.<br>\n";
1560 db_query("update RunCombat set HitsCaused=HitsCaused+$Hits where ID=$arow[ID]");
1561 }
1562 $msg.="<span style=\"color: white;\"><b>Total close combat hits suffered: Attackers: ";
1563 if ($OverkillAttackers) {
1564 $msg.="$ActualHitsAttackers ($HitsAttackers before overkill)";
1565 } else {
1566 $msg.="$ActualHitsAttackers";
1567 }
1568 $msg.=", Defenders: ";
1569 if ($OverkillDefenders) {
1570 $msg.="$ActualHitsDefenders ($HitsDefenders before overkill)";
1571 } else {
1572 $msg.="$ActualHitsDefenders";
1573 }
1574 $msg.="</b></span><br>\n";
1575
1576 /* bonus for fighting well */
1577 if ($AS>$DS*1.5&&$ActualHitsDefenders>$ActualHitsAttackers*1.5) {
1578 db_query("update RunCombat set CommanderHonour=CommanderHonour+3, CommanderPrestige=CommanderPrestige+1, CommanderXP=CommanderXP+1 where CombatRole='defender' and CombatLine=$i and CloseWith is not NULL");
1579 } else if ($DS>$AS*1.5&&$ActualHitsAttackers>$ActualHitsDefenders*1.5) {
1580 db_query("update RunCombat set CommanderHonour=CommanderHonour+3, CommanderPrestige=CommanderPrestige+1, CommanderXP=CommanderXP+1 where CombatRole='attacker' and CombatLine=$i and CloseWith is not NULL");
1581 }
1582
1583 } else {
1584 /* people not in close combat get only half the honour ... */
1585 db_query("update RunCombat set CloseCount=0, CommanderHonour=CommanderHonour+1 where CombatLine=$i");
1586 }
1587 }
1588}
1589
1590
1591
1592/**
1593 * @param unknown_type $Fortification
1594 * @param unknown_type $count
1595 */
1596function panic_checks($Fortification, $count) {
1597 global $debug;
1598 global $msg, $Fortification, $armyBanners;
1599
1600 /* archer units without infantry screens panic */
1601 /* we set the overkill factor up, this will make them retreat further down */
1602 $InfAtt = intval(db_fetch_single("select count(ID) from RunCombat where CombatRole='attacker' and Type!='Archers' and CombatLine is not NULL"));
1603 if ($InfAtt==0) {
1604 if ($debug>20) echo "Possible Attacker Archer panic<br>\n";
1605 db_query("update RunCombat set Morale=GREATEST(1,Morale-10) where CombatRole='attacker' and Type='Archers'");
1606 $ares = db_query("select * from RunCombat where CombatRole='attacker' and Type='Archers' and CloseHits=0 and RangedHits=0 and CombatLine is not NULL");
1607 while ($arow=db_fetch_array($ares)) {
1608 if ($debug>20) echo "Unit $arow[Name] (Morale $arow[Morale])...";
1609 if (rand(0,120)>$arow["Morale"]) {
1610 if ($debug>20) echo "yes, panic.<br>\n";
1611 $msg.=addtag($armyBanners[$arow['Army']]."With no infantry cover left, ".stripslashes($arow["Name"])." ($arow[CombatNr]) panic and retreat.<br>\n",$arow["Commander"]);
1612 db_query("update RunCombat set Overkill=500 where ID=$arow[ID]");
1613 } else if ($debug>20) echo "no<br>\n";
1614 }
1615 }
1616 $InfDef = intval(db_fetch_single("select count(ID) from RunCombat where CombatRole='defender' and Type!='Archers' and CombatLine is not NULL"));
1617 if ($InfDef==0&&$Fortification==0) {
1618 if ($debug>20) echo "Possible Defender Archer panic<br>\n";
1619 db_query("update RunCombat set Morale=GREATEST(1,Morale-10) where CombatRole='attacker' and Type='Archers'");
1620 $ares = db_query("select * from RunCombat where CombatRole='defender' and Type='Archers' and CloseHits=0 and RangedHits=0 and CombatLine is not NULL order by Serial ASC");
1621 while ($arow=db_fetch_array($ares)) {
1622 if ($debug>20) echo "Unit $arow[Name] (Morale $arow[Morale])...";
1623 if (rand(20,125)>$arow["Morale"]) {
1624 if ($debug>20) echo "yes, panic.<br>\n";
1625 $msg.=addtag($armyBanners[$arow['Army']]."With no infantry cover left, ".stripslashes($arow["Name"])." ($arow[CombatNr]) panic and retreat.<br>\n",$arow["Commander"]);
1626 db_query("update RunCombat set Overkill=500 where ID=$arow[ID]");
1627 } else if ($debug>20) echo "no<br>\n";
1628 }
1629 }
1630
1631 /* cavalry panics if they can't get through the walls in time */
1632 if ($Fortification>0&&$count>5) {
1633 $ares = db_query("select * from RunCombat where CombatRole='attacker' and Type='Cavalry' and CombatLine<=0 order by Serial ASC");
1634 while ($arow=db_fetch_array($ares)) {
1635 if (rand(0,100)>$arow["Morale"]-(($count-5)*5)) {
1636 $msg.=addtag($armyBanners[$arow['Army']]."Still riding up and down in front of the walls, ".stripslashes($arow["Name"])." ($arow[CombatNr]) give up and retreat.<br>\n",$arow["Commander"]);
1637 db_query("update RunCombat set CombatLine=GREATEST(-4,CombatLine-1), Overkill=250 where ID=$arow[ID]");
1638 }
1639 }
1640 }
1641
1642 /* panic due to overwhelming odds */
1643 $check = "";
1644 $AS = db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='attacker' and CombatLine is not NULL");
1645 $DS = db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='defender' and CombatLine is not NULL");
1646 if ($AS*rand(8,12)+10<$DS) { $check="attacker"; } else if ($DS*rand(8,12)+10<$AS) { $check="defender"; }
1647 if ($check!="") { /* check for panic*/
1648 $msg.="<br>\n<span style=\"color: #E0E0FF;\">The ${check}s are vastly outnumbered, and panic spreads throughout their ranks.</span><br>\n";
1649 db_query("update RunCombat set Morale=GREATEST(0,Morale-10), Overkill=Overkill+20 where CombatRole='$check'");
1650 }
1651}
1652
1653function damage_effects($Here, $RegName, $RegType, $Fortification, $FortDamage, $count, $OverkillAttackers, $OverkillDefenders) {
1654 global $debug;
1655 global $msg, $ShortSummary, $armyBanners;
1656
1657 $msg.="<br>\n";
1658 /* TODO: All this stuff should really be done in CSS */
1659 $COL_LEADER="#DDDDDD";
1660
1661
1662 $TCHitsAttackers=0;$TCHitsDefenders=0;$TRHitsAttackers=0;$TRHitsDefenders=0;
1663 $Dead['attacker']=0; $Dead['defender']=0; $UndeadKilled=0;
1664 $ares = db_query("select * from RunCombat where CombatLine is not NULL and ( CloseHits > 0 or RangedHits > 0 or Overkill > 0 ) order by Serial ASC");
1665 while ($arow=db_fetch_array($ares)) {
1666 $role=$arow['CombatRole'];
1667 $div=round((10000+($arow['Armour']*(100-$arow['Damage']))*3) /1000);
1668 /* some units take more or less damage */
1669 switch ($arow["Type"]) {
1670 case "Special Forces": $div+=rand(1,4); break;
1671 case "Cavalry": $div++; break;
1672 case "Archers": $div=max(1,$div-1); break;
1673 case "Monsters": $div*=3; break;
1674 case "Daimons": $div*=4; break;
1675 case "Peasants": $div=max(1,$div-2); break;
1676 }
1677 /* formation effects */
1678 switch ($arow["Tactic"]) {
1679 case "box": $div++; break;
1680 case "wedge": $div=max(1,$div-1); break;
1681 case "skirmish": $div=max(1,$div-2); break;
1682 }
1683 if ($role=="defender"&&$Fortification>0&&$arow["CombatLine"]>0) {
1684 if ($arow["CombatLine"]==1) {
1685 /* main wall == best defense */
1686 $Protection=10+round($Fortification*(100-$FortDamage)/10);
1687 } else if ($RegType=="Stronghold") {
1688 $Protection=round($Fortification*(100-$FortDamage)/10);
1689 } else {
1690 $Protection=round($Fortification/2*(100-$FortDamage)/10);
1691 }
1692 } else if ($arow["Position"]=="dug in") {
1693 $Protection=10;
1694 } else {
1695 $Protection=0;
1696 }
1697 $CHits=round($arow["CloseHits"]/(1+($Protection/100)));
1698 $RHits=round($arow["RangedHits"]/(1+($Protection/100)));
1699
1700 if ( $arow['MarshalFormation'] == 'Shieldwall' ) {
1701 $RHits /= 3;
1702 }
1703
1704 $Hits=$CHits+$RHits;
1705 if ($role=='attacker') {
1706 $TCHitsAttackers+=$CHits;
1707 $TRHitsAttackers+=$RHits;
1708 } else {
1709 $TCHitsDefenders+=$CHits;
1710 $TRHitsDefenders+=$RHits;
1711 }
1712
1713 /* Testing: Considerably reduced casualties: */
1714 $div*=1.5;
1715
1716 $loss=min(round($Hits/$div),$arow["Strength"]);
1717 if ( $loss==0 && rand(0,50)<$Hits && rand(0,5)<4 ) {
1718 $loss=1; // chance of killing at least one, provided you did cause some hits
1719 }
1720 $dead=min($loss,round( rand($CHits/($div*6),$CHits/($div*2))+rand($RHits/($div*6),$RHits/($div*2)) ));
1721 $notdead=$loss-$dead;
1722 if ($debug>20) { echo "$arow[Name]: Close: $arow[CloseHits] -> $CHits / $arow[RangedHits] -> $RHits / Total: $Hits / $div div ===> $loss losses ($dead dead)<br>\n";}
1723
1724 $umsg = stripslashes($arow["Name"])." ($arow[CombatNr]) ";
1725 if ($CHits>0||$RHits>0) {
1726 if ($CHits>0&&$RHits>0)
1727 $umsg.= "take $Hits hits ($CHits in close combat, $RHits from archer fire)";
1728 else if ($RHits>0)
1729 $umsg.= " take $Hits hits from archer fire";
1730 else $umsg.= " take $Hits hits in close combat";
1731 if ($Protection>0) {
1732 $umsg.=" (reduced due to fortifications)";
1733 }
1734 if ($arow['MarshalFormation']=='Shieldwall') {
1735 $umsg.=" (ranged hits reduced by the shieldwall)";
1736 }
1737 if ($loss==0) { $umsg.=". No casualties"; }
1738 else {
1739 $umsg.=", which cause $loss casualties";
1740 $Dead[$role]+=$loss;
1741 if ( $arow['Type']=="Undead" ) {
1742 $UndeadKilled+=$loss;
1743 }
1744 }
1745 } else $umsg.=" are shocked";
1746 $Capture=0;
1747 if ($loss>=$arow["Strength"]) {
1748 $umsg.=", wiping the unit out.<br>\n";
1749 /* don't delete - we still need stuff like the Commander values! */
1750 db_query("update RunCombat set Strength=0, Wounded=Wounded+$notdead, Position='scattered', CombatLine=NULL, Overkill=0, Banners=0 where ID=$arow[ID]");
1751 $Capture=8;
1752 } else {
1753 $bquery = "update RunCombat set ";
1754 /* equipment damage */
1755 $dam=round(sqrt($Hits/$arow["Strength"]));
1756 $bquery.= "ChangeDamage=ChangeDamage+$dam";
1757 if ($Hits==0) {
1758 $MinFlee=5; $MaxFlee=25; $Panic=30;
1759 } else if ($Hits>$arow["Strength"]*10||$arow["Strength"]<$arow["FullStrength"]*0.25) {
1760 $MinFlee=80; $MaxFlee=200; $Panic=200;
1761 } else if ($Hits>$arow["Strength"]*5||$arow["Strength"]<$arow["FullStrength"]*0.5) {
1762 $MinFlee=40; $MaxFlee=150; $Panic=150;
1763 } else if ($Hits>$arow["Strength"]*2||$arow["Strength"]<$arow["FullStrength"]*0.75) {
1764 $MinFlee=20; $MaxFlee=100; $Panic=100;
1765 } else {
1766 $MinFlee=10; $MaxFlee=50; $Panic=50;
1767 }
1768 $MaxFlee+=$count; $Panic+=$count;
1769
1770 /* encounter modifications */
1771 if ($arow["Encounter"]=="Evade") {
1772 $MinFlee*=1.5; $MaxFlee*=1.25; $Panic*=1.25;
1773 } else if ($arow["Encounter"]=="Defend") {
1774 if ($role=="attacker") {
1775 $MinFlee*=1.5; $MaxFlee*=1.5; $Panic*=1.5;
1776 } else {
1777 $MinFlee*=0.5; $MaxFlee*=0.75; $Panic*=0.9;
1778 }
1779 }
1780
1781 /* formation effects */
1782 switch ($arow["Tactic"]) {
1783 case "box": $MinFlee*=0.8; $MaxFlee*=0.9; $Panic*=1.1; break;
1784 case "skirmish": $MinFlee*=1.4; $MaxFlee*=1.6; $Panic*=2; break;
1785 }
1786
1787 if ($Fortification>1&&$role=="defender") {
1788 /* troops in fortifications don't retreat as easily */
1789 $MinFlee/=$Fortification;
1790 $MaxFlee/=$Fortification;
1791 $Panic/=$Fortification;
1792 } else if ($Fortification>1&&$role=="attacker"&&$arow["Type"]=="Cavalry") {
1793 /* cavalry units left alone against forts (no inf or MI) will bail out */
1794 $MyInf = db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='attacker' and CombatLine is not NULL and Type not in ('Cavalry','Archers')");
1795 if ($MyInf==0) {
1796 $MinFlee+=25; $MaxFlee+=50; $Panic=$Panic/2;
1797 }
1798 }
1799
1800 /* Banner bonus */
1801 if ($arow["Banners"]>0) {
1802 $Eff = min(2,$arow["Banners"]*100/$arow["Strength"]);
1803 if ($Eff>1) { $Panic/=$Eff; }
1804 }
1805
1806 $MinFlee+=$arow["Overkill"]; $MaxFlee+=$arow["Overkill"];
1807 $Panic+=$arow["Overkill"];
1808
1809 $RetreatOrdered = false;
1810 /* my retreat orders */
1811 if ($arow['Strength']-$loss < ((100-$arow['Withdraw'])*$arow['FullStrength'])/100) {
1812 if ($debug>20) echo "Withdraw triggered: ($arow[Strength]<(100-$arow[Withdraw])*$arow[FullStrength])<br>\n";
1813 $RetreatOrdered = true;
1814 }
1815
1816 /* round */
1817 $MinFlee=round($MinFlee); $MaxFlee=round($MaxFlee); $Panic=round($Panic);
1818
1819 /* check for morale, panic and flight - not in first two rounds, and undead and daimons never flee */
1820 if (($RetreatOrdered || $count>2 && rand($MinFlee,$MaxFlee)>$arow["Morale"]+$arow["Cohesion"]) && $arow["Type"]!="Undead" && $arow["Type"]!="Daimons") {
1821 /* safety catch - don't flee if we're the last one standing */
1822 if (db_fetch_single("select count(*) from RunCombat where CombatLine is not NULL")>1) {
1823 $strengthleft = $arow["Strength"]-$loss;
1824 if (rand(0,$Panic)>$arow["Morale"]+$arow["Training"]) {
1825 /* panic -> scatter */
1826 $Capture=5;
1827 $umsg.=", causing panicked flight among the survivors";
1828 if ($arow["CloseHits"]>0) {
1829 $morelosses = rand($strengthleft/10,$strengthleft/3);
1830 } else {
1831 $morelosses = rand(-$strengthleft/3,$strengthleft/5);
1832 }
1833 $ExtraDamage=rand(5,10);
1834 $bquery.= ", CombatLine=NULL, Overkill=0, ChangeDamage=ChangeDamage+$ExtraDamage, ChangeMorale=ChangeMorale-($ExtraDamage*2), Position='scattered'";
1835 $notdead=rand(0,$notdead/5);
1836 if ($debug>20) { echo "** Unit $arow[Name] scattered<br>\n"; }
1837 } else {
1838 /* controlled retreat */
1839 $Capture=2;
1840 $umsg.=", making the unit retreat from the battlefield";
1841 if ($arow["CloseHits"]>0) {
1842 $morelosses = rand(-$arow["Training"],$strengthleft/5);
1843 } else {
1844 $morelosses = 0;
1845 }
1846 $ExtraDamage=rand(0,5);
1847 $bquery.= ", CombatLine=NULL, Overkill=0, Position='retreated', ChangeMorale=ChangeMorale-($ExtraDamage*2) ";
1848 if ($debug>20) { echo "** Unit $arow[Name] retreated<br>\n"; }
1849 $notdead=rand($notdead/1.2,$notdead);
1850 }
1851 if ($morelosses>0) {
1852 $umsg.=", $morelosses additional men get slaughtered during the retreat";
1853 $loss+=$morelosses;
1854 $Dead[$role]+=$morelosses;
1855 if ( $arow['Type']=='Undead' ) {
1856 $UndeadKilled+=$morelosses;
1857 }
1858 }
1859 }
1860 }
1861
1862 /* not easy to be captured when there was no close combat */
1863 if ($arow["CloseHits"]==0&&$Capture>0) {
1864 $Capture=floor($Capture/2);
1865 }
1866
1867 /* Various fortification things */
1868 if ($Fortification>1&&$arow["CombatLine"]==1&&$role=="attacker") {
1869 /* getting thrown back when assaulting fortifications */
1870 $PseudoHits=$Hits;
1871 if ($OverkillAttackers) $PseudoHits=$Hits*$OverkillAttackers;
1872 else if ($OverkillDefenders) $PseudoHits=$Hits/$OverkillDefenders;
1873 if ($PseudoHits*$Fortification>($arow["HitsCaused"]*2)) {
1874 $umsg.=", throwing them back from the fortifications";
1875 $morelosses=min($arow["Strength"],rand(-round($arow["Strength"]/10),round(($Fortification*2*$arow["Strength"])/100)));
1876 if ($morelosses>0) {
1877 $umsg.=", causing another $morelosses casualties";
1878 $loss+=$morelosses;
1879 $Dead[$role]+=$morelosses;
1880 if ( $arow['Type']=='Undead' ) {
1881 $UndeadKilled+=$morelosses;
1882 }
1883 if ($loss>=$arow['Strength']) {
1884 $loss=$arow['Strength'];
1885 $umsg.=" and wiping the unit out";
1886 db_query("update RunCombat set Position='scattered', CombatLine=NULL, Overkill=0, Banners=0 where ID=$arow[ID]");
1887 }
1888 }
1889 $bquery.= ", CombatLine=CombatLine-1";
1890 } else {
1891 $FortBreached=true;
1892 }
1893 /* losing a siege engine */
1894 $lossratio = $loss/$arow["Strength"];
1895 $SL = min($arow["SiegeEngines"],round(rand($lossratio/10,$lossratio*2)*$arow["SiegeEngines"]));
1896 if ($SL>0) {
1897 if ($SL>1) $umsg.=". $SL siege engines are destroyed in the assault";
1898 else $umsg.=". One siege engine is destroyed during the attack";
1899 $bquery.=", SiegeEngines=SiegeEngines-$SL";
1900 }
1901 }
1902
1903 /* possibility of losing a banner */
1904 if ($arow["Banners"]>0) {
1905 $lossratio = $loss/$arow["Strength"];
1906 $BL = min($arow["Banners"],round(rand($lossratio/10,$lossratio*2)*$arow["Banners"]));
1907 if ($BL>0) {
1908 $RN = db_fetch_single("select Name from Realms where ID=$arow[Realm]");
1909 if ($BL>1) $umsg.=". $BL $RN banners fall";
1910 else $umsg.=". One $RN banner is lost";
1911 $bquery.=", Banners=Banners-$BL";
1912 }
1913 }
1914 if ($loss>$arow["Strength"]) { /*can happen with the extra casualties*/
1915 $loss=$arow["Strength"];
1916 $bquery.=", Position='scattered', CombatLine=NULL ";
1917 }
1918 $bquery.=", Strength=Strength-$loss, Wounded=Wounded+$notdead ";
1919 $bquery.=" where ID=$arow[ID]";
1920 db_query($bquery);
1921 $umsg.=".<br>\n";
1922 }
1923
1924 if ($arow["Commander"]>0&&$arow["CommanderPresent"]=="yes"&&($arow['CloseHits']>0||$arow['RangedHits']>0)) {
1925 $myFullStrength = $arow['Strength'];
1926 if ($arow['Type']=='Daimons') {
1927 $myFullStrength *= 4;
1928 } else if ($arow['Type']=='Monsters') {
1929 $myFullStrength *= 2;
1930 }
1931
1932 if ($Fortification>0&&$role=="defender") { $Capture=round($Capture/2); }
1933 if ($Hits>0&&$myFullStrength>0) {
1934 $Wounded=$arow["RangedHits"]/($myFullStrength);
1935 $Wounded+=$arow["CloseHits"]/($myFullStrength*2);
1936 $Wounded+=$Hits/200;
1937 $woundChance=min(90,round($Wounded/2));
1938 } else {
1939 $woundChance=0;
1940 }
1941 /* since heroes fight frontline, they are ALWAYS wounded if their unit gets wiped out */
1942 if ($arow["CommanderSubclass"]=="Hero"&&$arow["Strength"]==0&&$Hits>0) $woundChance=200;
1943
1944 // don't wound NPCs that often, they sometimes lead multiple units, etc.
1945// if ($arow['CommanderMainclass']=='NPC') $woundChance*=0.75;
1946
1947 $myStatus=db_fetch_single("select Status from Players where ID=$arow[Commander]");
1948 if ($myStatus=='dead'|| (db_fetch_single("select WoundRate from Players where ID=$arow[Commander]")>= 20 && db_fetch_single("Select Value from Globals where Var='Mortality'"))) {
1949 $Capture=0; // can't capture dead or mortally wounded guys
1950 }
1951
1952 if ($arow['CloseWith']) {
1953 $surroundStrength = db_fetch_single("Select Sum(Strength) from RunCombat where CloseWith=$arow[ID] or ID=$arow[CloseWith]");
1954 } else {
1955 $surroundStrength = db_fetch_single("Select Sum(Strength) from RunCombat where CloseWith=$arow[ID]");
1956 }
1957
1958 if ($surroundStrength > 10*$myFullStrength) {
1959 $woundChance += 60;
1960 } else if ($surroundStrength > 5*$myFullStrength) {
1961 $woundChance += 40;
1962 } else if ($surroundStrength > 2*$myFullStrength) {
1963 $woundChance += 30;
1964 } else if ($surroundStrength > $myFullStrength) {
1965 $woundChance += 20;
1966 }
1967
1968 $surroundFactor = min(30, $surroundStrength/($myFullStrength*4));
1969
1970 $opponents = db_get_array( "Select ID from RunCombat where CloseWith=$arow[ID] or RangedTarget=$arow[ID]" );
1971 $numOpps = count($opponents);
1972 if ($numOpps == 0) {
1973 $opponent = $arow['CloseWith'];
1974 if (!$opponent) {
1975 DebugLog("error", "OvercrowdingCombat: (1) Unit $arow[ID], $arow[Name] ($arow[CombatNr]) in line $arow[CombatLine] took damage (C: $arow[CloseHits] R: $arow[RangedHits] O: $arow[Overkill]) with no detectable opponent!");
1976 // TODO: Something more useful than this??
1977 }
1978 } else if ($numOpps == 1) {
1979 $opponent = $opponents[0];
1980 if (!$opponent) {
1981 DebugLog("debug", "OvercrowdingCombat: (o1) Unit $arow[ID], $arow[Name] ($arow[CombatNr]) in line $arow[CombatLine] took damage (C: $arow[CloseHits] R: $arow[RangedHits] O: $arow[Overkill]) with no detectable opponent!");
1982 /*echo "here are his opponents: <pre>";
1983 print_r( $opponents );
1984 echo "</pre>";*/
1985 }
1986 } else {
1987 if ($arow['CloseWith'] && rand(0,100) < 50) {
1988 $opponent = $arow['CloseWith'];
1989 } else {
1990 $opponent = $opponents[rand(0,$numOpps-1)];
1991 if (!$opponent) {
1992 DebugLog("debug", "OvercrowdingCombat: (o2) Unit $arow[ID], $arow[Name] ($arow[CombatNr]) in line $arow[CombatLine] took damage (C: $arow[CloseHits] R: $arow[RangedHits] O: $arow[Overkill]) with no detectable opponent!");
1993 /*echo "here are his opponents: <pre>";
1994 print_r( $opponents );
1995 echo "</pre>";*/
1996 }
1997 }
1998 }
1999 if (!$opponent) {
2000 /*echo "****BIG BIG PROBLEM**** We have someone who took damage, but who isn't fighting with anyone or targeted by anyone!!<br/>";
2001 echo "Unit is $arow[ID], $arow[Name] ($arow[CombatNr]) in line $arow[CombatLine]<br/>";*/
2002 DebugLog("error", "OvercrowdingCombat: (2) Unit $arow[ID], $arow[Name] ($arow[CombatNr]) in line $arow[CombatLine] took damage (C: $arow[CloseHits] R: $arow[RangedHits] O: $arow[Overkill]) with no detectable opponent!");
2003 /*echo "Here's his row: <pre>";
2004 print_r( $arow );
2005 echo "</pre>";*/
2006 }
2007
2008 list($oppName, $oppNr, $oppRealm, $oppCom) = db_fetch_single("Select Name, CombatNr, Realm, Commander from RunCombat where ID=$opponent");
2009 if ($oppCom) {
2010 if ($arow['CommanderMainclass']!='NPC') {
2011 $oppComName = db_fetch_single("Select CONCAT(CONCAT(P.CharacterName,' '),F.Name) from Players P join ".db_world_dbname(0).".Families F on P.Player=F.ID where P.ID=$oppCom");
2012 } else {
2013 $oppComName = db_fetch_single("Select P.CharacterName from Players P where P.ID=$oppCom");
2014 }
2015 } else {
2016 $oppComName = "a militia unit of ".db_fetch_single( "Select Name from Realms where ID=$oppRealm" );
2017 }
2018
2019 /* Double the wounding rate under the new system */
2020 if (rand(0,100)<$woundChance*2) {
2021 $name=player_title($arow["Commander"],false,true);
2022 $woundDamage = rand(1,6) + rand(0,ceil($surroundFactor/2.0)) + rand(0,ceil($surroundFactor/2.0));
2023 $totalWound = $woundDamage + $arow['WoundRate'];
2024 if ($totalWound>10) {
2025 /* already wounded this battle! */
2026 if ($arow['CommanderSubclass']!='Hero'&&$arow['CommanderMainclass']!='NPC') {
2027 if ($totalWound >= 20 && db_fetch_single("Select Value from Globals where Var='Mortality'")) {
2028 $woundMessage = 'killed';
2029 } else {
2030 $woundMessage = 'seriously wounded';
2031 }
2032 $umsg.="<span style=\"color: $COL_LEADER;\">$name has been $woundMessage by $oppName ($oppNr).</span><br>";
2033 if ($oppCom) {
2034 $ShortSummary.="$name was $woundMessage by $oppComName's unit.<br>";
2035 } else {
2036 $ShortSummary.="$name was $woundMessage by $oppComName.<br>";
2037 }
2038 } else {
2039 /* Heroes get killed in battle! */
2040 $umsg.="<span style=\"color: $COL_LEADER;\">$name has been killed by $oppName ($oppNr).</span><br>";
2041 if ($arow['CommanderSubclass']=='Hero') {
2042 $commanderGender = db_fetch_single("Select Gender from Players where ID=$arow[Commander]");
2043 if ($oppCom) {
2044 $ShortSummary .= "The ".g('hero',$commanderGender)." $name was killed by $oppComName's unit.<br>";
2045 } else {
2046 $ShortSummary.="The " . g('hero', $commanderGender) . " $name was killed by $oppComName.<br>";
2047 }
2048 } else {
2049 if ($oppCom) {
2050 $ShortSummary.="$name has been killed by $oppComName's unit.<br>";
2051 } else {
2052 $ShortSummary.="$name has been killed by $oppComName.<br>";
2053 }
2054 }
2055 }
2056 if ($oppCom && bountycheck($arow["Commander"],$oppCom) != "") {
2057 /* there was a bounty on his head! */
2058 $umsg.="$oppComName collects the bounty.<br>\n";
2059 }
2060 } else if ($myStatus!="dead" && $myStatus!="seriouswound" && $myStatus!="prison") {
2061 $umsg.="<span style=\"color: $COL_LEADER;\">$name has been wounded by $oppName ($oppNr).</span><br>";
2062 }
2063 if ($totalWound<0) {
2064 $totalWound = 0;
2065 }
2066 db_query("Update RunCombat set WoundRate=$totalWound where ID=$arow[ID]");
2067 } else if ($Capture>0) {
2068 /* may be captured */
2069 if ($role=="attacker") {
2070 $enemy="defender";
2071 } else {
2072 $enemy="attacker";
2073 }
2074 if ($arow["CombatLine"]) {
2075 $countenemies=max(1,db_fetch_single("select sum(Strength) from RunCombat where CombatLine=$arow[CombatLine] and CombatRole='$enemy' and CloseWith is not NULL"));
2076 } else {
2077 $countenemies=db_fetch_single("select count(*) from RunCombat where CombatRole='$enemy'");
2078 }
2079 if ($debug>20) echo "Commander of $arow[Name] may be captured: Chance = min(90,(sqrt($countenemies)+1)/5*$Capture) => ";
2080 $captureChance = min(min(90,$Capture*10),(sqrt($countenemies)+1)/10*$Capture);
2081 if ($arow["Type"]=="Daimons") $captureChance*=0.333; // daimons aren't easily captured...
2082 if ($debug>20) echo "Capture chance: $captureChance %<br>\n";
2083
2084 if (rand(0,100)<$captureChance) {
2085 /* remove player and make his unit pay a (temporary) morale penalty */
2086 /* find prisonrealm */
2087 $curPrisonRealm=db_fetch_single("Select PrisonRealm from RunCombat where ID=$arow[ID]");
2088 if (isset($curPrisonRealm) && is_numeric($curPrisonRealm)) {
2089 // Can't capture someone who's already captured! (How would this happen, anyway?)
2090 continue;
2091 }
2092 $name=player_title($arow["Commander"],false,true);
2093 $PRName=db_fetch_single("select Name from Realms where ID=$oppRealm");
2094 $umsg.="<span style=\"color: $COL_LEADER\">$name has been captured by $oppName ($oppNr).</span><br/>";
2095 if ( $oppCom ) {
2096 $ShortSummary.="$name was captured by $oppComName's unit.<br>";
2097 } else {
2098 $ShortSummary.="$name was captured by $oppComName.<br>";
2099 }
2100 db_query("update RunCombat set Morale=Morale*0.75 where ID=$arow[ID]");
2101 /* if he was a rebel leader, the rebellion is over */
2102 $Loy = db_fetch_single("select Loyalty from Players where ID=$arow[Commander]");
2103 if ($Loy=="rebelleader") {
2104 $ShortSummary.="This also ends the rebellion ".g("he",-1,$arow['Commander'])." was leading.<br>\n";
2105 }
2106 db_query("Update RunCombat set PrisonRealm=$oppRealm where ID=$arow[ID]");
2107 }
2108 }
2109 }
2110 $msg.=addtag($armyBanners[$arow['Army']].$umsg,$arow["Commander"]);
2111 }
2112 $hitsAttackers=$TCHitsAttackers+$TRHitsAttackers;
2113 $hitsDefenders=$TCHitsDefenders+$TRHitsDefenders;
2114 $msg.="<span style=\"color: white;\"><b>Total hits suffered: Attackers: ";
2115 $msg.="$hitsAttackers ($TCHitsAttackers from close combat and $TRHitsAttackers from ranged)";
2116 $msg.=", Defenders: ";
2117 $msg.="$hitsDefenders ($TCHitsDefenders from close combat and $TRHitsDefenders from ranged)";
2118 $msg.="</b></span><br>\n";
2119 if ($Dead['attacker']+$Dead['defender']>0) {
2120 $msg.="<span style=\"color: white;\"><b>Total casualties: $Dead[attacker] attackers, $Dead[defender] defenders</b></span><br>\n";
2121 global $TotalDead;
2122 $TotalDead+=$Dead['attacker']+$Dead['defender']-$UndeadKilled;
2123 }
2124}
2125
2126function after_battle_status($RegName,$Here) {
2127 // Wounding
2128 $woundQ = db_query("Select * from RunCombat where WoundRate>0");
2129 while ($wound=db_fetch_array($woundQ)) {
2130 $name=player_title($wound["Commander"],false,true);
2131 if ($wound['WoundRate'] > 10 && ($wound['CommanderSubclass']=="Hero" || $wound['CommanderMainclass']=="NPC") || $wound['WoundRate'] >= 20 && db_fetch_single("Select Value from Globals where Var='Mortality'")) {
2132 $charmsg="You have been killed during the battle in $RegName!";
2133 message($wound["Commander"],"Killed!",$charmsg,"Personal");
2134 $ShowMiracle = wounded($wound['Commander'], 'deadly', -1, -1, true);
2135 /* message to player */
2136 if (!$ShowMiracle) {
2137 $usermsg = "<br><hr/><b>Important information about your character $name:</b>\n";
2138 if ($wound['CommanderSubclass']=="Hero") {
2139 $usermsg.= "<p>This hero character was killed during a battle in $RegName.</p>";
2140 } else {
2141 $usermsg.= "<p>This character was killed during a battle in $RegName.</p>";
2142 }
2143 $User = db_fetch_single("select Player from Players where ID=$wound[Commander]");
2144 $FM = db_fetch_single("select FamilyMessage from ".db_world_dbname(0).".UserTexts where ID=$User");
2145 if ($FM!="") $FM.="<br>\n";
2146 $FM.=$usermsg;
2147 db_query("update ".db_world_dbname(0).".UserTexts set FamilyMessage='".db_string($FM)."',FMseen=0 where ID=$User");
2148 $myAge = floor(db_fetch_single("select Age from Players where ID=$wound[Commander]")/12);
2149 if ($wound['CommanderSubclass']=="Hero") {
2150 writehistory(0,$name,"Killed as a hero in battle at age $myAge",1,$wound["Commander"]);
2151 } else {
2152 writehistory(0,$name,"Killed in battle at age $myAge",1,$wound["Commander"]);
2153 }
2154 $altmsg="$name was killed during a battle in $RegName.";
2155 character_gone($wound["Commander"],$altmsg,$altmsg,'LeaveWorld');
2156 }
2157 } else {
2158 if ($wound['WoundRate'] <= 5) {
2159 // Very light wounds have a chance of turning into light wounds because of battlefield conditions
2160 $Age = db_fetch_single("Select Age from Players where ID=$wound[Commander]");
2161 if (rand(20,100) < $Age) {
2162 $wound['WoundRate'] = rand(6,8);
2163 db_query("Update RunCombat set WoundRate=$wound[WoundRate] where ID=$wound[ID]");
2164 }
2165 }
2166 $ShowMiracle = wounded($wound['Commander'], $wound['WoundRate'], -1, -1, true);
2167 if ($wound['WoundRate'] <= 5) {
2168 $altmsg="You have been very lightly wounded during the battle in $RegName.";
2169 message($wound["Commander"],"Lightly Wounded",$altmsg,"Personal");
2170 } else if ($wound['WoundRate'] <= 10) {
2171 $altmsg="You have been wounded during the battle in $RegName.";
2172 message($wound["Commander"],"Wounded!",$altmsg,"Personal");
2173 } else {
2174 $altmsg="You have been very seriously wounded during the battle in $RegName!";
2175 message($wound["Commander"],"Serious Wound!",$altmsg,"Personal");
2176 if (!$ShowMiracle) {
2177 /* remove from posts */
2178 $altmsg=$name." has been seriously wounded during the battle in $RegName.";
2179 character_gone($wound["Commander"],$altmsg,$altmsg,'Absence');
2180 }
2181 }
2182 }
2183 }
2184
2185 $prisonQ = db_query("Select * from RunCombat where PrisonRealm is not NULL");
2186 while ($prison=db_fetch_array($prisonQ)) {
2187 $name=player_title($prison["Commander"],false,true);
2188 $PRName=db_fetch_single("select Name from Realms where ID=$prison[PrisonRealm]");
2189
2190 if ($prison['WoundRate'] > 10 && ( $prison['CommanderSubclass']=="Hero" || $prison['CommanderMainclass']=="NPC" ) || $prison['WoundRate'] >= 20 && db_fetch_single("Select Value from Globals where Var='Mortality'")) {
2191 $altmsg="During a battle in $RegName, the enemy noble $name was captured; ";
2192 $altmsg.="however, ".g("he",-1,$prison['Commander'])." died before ".g("he",-1,$prison['Commander'])." could be taken to prison, and was left for ".g("his",-1,$prison['Commander'])." realmmates to bury.";
2193 continue;
2194 }
2195 $altmsg=$name." has been captured by $PRName forces during the battle in $RegName.";
2196 character_gone($prison["Commander"],$altmsg,$altmsg,'Absence');
2197 $altmsg ="During a battle in $RegName, the enemy noble $name was captured and ";
2198 $altmsg.="is currently on his way into your dungeons.";
2199 message(db_get_array("select Player_ID from Government where Realm=$prison[PrisonRealm] and Position in ('Ruler','Judge')"),"New Prisoner",$altmsg);
2200 Prison($prison['Commander'],"",$prison['PrisonRealm'],"battle",$Here);
2201 $altmsg="You were captured by $PRName forces during the battle in $RegName.";
2202 /* if he was a rebel leader, the rebellion is over */
2203 $Loy = db_fetch_single("select Loyalty from Players where ID=$prison[Commander]");
2204 if ($Loy=="rebelleader") {
2205 $altmsg.=" That also means your rebellion has come to an end.";
2206 }
2207 message($prison["Commander"],"Captured!",$altmsg,"Personal");
2208 }
2209}
2210
2211function region_damage($StartAS, $StartDS, $Here, $RegName, $RegType, $Fortification, $FortDamage, $CFD, $FortBreached, $count) {
2212 global $debug;
2213 global $msg, $CombatSummary, $TotalDead;
2214
2215 /* effect on region */
2216 $TotalCS=$StartAS+$StartDS;
2217 if ($TotalCS>1000) {
2218 $PD=0;
2219 switch ($RegType) {
2220 case "Woodlands":
2221 case "Mountains": $Eff = round(sqrt($TotalCS*2)/8); break;
2222 case "Stronghold": $Eff = round(sqrt($TotalCS*2)/4); break;
2223 case "Townsland": $Eff = round(sqrt($TotalCS*2)/3); break;
2224 case "City": $Eff = round(sqrt($TotalCS*2)/6); break;
2225 case "Rural":
2226 default: $Eff = round(sqrt($TotalCS*2)/5); break;
2227 }
2228 if ($Fortification>0) {
2229 if ($FortBreached) $Eff=round($Eff*0.8);
2230 else $Eff=round($Eff*0.4);
2231 }
2232 $Eff+=$count;
2233 if ($StartAS>$StartDS*0.5&&$StartDS>$StartAS*0.5) {
2234 /* more damage if both are high */
2235 $PD = rand($Eff*0.4, $Eff*0.75);
2236 } else if ($StartAS>$StartDS*10||$StartDS>$StartAS*10) {
2237 /* less if outnumbered - not a big or long battle */
2238 $PD = rand($Eff*0.05, $Eff*0.2);
2239 } else if ($StartAS>$StartDS*5||$StartDS>$StartAS*5) {
2240 /* less if outnumbered - not a big or long battle */
2241 $PD = rand($Eff*0.15, $Eff*0.3);
2242 } else {
2243 $PD = rand($Eff*0.2, $Eff*0.5);
2244 }
2245 $PD-=5;
2246 if ($PD>0) {
2247 $CombatSummary.="The battle does ";
2248 if ($PD<10) {
2249 $CombatSummary.="minor";
2250 } else if ($PD<20) {
2251 $CombatSummary.="some";
2252 } else {
2253 $CombatSummary.="extensive";
2254 }
2255 $CombatSummary.=" damage to the local infrastructure. Production falls $PD %.<br>\n";
2256
2257 $RD = rand(0,round($PD/5));
2258 if ($RD>0) {
2259 $CombatSummary.="The local roads network has also been damaged.<br>\n";
2260 db_query("update Ways set Quality=GREATEST(20,Quality-$RD) where (Region_From=$Here or Region_To=$Here) and Quality>25");
2261 }
2262 } else $PD=0;
2263
2264 if ($TotalDead>0) {
2265 $UD=rand(0,min(50,round(sqrt($TotalDead))));
2266 } else $UD=0;
2267 db_query("update Regions set peace='no',Production=GREATEST(1,Production-$PD),UndeadRate=UndeadRate+$UD where ID=$Here");
2268 }
2269
2270 if ($CFD>0) {
2271 if ($debug>15) { echo "Total Fortification Damage: $CFD %<br>\n"; }
2272 /* apply and tell the region commander */
2273 $Commander=db_fetch_single("select Commander from Regions where ID=$Here");
2274 if ($FortDamage+$CFD>=100) {
2275 if ($Fortification==1) {
2276 db_query("update Regions set FortificationDamage=0, Fortification=0 where ID=$Here");
2277 $Cmsg = "Heavy fighting in $RegName has given the long-damaged fortifications the final blow and they collapsed. ";
2278 $Cmsg.= "Your region now has no fortifications left. You should build new ones, and keep them repaired this time.";
2279 $CombatSummary.="The battle has destroyed the fortifications.<br>\n";
2280 } else {
2281 /* partly destroyed! */
2282 db_query("update Regions set FortificationDamage=0, Fortification=Fortification-1 where ID=$Here");
2283 $NF=$Fortification-1;
2284 $Cmsg = "Fighting in $RegName has partly destroyed the fortifications, reducing them ";
2285 $Cmsg.= "to level $NF. You might want to rebuild them, and keep them in better repair this time.";
2286 $CombatSummary.="The battle has heavily damaged the fortifications, and reduced them to ".fortification_name($NF)."<br>\n";
2287 }
2288 } else {
2289 db_query("update Regions set FortificationDamage=FortificationDamage+$CFD where ID=$Here");
2290 $Cmsg = "During a battle in $RegName, the fortifications suffer $CFD % damage.";
2291 $CombatSummary.="The battle does $CFD % damage to the fortifications.<br>\n";
2292 }
2293 if ($Commander) message($Commander, "Fortification Damage", $Cmsg, "Report");
2294 }
2295}
2296
2297function is_present($char_id) {
2298 $sql = "select Status,WoundRate from Players where ID = $char_id";
2299 list($status,$wound) = db_fetch_single($sql);
2300 if ($wound < 5) {
2301 $here_array = array('ok', 'recovering', 'healing');
2302 $here = in_array($status, $here_array);
2303 } else {
2304 $here=false;
2305 }
2306 return $here;
2307}
2308
2309/* =================================================================
2310 Main Loop
2311 ================================================================= */
2312
2313/* set up rebels */
2314$res = db_query("select ID,Realm from Players where Loyalty in ('rebelleader','rebel')");
2315while ($row = db_fetch_array($res)) {
2316 db_query("update Troops set Realm=-Realm where Commander=$row[ID]");
2317}
2318
2319$ExtraBanners = ExtraID('Banners');
2320$ExtraSE = ExtraID('Siege Engines');
2321
2322$query = "select A.Location from Troops A, Troops B where A.Location=B.Location and ";
2323$query.= "A.Location>0 and A.ID>B.ID and A.Travel is NULL and B.Travel is NULL and ";
2324$query.= "A.Position in ('normal','fresh','dug in','hunting','ambush','evading') and ";
2325$query.= "B.Position in ('normal','fresh','dug in','hunting','ambush','evading') and ";
2326$query.= "(A.Realm!=B.Realm or (A.Realm=0 and B.Realm=0 and (A.Type in ('Monsters','Undead','Daimons') and B.Type not in ('Monsters','Undead','Daimons')) or (B.Type in ('Monsters','Undead','Daimons') and A.Type not in ('Monsters','Undead','Daimons')))) group by Location";
2327$res = db_query($query);
2328
2329/* resetting rebels */
2330db_query("update Troops set Realm=-Realm where Realm<0");
2331
2332while ($row = db_fetch_row($res)) {
2333 $Here=$row[0]; $Loot=0; $TotalDead=0;
2334 list($RegName, $RegRealm, $RegDuchy)=db_fetch_single("select Name,Realm,Duchy from Regions where ID=$Here");
2335 if ($debug>10) { echo "<p>Region: $RegName (#$Here)<br>\n"; }
2336
2337 /* Create temporary table to run this battle on
2338 (this makes sure we leave uninvolved units out) */
2339 db_query("DROP TABLE IF EXISTS RunCombat");
2340 $aquery ="CREATE TABLE RunCombat (";
2341 $aquery.="ID int(11) NOT NULL auto_increment,";
2342 $aquery.="Name char(32) default NULL,";
2343 $aquery.="Strength int(6) default NULL,";
2344 $aquery.="Wounded int(6) default NULL,";
2345 $aquery.="Type enum('Militia/Guards','Infantry','Archers','Mixed Infantry','Cavalry','Special Forces','Peasants','Hero','Monsters','Undead','Daimons') default NULL,";
2346 $aquery.="Training int(3) default NULL,";
2347 $aquery.="Weapons int(3) default NULL,";
2348 $aquery.="Armour int(3) default NULL,";
2349 $aquery.="WpnRange tinyint(2) NOT NULL default '0',";
2350 $aquery.="Morale tinyint(3) default NULL,";
2351 $aquery.="Cohesion tinyint(3) default NULL,";
2352 $aquery.="Damage tinyint(3) NOT NULL default '0',";
2353 $aquery.="Commander int(11) default NULL,";
2354 $aquery.="CombatStrength int(11) default NULL,";
2355 $aquery.="Realm smallint(5) NOT NULL default '0',";
2356 $aquery.="Army smallint(4) default NULL,";
2357 $aquery.="UnpaidDays tinyint(2) NOT NULL default '0',";
2358 $aquery.="Encounter enum('Murder','Attack','Normal','Defend','Evade') NOT NULL default 'Normal',";
2359 $aquery.="DeployLine tinyint(1) default NULL,";
2360 $aquery.="Tactic enum('line', 'box', 'wedge', 'skirmish') NOT NULL default 'line',";
2361 $aquery.="Withdraw tinyint(3) default 60,";
2362 $aquery.="Position enum('normal','fresh','dug in','hunting','evading','ambush','retreated','scattered','rallying') NOT NULL default 'normal',";
2363 $aquery.="Designation enum('army', 'sentries', 'vanguard', 'police', 'mercenary') NOT NULL default 'army',";
2364 $aquery.="CommanderMainclass enum('Warrior', 'Courtier', 'Priest', 'Adventurer', 'NPC') NOT NULL default 'Warrior',";
2365 $aquery.="CommanderSubclass enum('Mentor', 'Student', 'Diplomat', 'Ambassador', 'Trader', 'Infiltrator', 'Cavalier', 'Hero') default NULL,";
2366 $aquery.="CommanderPresent enum('yes','no') NOT NULL default 'yes',";
2367 $aquery.="CaptainSkill tinyint(3) default 0,";
2368 $aquery.="PRIMARY KEY (ID))";
2369 db_query($aquery);
2370
2371 // For those troops with a valid commander
2372 $aquery ="INSERT INTO RunCombat SELECT T.ID,T.Name,T.Strength,T.Wounded,T.Type,T.Training,T.Weapons,T.Armour,";
2373 $aquery.="T.WpnRange,T.Morale,T.Cohesion,T.Damage,T.Commander,T.CombatStrength,T.Realm,P.Army,T.UnpaidDays,T.Encounter,T.DeployLine,T.Tactic,T.Withdraw,";
2374 $aquery.="T.Position,T.Designation,P.Mainclass,P.Subclass,'yes',T.CaptainSkill FROM Troops T LEFT JOIN Players P ON T.Commander=P.ID WHERE T.Commander is not NULL and T.Location=$Here and T.Travel is NULL and T.Position in ('normal','fresh','dug in','hunting','ambush')";
2375 db_query($aquery);
2376
2377 // For those troops without a valid commander
2378 $aquery ="INSERT INTO RunCombat SELECT T.ID,T.Name,T.Strength,T.Wounded,T.Type,T.Training,T.Weapons,T.Armour,";
2379 $aquery.="T.WpnRange,T.Morale,T.Cohesion,T.Damage,T.Commander,T.CombatStrength,T.Realm,P.Army,T.UnpaidDays,T.Encounter,T.DeployLine,T.Tactic,T.Withdraw,";
2380 $aquery.="T.Position,T.Designation,'Warrior',P.Subclass,'yes',T.CaptainSkill FROM Troops T LEFT JOIN Players P ON T.Commander=P.ID WHERE T.Commander is NULL and T.Location=$Here and T.Travel is NULL and T.Position in ('normal','fresh','dug in','hunting','ambush')";
2381 db_query($aquery);
2382
2383 /* check if commander is with his unit */
2384 $ares = db_query("select R.ID,P.ID,P.Location,P.Status,P.WoundRate from RunCombat R, Players P where R.Commander=P.ID");
2385 while ($arow=db_fetch_row($ares)) {
2386 if ($arow[2]!=$Here) db_query("update RunCombat set CommanderPresent='no' where ID=$arow[0]");
2387 else if ($arow[3]!='ok'&&$arow[3]!='recovering'&&$arow[3]!='healing'||$arow[4]>5) db_query("update RunCombat set CommanderPresent='no' where ID=$arow[0]");
2388 }
2389
2390 $count = db_fetch_single("select count(*) from RunCombat");
2391 if ($debug>15) echo "$count combat worthy units in this region<br>\n";
2392 if ($count==0) continue;
2393 $RealmList=db_get_list("select Realm from RunCombat where Realm>0 group by Realm");
2394
2395 /* --- Determine Combat Roles --- */
2396
2397 /* preparations */
2398 $msg=""; $Unimsg="";
2399 $aquery = "ALTER TABLE RunCombat ADD FullStrength int(6) NOT NULL default 0, ";
2400 $aquery.= "ADD FullWounded int(6) NOT NULL default 0, ";
2401 $aquery.= "ADD CombatRole enum('attacker','defender','neutral') default NULL,";
2402 $aquery.= "ADD CombatNr smallint(3) default NULL, ";
2403 $aquery.= "ADD CombatLine tinyint(2) default NULL, ";
2404 $aquery.= "ADD CloseWith int(11) default NULL, ";
2405 $aquery.= "ADD CloseHits int(11) default 0, ";
2406 $aquery.= "ADD RangedTarget int(11) default NULL, ";
2407 $aquery.= "ADD RangedHits int(11) default 0, ";
2408 $aquery.= "ADD HitsCaused int(11) default 0, ";
2409 $aquery.= "ADD CombatWait tinyint(1) default NULL, ";
2410 $aquery.= "ADD UnitTraining int(4) not null default 0, ";
2411 $aquery.= "ADD ChangeDamage int(3) not null default 0, ";
2412 $aquery.= "ADD ChangeMorale int(3) not null default 0, ";
2413 $aquery.= "ADD Banners int(3) not null default 0, ";
2414 $aquery.= "ADD SiegeEngines int(3) not null default 0, ";
2415 $aquery.= "ADD CommanderXP int(3) not null default 0, ";
2416 $aquery.= "ADD CommanderHonour int(3) not null default 1, ";
2417 $aquery.= "ADD CommanderPrestige int(3) not null default 0, ";
2418 $aquery.= "ADD CommanderSkill int(3) not null default 0, ";
2419 $aquery.= "ADD CommanderScore int(3) not null default 0, ";
2420 $aquery.= "ADD WoundRate int(3) not null default 0, ";
2421 $aquery.= "ADD PrisonRealm smallint(5) default NULL, ";
2422 $aquery.= "ADD Organisation int(3) not null default 0, ";
2423 $aquery.= "ADD MarshalFormation varchar(32) default NULL,";
2424 $aquery.= "ADD Overkill int(3) not null default 0, ";
2425 $aquery.= "ADD CloseCount int(3) not null default 0, ";
2426 $aquery.= "ADD Serial int(11) not null default 0";
2427 /* $aquery.= ", ADD Action enum('forward','back','stay','fight','shoot','charge') not null default 'stay'";*/
2428 db_query($aquery);
2429
2430 $bonusQ = db_query( "Select E.*, RC.Type from DelayedEvents E join RunCombat RC on E.Unit_ID=RC.ID where E.EventType in ('MagicWeapons','MagicArmour','MagicSteeds')" );
2431 while ( $bonus = db_fetch_array($bonusQ) ) {
2432
2433 if ( $bonus['EventType'] == 'MagicWeapons' ) {
2434 db_query( "Update RunCombat set Weapons=Weapons+$bonus[Value] where ID=$bonus[Unit_ID]" );
2435 } else if ( $bonus['EventType'] == 'MagicArmour' ) {
2436 db_query( "Update RunCombat set Armour=Armour+$bonus[Value] where ID=$bonus[Unit_ID]" );
2437 } else if ( $bonus['EventType'] == 'MagicSteeds' ) {
2438 if ( $bonus['Type'] == 'Infantry' ) {
2439 db_query( "Update RunCombat set Type='Cavalry' where ID=$bonus[Unit_ID]" );
2440 }
2441 }
2442
2443 db_query( "Delete from DelayedEvents where ID=$bonus[ID]" );
2444 }
2445
2446 combatstrength(-1,"RunCombat");
2447
2448 db_query("update RunCombat set CombatRole=NULL, CombatLine=NULL, CloseHits=0, RangedHits=0, FullStrength=Strength, FullWounded=Wounded, Organisation=Training/5");
2449 db_query("update RunCombat set CombatWait=0 where Encounter in ('Murder','Attack')");
2450 db_query("update RunCombat set CombatWait=1 where Encounter='Normal'");
2451 db_query("update RunCombat set CombatWait=3 where Encounter='Defend'");
2452 db_query("update RunCombat set CombatWait=4 where Encounter='Evade'");
2453 $ares = db_query("select Realm, Fortification, FortificationDamage, Type from Regions where ID=$Here");
2454 $arow = db_fetch_array($ares);
2455 $Owner = $arow['Realm'];
2456 $Fortification = $arow['Fortification'];
2457 $FortDamage = $arow['FortificationDamage'];
2458 $RegType = $arow['Type'];
2459 $TORealm = db_fetch_single("select Realm_ID from Takeovers where Region_ID=$Here");
2460 if (!$TORealm) $TORealm=-1;
2461 $DefFort=false;
2462 $FortBreached=false;
2463 if ($debug>15) { echo "Owner: $Owner, Fortification: $Fortification ($FortDamage % damage)<br>\n"; }
2464
2465 $Hunters=db_fetch_single("select sum(CombatStrength) from Troops where Realm=$Owner and Location=$Here and Position='hunting'");
2466 $Evading=false;
2467
2468 $msg.=battle_setupsides($Owner,$TORealm);
2469
2470 /* morale penalty for police */
2471 db_query("update RunCombat set Morale=Morale/2, ChangeMorale=-(Morale/2) where Designation='police'");
2472
2473 /* honour and prestige bonus for defending the homeland */
2474 $Capital = db_fetch_single("select Capital from Realms where ID=$Owner");
2475 if ($Capital==$Here) {
2476 /* high bonus for defending the Capital */
2477 $HomeBonus=10;
2478 } else {
2479 $HomeBonus=5;
2480 }
2481 db_query("update RunCombat set CommanderHonour=CommanderHonour+$HomeBonus, CommanderPrestige=CommanderPrestige+$HomeBonus where Realm=$Owner");
2482
2483 /* roles have been set, let's go */
2484 $CountAttackers = db_fetch_single("select count(ID) from RunCombat where CombatRole='attacker'");
2485 $CountDefenders = db_fetch_single("select count(ID) from RunCombat where CombatRole='defender'");
2486 $CountNeutrals = db_fetch_single("select count(ID) from RunCombat where CombatRole='neutral'");
2487 if ($debug>15) { echo "Attackers: $CountAttackers<br>Defenders: $CountDefenders<br>Neutral: $CountNeutrals<br>\n"; }
2488
2489 $RebelCombat=false;
2490 if ($CountAttackers==0||$CountDefenders==0) {
2491 /* no regular combat - check for rebels */
2492 $subres = db_query("select Realm from Players where active='yes' and Loyalty in ('rebel','rebelleader') and Location=$Here group by Realm");
2493 while ($subrow=db_fetch_row($subres)) {
2494 $Loyals = db_fetch_single("select ID from Players where active='yes' and Loyalty not in ('rebel','rebelleader') and Location=$Here and Realm=$subrow[0]");
2495 if ($Loyals) {
2496 /* yes, there is an encounter between loyal and rebel troops here! */
2497 $msg=battle_setuprebelcombat($subrow[0]);
2498 $CountAttackers = db_fetch_single("select count(ID) from RunCombat where CombatRole='attacker'");
2499 $CountDefenders = db_fetch_single("select count(ID) from RunCombat where CombatRole='defender'");
2500 $CountNeutrals = db_fetch_single("select count(ID) from RunCombat where CombatRole='neutral'");
2501 if ($debug>15) { echo "After rebellion:<br>\nAttackers: $CountAttackers<br>Defenders: $CountDefenders<br>Neutral: $CountNeutral<br>\n"; }
2502 $RebelCombat=true;
2503 }
2504 }
2505 }
2506
2507 if ($CountAttackers==0||$CountDefenders==0) {
2508 if ($debug>15) echo "No battle:<br>$msg<br>\n";
2509 if ($Evading) {
2510 $emsg = "Battle preparations were made in $RegName, but no battle took place ";
2511 $emsg.= "because the following units successfully evaded combat:<br><ul>";
2512 $eres = db_query("select * from RunCombat where Position='evading'");
2513 while ($erow = db_fetch_array($eres)) {
2514 $emsg.="<li>".stripslashes($erow["Name"]);
2515 }
2516 $emsg.= "</ul>";
2517 message(db_get_array("select Commander from RunCombat"), "No Battle in $RegName", $emsg);
2518 }
2519 continue;
2520 }
2521
2522 /* leadership */
2523 $ares = db_query("select * from RunCombat where Commander is not NULL");
2524 while ($arow=db_fetch_array($ares)) {
2525 $LSkill = skill_get($arow['Commander'], "Leadership") + $arow['CaptainSkill'];
2526 db_query("update RunCombat set CommanderSkill=$LSkill where ID=$arow[ID]");
2527 }
2528
2529 /* banners */
2530 $Defenders=db_get_list("select ID from RunCombat where CombatRole='defender'");
2531 $Attackers=db_get_list("select ID from RunCombat where CombatRole='attacker'");
2532 $ares = db_query("select ID, Number from PlayerExtras P, Troops T where T.ID in ($Defenders,$Attackers) and T.Commander=P.Player_ID and P.Extra_ID=$ExtraBanners");
2533 while ($arow = db_fetch_row($ares)) {
2534 db_query("update RunCombat set Banners=$arow[1] where ID=$arow[0]");
2535 }
2536 $ares = db_query("select ID, Number from PlayerExtras P, Troops T where T.ID in ($Defenders,$Attackers) and T.Commander=P.Player_ID and P.Extra_ID=$ExtraSE");
2537 while ($arow = db_fetch_row($ares)) {
2538 db_query("update RunCombat set SiegeEngines=$arow[1] where ID=$arow[0]");
2539 }
2540
2541 $OnlyPeasants=false;
2542 $Test = db_fetch_single("select count(ID) from RunCombat where CombatRole='attacker' and Type!='Peasants'");
2543 if ($debug>20) { echo "OnlyPeasants test for Attackers: $Test<br>\n"; }
2544 if ($Test==0) { $OnlyPeasants=true; }
2545 $Test = db_fetch_single("select count(ID) from RunCombat where CombatRole='defender' and Type!='Peasants'");
2546 if ($debug>20) { echo "OnlyPeasants test for Defenders: $Test<br>\n"; }
2547 if ($Test==0) { $OnlyPeasants=true; }
2548
2549 /* find out if we can use the fortifications */
2550 if ($Fortification>0&&!$RebelCombat) {
2551 $WeAreHome = db_fetch_single("select ID from RunCombat where CombatRole='defender' and Realm=$Owner");
2552 if ($WeAreHome) $DefFort=true;
2553 }
2554
2555 /* random effect on archers */
2556 $Weather=rand(0,25)+rand(0,25)+rand(0,50);
2557 if ($debug>20) { echo "Weather: $Weather<br>\n"; }
2558 if ($Weather<20) {
2559 $msg.="<br>There is almost no wind today, archers will be deadly.<br>";
2560 } else if ($Weather<45) {
2561 $msg.="<br>A calm wind blows, to the joy of the archers.<br>";
2562 } else if ($Weather<60) {
2563 $msg.="<br>It is quite windy and the archers will have to aim very carefully.<br>";
2564 } else if ($Weather<85) {
2565 $msg.="<br>Strong winds and gusts are making ranged combat a game of luck.<br>";
2566 } else {
2567 $msg.="<br>The battle takes place in the middle of a storm, archers will be almost worthless.<br>";
2568 }
2569
2570 if ($DefFort) {
2571 $msg.="<span style=\"color: #E0FFFF;\">The defenders take up positions inside the ".fortification_name($Fortification).".</span><br>";
2572 db_query("update RunCombat set CombatWait=CombatWait+$Fortification/2, Position='dug in' where CombatRole='defender' and Encounter='Attack'");
2573 db_query("update RunCombat set CombatWait=CombatWait+$Fortification, Position='dug in' where CombatRole='defender' and Encounter not in ('Attack','Murder')");
2574 db_query("update RunCombat set CombatWait=CombatWait+2 where CombatRole='defender' and Encounter in ('Evade','Defend')");
2575 db_query("update RunCombat set CombatStrength=CombatStrength*1.1 where CombatRole='defender' and Designation='sentries'");
2576 } else {
2577 if ($RebelCombat) {
2578 $msg.="As this is a civil war, neither side can make proper use of the fortifications.<br>";
2579 $Fortification=0;
2580 } else if ($Fortification>0) {
2581 $msg.="Even though there is a fortification nearby, neither attackers nor defenders are ";
2582 $msg.="able to make use of it, so the battlefield is in the open.<br>";
2583 $Fortification=0;
2584 }
2585 }
2586
2587 /* unique items - only show the top 5 */
2588 $Items['attacker']=0; $Items['defender']=0;
2589 $Coms = db_get_list("select Commander from RunCombat where CombatRole in ('attacker','defender') and Commander is not NULL");
2590 if ($Coms&&$Coms!="") {
2591 $icount=0;
2592 $ares = db_query("select P.ID, I.Name, I.Type, I.ID as ItemID, I.Prestige from PlayerItems I, Players P where I.Owner_ID in ($Coms) and I.Owner_ID=P.ID and P.Location=$Here order by I.Prestige DESC");
2593 if (db_num_rows($ares)>0) $msg.="<br>";
2594 while ($arow=db_fetch_array($ares)) {
2595 db_query("update PlayerItems set CurrentCond=CurrentCond-1 where ID=$arow[ItemID]");
2596 $Side = db_fetch_single("select CombatRole from RunCombat where Commander=$arow[ID]");
2597 $icount++; $Items[$Side]++;
2598 if ($icount>5) continue;
2599 switch ($arow['Type']) {
2600 case 'Weapon':
2601 case 'Shield': $a="wielding"; break;
2602 case 'Armour':
2603 case 'Ring':
2604 case 'Accessory': $a="wearing"; break;
2605 case 'Scroll':
2606 case 'Book': $a="reading from"; break;
2607 default: $a="carrying";
2608 }
2609 $UniqueHolder = \DoctrineWorldEM()->getRepository('BattleMaster\Character')->find($arow['ID']);
2610 $unique = $UniqueHolder->ShortTitle()." is spotted $a the ".stripslashes($arow['Name']).".<br>";
2611 $msg.=$unique;
2612 if ($arow['Prestige']>2) $Unimsg.=$unique;
2613 item_prestige($arow['ItemID'],2);
2614 }
2615 }
2616
2617 $DSide='';
2618 $ADaimons=db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='attacker' and Type='Daimons'");
2619 if ($ADaimons>0) {
2620 $DSide='defender'; $Daimons=$ADaimons;
2621 } else {
2622 $DDaimons=db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole='defender' and Type='Daimons'");
2623 if ($DDaimons>0) {
2624 $DSide='attacker';$Daimons=$DDaimons;
2625 }
2626 }
2627 if ($DSide!='') {
2628 if ($Items[$DSide]==0) {
2629 $msg.="Facing the Daimons without any unique items, the ${DSide}s suffer a morale penalty.<br>";
2630 db_query("update RunCombat set Morale=GREATEST(1,Morale-25) where CombatRole='$DSide' and Type!='Daimons' and Type!='Monsters' and Type!='Undead'");
2631 } else if ($Items[$DSide]==1&&$Daimons>5000) {
2632 $msg.="Facing so many Daimons with just one unique item, the ${DSide}s suffer a small morale penalty.<br>";
2633 db_query("update RunCombat set Morale=GREATEST(1,Morale-15) where CombatRole='$DSide' and Type!='Daimons' and Type!='Monsters' and Type!='Undead'");
2634 } else if ($Items[$DSide]==2&&$Daimons>12000) {
2635 $msg.="Facing so many Daimons with so few unique items, the ${DSide}s suffer a small morale penalty.<br>";
2636 db_query("update RunCombat set Morale=GREATEST(1,Morale-15) where CombatRole='$DSide' and Type!='Daimons' and Type!='Monsters' and Type!='Undead'");
2637 } else $msg.="Thanks to the unique item(s), the ${DSide} fight with full morale.<br>";
2638 }
2639
2640 /* attackers don't gain anything from digging in */
2641 db_query("update RunCombat set Position='normal' where CombatRole='attacker'");
2642
2643 /* --- Determine Combat Lines --- */
2644
2645 db_query("update RunCombat set CombatLine=1");
2646 db_query("update RunCombat set CombatLine=CombatLine+2 where Type='Cavalry' and WpnRange=0");
2647 db_query("update RunCombat set CombatLine=CombatLine+1 where WpnRange>1");
2648 db_query("update RunCombat set CombatLine=CombatLine+1 where WpnRange>3");
2649 db_query("update RunCombat set CombatLine=CombatLine+1 where Encounter='Defend'");
2650 db_query("update RunCombat set CombatLine=CombatLine+1 where Encounter='Evade'");
2651 db_query("update RunCombat set CombatLine=CombatLine-1 where Encounter='Murder'");
2652 db_query("update RunCombat set CombatLine=CombatLine-1 where Encounter='Attack' and WpnRange<2");
2653 db_query("update RunCombat set CombatLine=GREATEST(1,LEAST(5,CombatLine))");
2654
2655 /* use deployline setting */
2656 db_query("update RunCombat set CombatLine=DeployLine where DeployLine is not NULL");
2657
2658
2659 $TotalSize = db_fetch_single("select sum(CombatStrength) from RunCombat where CombatRole in ('attacker','defender')");
2660 /* new code: every marshal commands only men from his army */
2661 $lres = db_query("select count(*) as nr, sum(CombatStrength) as CS, Army from RunCombat where Army is not NULL group by Army order by CombatRole");
2662 while ($lrow = db_fetch_array($lres)) {
2663 if ($lrow['nr']>2) {
2664 list($ArmyName, $Marshal, $Second, $Offensive, $Defensive) = db_fetch_single("select Name, Marshal, Second, Offensive, Defensive from Armies where ID=$lrow[Army]");
2665
2666 $MCR =0;$SCR=0;
2667 if ($Marshal && is_present($Marshal)) {
2668 //check if Marshal actually present
2669 $MCR = db_fetch_single("select CombatRole from RunCombat where Commander=$Marshal and CombatRole in ('attacker', 'defender')");
2670 }
2671 if ($Second && is_present($Second)) {
2672 $SCR = db_fetch_single("select CombatRole from RunCombat where Commander=$Second and CombatRole in ('attacker', 'defender')");
2673 }
2674 if ($MCR||$SCR) {
2675 /* marshal or second is present, let's take command */
2676 if (!$MCR) { $Marshal=$Second; $MCR=$SCR; } // second takes over
2677 /* Fame for the marshal in large battles */
2678 $MySize = db_query("select sum(CombatStrength) from RunCombat where CombatRole='$MCR' and Army=$lrow[Army]");
2679 if ($TotalSize>7500&&$MySize>2000) {
2680 $Fam = db_fetch_single("select Player from Players where ID=$Marshal");
2681 famecheck($Fam,'Large Command');
2682 }
2683 /* Announcement and formation */
2684 if ($MCR=='attacker') $msg.=marshal_setup($MCR, $lrow['Army'], $ArmyName, $Marshal, $Offensive);
2685 else $msg.=marshal_setup($MCR, $lrow['Army'], $ArmyName, $Marshal, $Defensive);
2686 }
2687 }
2688 }
2689
2690 /* split up forces (attackers left, defenders right) */
2691 db_query("update RunCombat set CombatLine=-CombatLine where CombatRole='attacker'");
2692
2693 /* remove neutral observers */
2694 db_query("update RunCombat set CombatLine=NULL where CombatRole='neutral'");
2695
2696 /* fame for large units */
2697 $ares = db_query("select * from RunCombat where Commander is not NULL and (Strength>=100 or (Type in ('Cavalry','Special Forces') && Strength>=50))");
2698 while ($arow=db_fetch_array($ares)) {
2699 $Fam = db_fetch_single("select Player from Players where ID=$arow[Commander]");
2700 famecheck($Fam,'Large Unit');
2701 }
2702 /* fame for elite units */
2703 $ares = db_query("select * from RunCombat where Commander is not NULL and Training>=80 and Cohesion>=60 and (Weapons>60 or Armour>60) and Strength>=20");
2704 while ($arow=db_fetch_array($ares)) {
2705 $Fam = db_fetch_single("select Player from Players where ID=$arow[Commander]");
2706 famecheck($Fam,'Elite Unit');
2707 }
2708
2709 // Glory for all the realms involved
2710 $ares = db_query("select Realm, sum(CombatStrength) as CS, sum(Strength) as Men from RunCombat where CombatRole in ('attacker', 'defender') group by Realm");
2711 while ($arow=db_fetch_array($ares)) {
2712 $Glory = round($arow['Men']/2 + $arow['CS']/12);
2713 if($arow["Realm"] == 43) {
2714 $Glory /= 2;
2715 DebugLog( "debug", "Combat Glory Gain: Daimons gain $Glory glory points (due to having $arow[Men] men with $arow[CS] CS in battle) and now have a total of " . db_fetch_single("select Glory from Realms where ID=43") );
2716
2717 }
2718 db_query("update Realms set Glory=Glory+$Glory where ID=$arow[Realm]");
2719 }
2720
2721 // organisation
2722 /* disabled again for the moment
2723 db_query("update RunCombat set Organisation=Organisation+CommanderSkill/5 where Organisation<50"); // for all without marshals, personal skill can compensate a little
2724 $msg.="<br />";
2725 $ASize = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='attacker'");
2726 $AOrg = db_fetch_single("select avg(Organisation) from RunCombat where CombatRole='attacker'");
2727 $sub=round(sqrt($ASize)/5 + (100-$AOrg)/10);
2728 echo "error/debug: Attackers: $ASize, avg Org = $AOrg, sub = $sub<br>\n";
2729 if ($sub>10) $msg.="The attackers are very disorganised and confusion reduces their efficiency.<br />";
2730 else if ($sub>7) $msg.="The attackers are not well organised and some confusion hinders their efficiency.<br />";
2731 else if ($sub<3) $msg.="The attackers are very well organised and fight very efficiently.<br />";
2732 else if ($sub<5) $msg.="The attackers are well organised and fight efficiently.<br />";
2733 if ($sub>4) {
2734 // bad organisation leads to confusion, confusion leads to not being where you should be
2735 $A = db_query("select count(*) from RunCombat where CombatRole='attacker'");
2736 $dis = ceil($A*$sub/20);
2737 $ares = db_query("select * from RunCombat where CombatRole='attacker' order by RAND() limit 0,$dis");
2738 while ($arow=db_fetch_array($ares)) {
2739 $move=rand(-1,1);
2740 if ($move==0) db_query("update RunCombat set CombatWait=CombatWait+2 where ID=$arow[ID]");
2741 else db_query("update RunCombat set CombatLine=CombatLine+$move where ID=$arow[ID]");
2742 }
2743 db_query("update RunCombat set Morale=GREATEST(1,Morale-$sub) where CombatRole='attacker'");
2744 }
2745
2746 $DSize = db_fetch_single("select sum(Strength) from RunCombat where CombatRole='defender'");
2747 $DOrg = db_fetch_single("select avg(Organisation) from RunCombat where CombatRole='defender'");
2748 $sub=round(sqrt($DSize)/7 + (100-$DOrg)/10); // can handle more men better as defender
2749 echo "error/debug: Defenders: $DSize, avg Org = $DOrg, sub = $sub<br>\n";
2750 if ($sub>10) $msg.="The defenders are very disorganised and confusion reduces their efficiency.<br />";
2751 else if ($sub>7) $msg.="The defenders are not well organised and some confusion hinders their efficiency.<br />";
2752 else if ($sub<3) $msg.="The defenders are very well organised and fight very efficiently.<br />";
2753 else if ($sub<5) $msg.="The defenders are well organised and fight efficiently.<br />";
2754 if ($sub>4) {
2755 // bad organisation leads to confusion, confusion leads to not being where you should be
2756 $D = db_query("select count(*) from RunCombat where CombatRole='defender'");
2757 $dis = ceil($D*$sub/20);
2758 $ares = db_query("select * from RunCombat where CombatRole='defender' order by RAND() limit 0,$dis");
2759 while ($arow=db_fetch_array($ares)) {
2760 $move=rand(-1,1);
2761 if ($move==0) db_query("update RunCombat set CombatWait=CombatWait+2 where ID=$arow[ID]");
2762 else db_query("update RunCombat set CombatLine=CombatLine+$move where ID=$arow[ID]");
2763 }
2764 db_query("update RunCombat set Morale=GREATEST(1,Morale-$sub) where CombatRole='defender'");
2765 }
2766 */
2767
2768
2769 /* --- Determine Combat Strength and write start report --- */
2770
2771 $summary = "<table bgcolor=#000032><tr><th>No.</th><th>Role</th><th>Army</th><th>Unit</th><th>Commander</th><th>Realm</th><th>Unit</th><th>Formation</th><th>CS</th></tr>\n";
2772 $ares = db_query("select * from RunCombat order by CombatRole, Name ASC");
2773 $count=0;
2774 $types=array("Inf","MI","Arch","Cav","SF","other");
2775 foreach($types as $curtype) {
2776 ${"A-$curtype"}=0;
2777 ${"D-$curtype"}=0;
2778 ${"N-$curtype"}=0;
2779 }
2780 while ($arow=db_fetch_array($ares)) {
2781 $count++;
2782 db_query("update RunCombat set CombatNr=$count where ID=$arow[ID]");
2783 if ($arow["Commander"]) {
2784 if ($arow["CommanderPresent"]=="yes")
2785 $Com=db_fetch_single("select CharacterName from Players where ID=$arow[Commander]");
2786 else $Com="<i>(not present)</i>";
2787 } else if ($arow["Type"]=="Monsters"||$arow["Type"]=="Undead"||$arow["Type"]=="Daimons") $Com="<i>($arow[Type])</i>";
2788 else $Com="<i>(militia/guard unit)</i>";
2789 $Realm=db_fetch_single("select Name from Realms where ID=$arow[Realm]");
2790 switch ($arow["Type"]) {
2791 case "Infantry": $Type="Inf"; break;
2792 case "Mixed Infantry": $Type="MI"; break;
2793 case "Archers": $Type="Arch"; break;
2794 case "Cavalry": $Type="Cav"; break;
2795 case "Special Forces": $Type="SF"; break;
2796 default: $Type="other";
2797 }
2798 $R=strtoupper(substr($arow["CombatRole"],0,1));
2799 ${"$R-$Type"}+=$arow["Strength"];
2800 $summary .= "<tr><td style=\"text-align: center;\">$count</td><td style=\"text-align: center;\">$R</td><td>".$armyBanners[$arow['Army']]."</td><td>".stripslashes($arow["Name"])."</td><td>$Com</td><td style=\"text-align: center;\">$Realm</td>";
2801 $summary .= "<td style=\"text-align: center;\">$arow[Strength] $Type</td><td style=\"text-align: center;\">$arow[Tactic]</td><td style=\"text-align: right;\"> $arow[CombatStrength]</td></tr>\n";//<td align=right>$arow[Organisation] % Removed for now because it does nothing
2802 }
2803 $summary .= "</table><br>\nTotal:<br>";
2804
2805 /* If there are monsters, undead, or Daimons in the battle, whoever's fighting against them may get a bonus. */
2806 $evilSide = db_fetch_single( "Select distinct CombatRole from RunCombat where Type in ( 'Monsters', 'Undead', 'Daimons' )" );
2807 if (!$evilSide) {
2808 /* If there are no inhuman beasties, realm loyalty may drop for every attacker */
2809 $ares = db_query("select Realm from RunCombat where CombatRole='attacker' and Realm!=$Owner group by Realm");
2810 while ($arow=db_fetch_row($ares)) {
2811 $lossChance=loyality($arow[0],$Here);
2812 $Roll=rand(0,100);
2813 $loss=0;
2814 if ($Roll<$lossChance) { $loss++; }
2815 if ($Roll<$lossChance/2) { $loss++; }
2816 if ($Roll<$lossChance/10) { $loss++; }
2817 if ($loss>=$lossChance) { $loss=$lossChance-1; }
2818 if ($loss>0) {
2819 $NewMax=max(1,$lossChance-$loss);
2820 if ($debug>20) echo "Loyalty drop: $loss pts. to $NewMax for Realm $arow[0]<br>\n";
2821 db_query("replace Morale set MaxMorale=$NewMax, Region_ID=$Here, Realm_ID=$arow[0]");
2822 }
2823 }
2824 }
2825
2826 $DefNames=db_get_list("select Realms.Name from RunCombat, Realms where RunCombat.CombatRole='defender' and RunCombat.Realm=Realms.ID group by Realms.Name");
2827 $AttNames=db_get_list("select Realms.Name from RunCombat, Realms where RunCombat.CombatRole='attacker' and RunCombat.Realm=Realms.ID group by Realms.Name");
2828 if ($RebelCombat) {
2829 $AttNames.=" rebels"; $DefNames.=" loyalists";
2830 }
2831 $historyAttackers = stripslashes($AttNames);
2832 $historyDefenders = stripslashes($DefNames);
2833 $ShortSummary=stripslashes($AttNames)." vs. ".stripslashes($DefNames)."<br>\n";
2834 $ares = db_query("select count(*), sum(CombatStrength), avg(Morale), sum(Strength) from RunCombat where CombatRole='attacker'");
2835 $arow=db_fetch_row($ares);
2836 $AC=$arow[0]; $StartAS=$arow[1]; $StartAM=$arow[2];
2837 $EstimateAS = round( max(1,(rand(75,125)*$arow[3])/1000))*10;
2838 $ares = db_query("select count(*), sum(CombatStrength), avg(Morale), sum(Strength) from RunCombat where CombatRole='defender'");
2839 $arow=db_fetch_row($ares);
2840 $DC=$arow[0]; $StartDS=$arow[1];
2841 $EstimateDS = round( max(1,(rand(75,125)*$arow[3])/1000))*10;
2842
2843 if ($StartAS*(15+($StartAM/10))<$StartDS) {
2844 /* suicide attack - except for rogues (includes monsters and undead!) */
2845 $ARL=db_get_list("select Realm from RunCombat where CombatRole='attacker' and Realm>0");
2846 if ($ARL!="") {
2847 suicide_attack($AttNames, $RealmList, $Here, $RegName, $Owner, $StartDS);
2848 continue;
2849 }
2850 }
2851
2852 $ArmyListing="";
2853
2854 $armyq = db_query( "Select A.ID as ArmyID, A.Name as ArmyName, R.Name as RealmName, A.Sponsor, A.Marshal, A.Second, Count(P.ID) as Nobles, Sum(RC.Strength) as Troops from RunCombat RC join Players P on P.ID=RC.Commander join Armies A on P.Army=A.ID join Realms R on A.Realm=R.ID group by P.Army order by A.Realm" );
2855 while ($army=db_fetch_array($armyq)) {
2856 if ($army['Nobles'] < 5 || $army['Troops'] < 50) {
2857 continue;
2858 }
2859 $MarshalPresent = false;
2860 $SecondPresent = false;
2861 if ($army['Marshal']) {
2862 $MarshalPresent = db_fetch_single( "Select Count(ID) from RunCombat where Commander=$army[Marshal] and CombatRole in ('attacker', 'defender')" );
2863 if ($army['Marshal'] == $army['Sponsor']) {
2864 $SponsorLeads==true;
2865 }
2866 }
2867 if (!$MarshalPresent) {
2868 if ($army['Second']) {
2869 $SecondPresent = db_fetch_single( "Select Count(ID) from RunCombat where Commander=$army[Second] and CombatRole in ('attacker', 'defender')" );
2870 if ( $army['Second'] == $army['Sponsor'] ) {
2871 $SponsorLeads==true;
2872 }
2873 }
2874 }
2875 if (!$MarshalPresent && !$SecondPresent) {
2876 continue;
2877 } else if ($MarshalPresent) {
2878 if ($SponsorLeads) {
2879 $Leader = "Marshal";
2880 } else {
2881 $Leader = "Marshal ".getCharName( $army['Marshal'], true );
2882 }
2883 } else {
2884 if ($SponsorLeads) {
2885 $Leader = "Vice-Marshal";
2886 } else {
2887 $Leader = "Vice-Marshal ".getCharName( $army['Second'], true );
2888 }
2889 }
2890 $Sponsor = \DoctrineWorldEM()->getRepository('BattleMaster\Character')->find($army['Sponsor']);
2891 if (!$SponsorLeads) {
2892 $armyline = "The $army[ArmyName] (<span style=\"color: #D0D0D0;\">$army[RealmName]</span>), sponsored by ".$Sponsor->ShortTitle().", were led into battle by $Leader.";// ($army[Nobles] nobles, $army[Troops] troops)";
2893 } else {
2894 $armyline = "The $army[ArmyName] (<span style=\"color: #D0D0D0;\">$army[RealmName]</span>) are sponsored by ".$Sponsor->ShortTitle().", who also led the army into battle as its $Leader.";
2895 }
2896 $ArmyListing.=$armyline."<br/>\n";
2897 }
2898
2899 $ares = db_query("select count(*), sum(CombatStrength) from RunCombat where CombatRole='neutral'");
2900 $arow=db_fetch_row($ares);
2901 $NC=$arow[0]; $NS=$arow[1];
2902 $ShortSummary.="Estimated strengths: $EstimateAS men vs. $EstimateDS men<br>\n";
2903 $historyAttackers = $historyAttackers.' ('.$EstimateAS.' men)';
2904 $historyDefenders = $historyDefenders.' ('.$EstimateDS.' men)';
2905 $VeryShortSummary=$ShortSummary;
2906 $ShortSummary.=$ArmyListing;
2907 $ShortSummary.= "<span style=\"color: #AAA;\">".$Unimsg."</span>";
2908 $summary .= "$AC attackers (";
2909 $troops="";
2910 foreach($types as $curtype) {
2911 if (${"A-$curtype"}>0) $troops.=", ".${"A-$curtype"}." $curtype";
2912 }
2913 $summary .= substr($troops,2);
2914 $summary .= ")<br>$DC defenders (";
2915 $troops="";
2916 foreach($types as $curtype) {
2917 if (${"D-$curtype"}>0) $troops.=", ".${"D-$curtype"}." $curtype";
2918 }
2919 $summary .= substr($troops,2);
2920 $summary .= ")<br>Total combat strengths: $StartAS vs. $StartDS";
2921 if ($NC>0) {
2922 $summary.="<br>\n$NC neutral observers ($NS combat strength).";
2923 }
2924 $summary .= "<br><p>\n";
2925
2926 // Battle size effects
2927 $ClaimStrength = 2;
2928
2929 if ($StartAS>1000&&$StartDS>1000) $ClaimStrength++;
2930 if ($StartAS>2500&&$StartDS>2500) $ClaimStrength++;
2931 if ($StartAS+$StartDS>4000) $ClaimStrength++;
2932 if ($StartAS+$StartDS>7500) $ClaimStrength++;
2933 if ($StartAS+$StartDS>10000) $ClaimStrength++;
2934 if ($StartAS>3000&&$StartDS>3000&&$StartAS+$StartDS>8000) $HugeBattle=true;
2935 else $HugeBattle=false;
2936
2937 /* honour bonus for daring combats */
2938 if ($StartAS>$StartDS*1.5&&$StartAS<$StartDS*6) {
2939 db_query("update RunCombat set CommanderHonour=CommanderHonour+10 where CombatRole='defender'");
2940 } else if ($StartDS>$StartAS*1.5&&$StartDS<$StartAS*4) {
2941 db_query("update RunCombat set CommanderHonour=CommanderHonour+10 where CombatRole='attacker'");
2942 }
2943
2944 /* no honour for crushing weak opponents */
2945 if ($StartAS>$StartDS*5) {
2946 db_query("update RunCombat set CommanderHonour=CommanderHonour-20 where CombatRole='attacker'");
2947 } else if ($StartDS>$StartAS*5) {
2948 db_query("update RunCombat set CommanderHonour=CommanderHonour-20 where CombatRole='defender'");
2949 }
2950
2951 /* --- Fight until only one side remains --- */
2952
2953 $CombatSummary = $summary.$msg."<P>";
2954
2955 $CombatSummary.="<span style=\"font-size: 80%; text-align: center;\">(legend: I=Infantry, M=Mixed Inf, A=Archers, C=Cavalry, S=Special Forces, U=Undead, M=Monsters)</span><br>\n";
2956
2957 if ($debug>15) { echo "Start Combat...<br>\n"; }
2958 $done=false; $count=0; $msg=""; $CFD=0;
2959 while (!$done) {
2960 if ($debug>15) { echo "<hr/>Turn "; echo $count+1; echo ":<br>\n"; }
2961 /* preparation: set up serials */
2962 $ares = db_query("select * from RunCombat where CombatLine is not NULL");
2963 while ($arow=db_fetch_array($ares)) {
2964 $ser = rand(0,10000);
2965 db_query("update RunCombat set Serial=$ser where ID=$arow[ID]");
2966 }
2967 /* preparation: draw battleview */
2968 $msg.="<table style=\"background-color: #004000; width: 100%;\" border=\"2\"><tr>";
2969 for ($i=-$CombatLines;$i<=$CombatLines;$i++) {
2970 if ($Fortification==0||$i<=0) $msg.="<td width=\"9%\">";
2971 else {
2972 if ($i==0||$RegType=="Stronghold") $msg.="<td width=\"9%\" style=\"background-color: #606060;\">";
2973 else $msg.="<td width=\"9%\" style=\"background-color: #404040;\">";
2974 }
2975 $ares = db_query("select CombatNr,Strength,Commander,CombatRole,Type,Army from RunCombat where CombatLine=$i order by CombatNr ASC");
2976 if (db_num_rows($ares)==0) {
2977 $msg.=" ";
2978 } else {
2979 $curcolour="";
2980 while ($arow=db_fetch_array($ares)) {
2981 if ($arow["CombatRole"]=="attacker") $nextcolour='#FF6464';
2982 else $nextcolour='#9696FF';
2983 if ($curcolour!=$nextcolour) {
2984 if ($curcolour!="") $msg.="</span>";
2985 $msg.="<span style=\"color: $nextcolour;\">";
2986 $curcolour=$nextcolour;
2987 }
2988 $msg.=addtag($armyBanners[$arow['Army']]."$arow[CombatNr] ($arow[Strength]-".substr($arow["Type"],0,1).")<br>",$arow["Commander"]);
2989 }
2990 $msg.="</span>";
2991 }
2992 $msg.="</td>";
2993 }
2994 $msg.="</tr></table><p>\n";
2995 $t=$count+1;
2996 $CombatSummary.="<span style=\"color: white;\"><b>Turn No. $t</b></span><br>".$msg;
2997
2998 /* preparation: resets */
2999 $msg="";
3000 db_query("update RunCombat set CloseHits=0, RangedHits=0, HitsCaused=0");
3001
3002 /* CS recalculation */
3003 combatstrength(-1,"RunCombat");
3004 if ($DefFort) db_query("update RunCombat set CombatStrength=CombatStrength*1.1 where CombatRole='defender' and Designation='sentries'");
3005
3006 /* home region bonus */
3007 db_query("update RunCombat set CombatStrength=CombatStrength*1.1 where Realm=$Owner");
3008
3009 $FortificationBreached = db_fetch_single("select count(*) from RunCombat where CombatRole='attacker' and CombatLine>0");
3010
3011 $ANoCombat = array();
3012 $DNoCombat = array();
3013
3014 /* === main fighting part === */
3015 whoops_move_back();
3016 list( $ANoCombat, $DNoCombat ) = check_melee( $ANoCombat, $DNoCombat );
3017 artillery_fire($Weather,$Fortification,$FortificationBreached);
3018 /* we deal with cavalry (and daimons) seperately - so they won't charge walls together with infantry */
3019 cavalry_charge($Fortification,$FortificationBreached);
3020 $SE=0;
3021 if ($Fortification) {
3022 $Scalers = db_fetch_single("select count(*) from RunCombat where CombatLine=0 and CombatRole='attacker'");
3023 if ($Scalers>0) {
3024 $SE=db_fetch_single("select sum(SiegeEngines) from RunCombat where CombatLine=0 and CombatRole='attacker'");
3025 if ($SE==1) $msg.="<span style=\"color: #E0E0FF;\">There is one siege engine at the wall.</span><br>\n";
3026 else if ($SE>1) $msg.="<span style=\"color: #E0E0FF;\">There are $SE siege engines at the walls.</span><br>\n";
3027 }
3028 }
3029 units_advance($Fortification, $SE, $count); /* all non-cavalry/daimonic units */
3030 list( $ANoCombat, $DNoCombat ) = check_melee( $ANoCombat, $DNoCombat ); /* Check all the units that weren't in close combat before, but are now */
3031 $msg.=unroll_textarray($ANoCombat, "cannot join the melee, as it is too crowded.<br>\n");
3032 $msg.=unroll_textarray($DNoCombat, "cannot join the melee, as it is too crowded.<br>\n");
3033
3034 $msg.="<br/>";
3035 close_combat();
3036 /* exhaustion - except for Undead and Daimons */
3037 db_query("update RunCombat set Morale=GREATEST(1,Morale-(CloseCount*2)) where Type not in ('Undead','Daimons')");
3038 /* Hero class - hero adds morale to their unit each round */
3039 db_query("update RunCombat set Morale=LEAST(100,Morale+10) where CommanderSubclass='Hero'");
3040 if ($count>2) panic_checks($Fortification, $count);
3041
3042 damage_effects($Here, $RegName, $RegType, $Fortification, $FortDamage, $count, $OverkillAttackers, $OverkillDefenders);
3043 db_query("Update RunCombat set CloseWith=NULL");
3044
3045 /* damage to fortifications */
3046 if ($Fortification) {
3047 $DefHits = intval(db_fetch_single("select sum(CloseHits+RangedHits/10) from RunCombat where CombatRole='defender' and CombatLine>0"));
3048 $maxnewdam=max(0,floor((sqrt($DefHits)/2)-2));
3049 $newdam=rand(0,$maxnewdam);
3050 if ($debug>20) { echo "===> Fortification Damage: Defhits $DefHits, max $maxnewdam, real: $newdam<br>\n"; }
3051 if ($newdam>0) {
3052 $CFD+=$newdam;
3053 if ($debug>20) { echo "* $newdam % fortification damage<br>\n"; }
3054 }
3055 }
3056
3057 /* prevent units leaving the field - we could interpret it as fleeing, but we don't */
3058 db_query("update RunCombat set CombatLine=-$CombatLines where CombatLine<-$CombatLines");
3059 db_query("update RunCombat set CombatLine=$CombatLines where CombatLine>$CombatLines");
3060
3061 /* Training and Morale (and a steady +1 % damage per round IF USED) */
3062 $ares = db_query("select * from RunCombat where CombatLine is not NULL");
3063 while ($arow=db_fetch_array($ares)) {
3064 $Train=10;
3065 if ($count<10) {
3066 $Train=round((10-$count)*(100-$arow["Training"])/100);
3067 }
3068 /* ranged hits count more - it sucks twice as bad if you can't fight back */
3069 $Hits=$arow["CloseHits"]+($arow["RangedHits"]*2);
3070 if ($Hits==0) {
3071 $Mor=-1;
3072 } else if ($Hits<$arow["Strength"]) {
3073 $Mor=-2;
3074 } else if ($Hits<$arow["Strength"]*5) {
3075 $Mor=-5;
3076 } else if ($Hits<$arow["Strength"]*10) {
3077 $Mor=-7;
3078 } else if ($Hits<$arow["Strength"]*25) {
3079 $Mor=-10;
3080 } else {
3081 $Mor=-15;
3082 }
3083 $Mor+=floor($arow["Training"]/10);
3084 if ($debug>20) { echo "** Unit $arow[Name]: +$Train training, $Mor morale<br>\n"; }
3085 $extra=""; if ($Hits>0) $extra=", ChangeDamage=ChangeDamage+1";
3086 db_query("update RunCombat set CloseHits=0, RangedHits=0, Morale=GREATEST(1,Morale+$Mor), ChangeMorale=ChangeMorale+$Mor, UnitTraining=UnitTraining+$Train $extra where ID=$arow[ID]");
3087 }
3088
3089 /* 5th strike: battle over? */
3090 $CountAttackers = db_fetch_single("select count(ID) from RunCombat where CombatRole='attacker' and CombatLine is not NULL");
3091 $CountDefenders = db_fetch_single("select count(ID) from RunCombat where CombatRole='defender' and CombatLine is not NULL");
3092 $Winners="";
3093 if ($CountAttackers==0||$CountDefenders==0) {
3094 if ($CountAttackers==0) {
3095 $msg.= "<p><b><span style=\"color: #C0FFC0;\">Defender Victory!</span></b><br>\n";
3096 $ShortSummary.= "<p><b><span style=\"color: #C0FFC0;\">Defender Victory!</span></b><br>\n";
3097 $VeryShortSummary.= "<p><b><span style=\"color: #C0FFC0;\">Defender Victory!</span></b><br>\n";
3098 $historySummary = $historyAttackers.' attacked '.$historyDefenders.' and were defeated';
3099 $Winners="defender";
3100 $Honour=4; $Prestige=2;
3101 if ($CountDefenders<5) $Prestige++;
3102 if ($CountDefenders<3) $Prestige++;
3103 if ($StartDS<$StartAS*5) { $Honour+= 5; $Prestige+=2; }
3104 if ($StartDS<$StartAS*2) { $Honour+=10; $Prestige+=3; }
3105 if ($StartDS<$StartAS) { $Honour+=10; $Prestige+=4; }
3106 if ($StartDS*2<$StartAS) { $Honour+=10; $Prestige+=5; }
3107 db_query("update RunCombat set CommanderHonour=CommanderHonour+$Honour, CommanderPrestige=CommanderPrestige+$Prestige where CombatRole='defender'");
3108 db_query("update RunCombat set ChangeMorale=ChangeMorale-10 where CombatRole='attacker'");
3109 } else {
3110 $msg.= "<p><b><span style=\"color: #FFC0C0;\">Attacker Victory!</span></b><br>\n";
3111 $ShortSummary.= "<p><b><span style=\"color: #FFC0C0;\">Attacker Victory!</span></b><br>\n";
3112 $VeryShortSummary.= "<p><b><span style=\"color: #FFC0C0;\">Attacker Victory!</span></b><br>\n";
3113 $historySummary = $historyAttackers.' attacked '.$historyDefenders.' and were victorious';
3114 $Winners="attacker";
3115 $Honour=2; $Prestige=5;
3116 if ($CountAttackers<5) $Prestige++;
3117 if ($CountAttackers<3) $Prestige++;
3118 if ($StartAS<$StartDS*5) { $Honour+= 5; $Prestige+=3; }
3119 if ($StartAS<$StartDS*2) { $Honour+= 5; $Prestige+=4; }
3120 if ($StartAS<$StartDS) { $Honour+=10; $Prestige+=5; }
3121 if ($StartAS*2<$StartDS) { $Honour+=10; $Prestige+=6; }
3122 db_query("update RunCombat set CommanderHonour=CommanderHonour+$Honour, CommanderPrestige=CommanderPrestige+$Prestige where CombatRole='attacker'");
3123 db_query("update RunCombat set ChangeMorale=ChangeMorale-10 where CombatRole='defender'");
3124 }
3125 $done=true;
3126 } else {
3127 /* 6th strike: countdown */
3128 $count++;
3129 db_query("update RunCombat set CombatWait=CombatWait-1 where CombatWait>0");
3130 $hold = db_fetch_single( "Select Count(*) from RunCombat where MarshalFormation='HoldLine' and CombatLine = 1" );
3131 if ($hold > 0) {
3132 $enemiesLeft = db_fetch_single( "Select count(*) from RunCombat where CombatRole='attacker' and CombatLine < 1" );
3133 if ($enemiesLeft > 0) {
3134 db_query( "Update RunCombat set CombatWait=10 where where MarshalFormation='HoldLine' and CombatLine = 1" );
3135 }
3136 }
3137 }
3138
3139 $CombatSummary.=$msg."<P>";
3140 $msg="";
3141 /* safety catch */
3142 if ($count>=20) {
3143 $CombatSummary.="<br>The battle ends indecisive. No winners.<br>\n";
3144 $ShortSummary.= "<p><b>The battle ends indecisive. No winners.</b><br>\n";
3145 $VeryShortSummary.= "<p><b>The battle ends indecisive. No winners.</b><br>\n";
3146 $historySummary = $historyAttackers.' attacked '.$historyDefenders.' and fought to a stalemate';
3147 $done=true;
3148 }
3149 }
3150
3151 combatstrength(-1,"RunCombat");
3152 region_damage($StartAS, $StartDS, $Here, $RegName, $RegType, $Fortification, $FortDamage, $CFD, $FortBreached, $count);
3153
3154 if ($evilSide && $evilSide != $Winners) {
3155 $loyalty_gain=rand(0,3);
3156 if ($loyalty_gain) {
3157 db_query( "Update Morale join RunCombat on Morale.Realm_ID=RunCombat.Realm set Morale.MaxMorale=LEAST(100,MaxMorale+$loyalty_gain) where RunCombat.CombatRole='$Winners' and Morale.Region_ID=$Here");
3158 $CombatSummary.="The locals are grateful for defeating the evil forces plaguing their region. <br/>";
3159 }
3160 }
3161
3162 /* summary */
3163 message(db_get_array("select Commander from RunCombat where Commander is not NULL"), "<a name=#battle>Battle in $RegName</a>", $CombatSummary, 'Personal');
3164 $Hash = substr(md5($CombatSummary.time()),0,16);
3165 $ScribeID = db_getnextID("Scribes");
3166 $Title="Battle in $RegName";
3167 /* remove all char tags, this should save a LOT of space and makes the scribe note more general */
3168 $Content = preg_replace("/<\/?Char [0-9]+>/", "", $CombatSummary);
3169 db_query("insert into Scribes set ID=$ScribeID, Hash='$Hash', Owner=0, Region=$Here, LifeSpan=12, Title='".db_string($Title)."', Content='".db_string($Title."<br>".$CombatSummary)."'");
3170
3171 after_battle_status($RegName,$Here);
3172 sleep(1);
3173
3174 /* move data back into real table and update commander data */
3175 db_query("update RunCombat set Position='normal' where Position not in ('evading','retreated','scattered')");
3176 $BattleLength=round($count/5)+1;
3177
3178 $now = new \DateTime();
3179 $ares = db_query("select * from RunCombat");
3180 while ($arow=db_fetch_array($ares)) {
3181 if ($arow["Commander"]) {
3182 /* copy scribe report as scribe copy */
3183 db_query("insert into ScribeCopies set Player_ID=$arow[Commander], Scribe_ID=$ScribeID");
3184 }
3185 if ($arow["CombatRole"]=="neutral") {
3186 $mymsg="You have witnessed a battle in $RegName. Your scribe has written down a battle report as a [Scribe:$ScribeID|$Hash].<br><p>";
3187 if ( $arow['Position'] != "evading" ) {
3188 db_query("update Troops set Position='neutral' where ID=$arow[ID]");
3189 }
3190 } else {
3191 $mymsg="Your unit participated in a battle in $RegName. Your scribe has written down a battle report as a [Scribe:$ScribeID|$Hash].<br><p>";
3192 $Hon=$arow["CommanderHonour"];
3193 $Pres=$arow["CommanderPrestige"];
3194 if ($arow["Commander"]>0&&$arow["CommanderPresent"]=="yes") {
3195 /* making it more difficult if you already have lots */
3196 $bres = db_query("select Honour,Prestige,Subclass from Players where ID=$arow[Commander]");
3197 $brow = db_fetch_array($bres);
3198 $Hon=floor($arow["CommanderHonour"]/(20+$brow["Honour"]/12))+1;
3199 $Pres=round($arow["CommanderPrestige"]/min(15,(1+$brow["Prestige"])));
3200
3201 /* easier for beginners */
3202 if ($brow['Honour']<15) { $Hon++; }
3203 if ($brow['Honour']<25) { $Hon++; }
3204 if ($arow['CombatRole']==$Winners&&$brow['Prestige']<5) { $Pres++; }
3205 if ($arow['CombatRole']==$Winners&&$brow['Prestige']<10) { $Pres++; }
3206
3207 /* Cavaliers get extra honour */
3208 if ($brow['Subclass']=='Cavalier') $Hon++;
3209
3210 /* Prestige pretty hard to gain beyond 25 */
3211 if ($brow["Prestige"]>25) $Pres-=round($brow["Prestige"]/30);
3212
3213 /* can't get more prestige than honour in a battle */
3214 if ($Pres>$Hon) { $Pres=$Hon; }
3215
3216 /* not much gain during short battles */
3217 if ($Hon>$count) { $Hon=max(1,$count); }
3218 if ($Pres>$count/2) { $Pres=floor($count/2); }
3219 $Pres=max(0,$Pres);
3220
3221 /* almost nothing to gain when fighting only peasants */
3222 if ($OnlyPeasants) {
3223 if ($debug>20) { echo "Reduced Pres/Hon: OnlyPeasants<br>\n"; }
3224 $Pres=0; $Hon=floor($Hon/3);
3225 }
3226
3227 /* update player data */
3228 db_query("update Players set Honour=Honour+$Hon, Prestige=Prestige+$Pres, Hours=Hours-$BattleLength where ID=$arow[Commander]");
3229 $mymsg.="The battle lasted for $BattleLength hours.<br>\nYou have gained $Hon Honour";
3230 if ($Pres>0) { $mymsg.=" and $Pres Prestige"; }
3231 $mymsg.=".<br>\n";
3232
3233 /* experience with the sword or lance */
3234 if ($arow["CommanderXP"]>0) {
3235 switch ($arow["Type"]) {
3236 case "Cavalry":
3237 if (skill_gain($arow["Commander"],"Jousting",floor($arow["CommanderXP"]/2))>0)
3238 $mymsg.="Your jousting skill has increased.<br>\n";
3239 break;
3240 case "Infantry":
3241 if (skill_gain($arow["Commander"],"Swordfighting",floor($arow["CommanderXP"]/2))>0)
3242 $mymsg.="You have improved your swordfighting skill.<br>\n";
3243 break;
3244 case "Archers": /* nothing */
3245 break;
3246 default: /* MI, special forces, might: */
3247 if ($arow["WpnRange"]>0) $XP=floor($arow["CommanderXP"]/($arow["WpnRange"]+2));
3248 else $XP=floor($arow["CommanderXP"]/3);
3249 if ($XP>0) {
3250 if (skill_gain($arow["Commander"],"Swordfighting",$XP)>0);
3251 $mymsg.="You have improved your swordfighting skill.<br>\n";
3252 }
3253 }
3254 $XP = floor($arow["CommanderXP"]/2);
3255 $Comm = DoctrineWorldEM()->getRepository('BattleMaster\Character')->find($arow["Commander"]);
3256 $CommArmy = $Comm->getArmy();
3257 if ($CommArmy && in_array($Comm,array($CommArmy->getMarshal()))) {
3258 $XP = floor($XP*1.2);
3259 } else if ($CommArmy && in_array($Comm,array($CommArmy->getSecond()))) {
3260 $XP = floor($XP*1.1);
3261 }
3262 if (skill_gain($arow["Commander"],"Leadership",$XP)>0)
3263 $mymsg.="You have improved your leadership skill.<br>\n";
3264 }
3265 if ($arow['CaptainSkill']>0) {
3266 if (rand(0,$arow['CaptainSkill']*2)==0 && $arow['CaptainSkill']<50) {
3267 /* increased skill */
3268 $mymsg.="Your captain has improved his skill level.<br>\n";
3269 $arow['CaptainSkill']++;
3270 }
3271 }
3272 } else if ($arow["Commander"]>0) {
3273 /* we have one, but he was not there */
3274 $mymsg="Since you were not present at the battle, you receive no honour or prestige.<br>\n";
3275 }
3276
3277 /* Extras */
3278 if ($arow["Banners"]==0&&$arow["Commander"]) {
3279 db_query("delete from PlayerExtras where Player_ID=$arow[Commander] and Extra_ID=$ExtraBanners");
3280 } else if ($arow["Banners"]>0&&$arow["Commander"]) {
3281 db_query("update PlayerExtras set Number=$arow[Banners] where Player_ID=$arow[Commander] and Extra_ID=$ExtraBanners");
3282 }
3283 if ($arow["SiegeEngines"]==0&&$arow["Commander"]) {
3284 db_query("delete from PlayerExtras where Player_ID=$arow[Commander] and Extra_ID=$ExtraSE");
3285 } else if ($arow["SiegeEngines"]>0&&$arow["Commander"]) {
3286 db_query("update PlayerExtras set Number=$arow[SiegeEngines] where Player_ID=$arow[Commander] and Extra_ID=$ExtraSE");
3287 }
3288
3289 if ($arow["Type"]!='Hero') {
3290 if ($arow["Strength"]+$arow["Wounded"]==0) {
3291 db_query("delete from Troops where ID=$arow[ID]");
3292 $mymsg.="Your unit was wiped out to the last man.<br>";
3293 /* add battle loot */
3294 $Loot+=$arow["FullStrength"]*sqrt($arow['Weapons']+$arow['Armour'])*2;
3295 } else {
3296 $CMor=$arow["ChangeMorale"];
3297 $CDam=$arow["ChangeDamage"];
3298 /* morale bonus for troops with little losses */
3299 if ($arow["Strength"]>$arow["FullStrength"]*0.9) {
3300 $CMor+=5;
3301 }
3302 /* regular damage */
3303 $CDam+=min(rand(0,min($count,5)),rand(0,min($count,5)));
3304 $CMor-=rand(0,5);
3305
3306 if ($arow["Morale"]+$CMor>100) {
3307 $CMor=100-$arow["Morale"];
3308 } else if ($arow["Morale"]+$CMor<1) {
3309 $CMor=1-$arow["Morale"];
3310 }
3311 if ($arow["Damage"]+$CDam>100) {
3312 $CDam=100-$arow["Damage"];
3313 } else if ($arow["Damage"]+$CDam<0) {
3314 $CDam=-$arow["Damage"];
3315 }
3316 if ($arow["UnitTraining"]>100) {
3317 $Train=round($arow["UnitTraining"]/12);
3318 } else if ($arow["UnitTraining"]>50) {
3319 $Train=round($arow["UnitTraining"]/8);
3320 } else {
3321 $Train=round($arow["UnitTraining"]/5);
3322 }
3323 $RealTrain=0; $RealCohesion=rand(1,3);
3324 for ($i=0;$i<$Train;$i++) {
3325 if (rand(0,100)>$arow["Training"]) { $RealTrain++; }
3326 if (rand(0,100)<65) { $RealCohesion++; }
3327 }
3328 if ($RealTrain<$arow["UnitTraining"]/10) $RealTrain++;
3329 if ($arow["Training"]+$RealTrain>100) $RealTrain=100-$arow["Training"];
3330 if ($arow["Cohesion"]+$RealCohesion>100) $RealCohesion=100-$arow["Cohesion"];
3331 if ($arow["Position"]=="retreated"||$arow["Position"]=="scattered") $RealCohesion=floor($RealCohesion/2);
3332
3333 /* not much to gain when fighting only peasants */
3334 if ($OnlyPeasants) {
3335 $RealTrain=floor($RealTrain/3);
3336 if ($CMor>=0) { $CMor-=rand(1,5); }
3337 }
3338
3339 /* undead don't learn stuff */
3340 if ($arow["Type"]=="Undead") $RealTrain=0;
3341
3342 /* loss info */
3343 $wounded = $arow["Wounded"]-$arow["FullWounded"];
3344 $dead = $arow["FullStrength"]-$arow["Strength"]-$wounded;
3345 if ($dead==0) { $dead="None"; }
3346 $mymsg.="$dead of your men were killed ";
3347 if ($wounded>0) {
3348 if ($dead>0) $mymsg.="and "; else $mymsg.="but ";
3349 $mymsg.="$wounded were wounded ";
3350 }
3351 $mymsg.="in this battle.<br>\n";
3352 /* add battle loot */
3353 $Loot+=$dead*sqrt($arow['Weapons']+$arow['Armour'])*2;
3354
3355 /* update unit data */
3356 if ($CMor>=0) { $CMor=floor($CMor/2)-rand(0,2); }
3357 $DR=intval($dead)+intval($wounded);
3358 db_query("update Troops set Morale=GREATEST(1,LEAST(100,Morale+$CMor)), Cohesion=LEAST(Cohesion+$RealCohesion,100), Damage=Damage+$CDam, Training=Training+$RealTrain, Strength=$arow[Strength], Wounded=$arow[Wounded], Position='$arow[Position]', CaptainSkill=$arow[CaptainSkill], TotalRest=0 where ID=$arow[ID]");
3359 if ($CMor>0) {
3360 $mymsg.="Your unit gains $CMor points of Morale. ";
3361 } else if ($CMor<0) {
3362 $M=abs($CMor);
3363 $mymsg.="Morale of your troops falls by $M points. ";
3364 }
3365 if ($CDam>0) $mymsg.="Your men's equipment suffers $CDam % damage. ";
3366 if ($RealTrain>0) $mymsg.="Combat training increases by $RealTrain points. ";
3367 if ($RealCohesion>0) $mymsg.="Unit cohesion rises $RealCohesion points. ";
3368 $mymsg.="<br>\n";
3369 }
3370 }
3371 if ($HugeBattle && $arow['Commander']) {
3372 db_query("Insert into CharacterHistory set characterId=".$arow['Commander'].", date='".$now->format('Y-m-d H:i:s')."', world=".$World.", level=4, regionToId=".$Here.", eventType='Huge Battle', description='Participated in a huge battle in ".$RegName.": ".$historySummary."'");
3373 }
3374 }
3375
3376 if ($arow["Commander"]&&$mymsg!="") {
3377 /* personal result, only as personal if we were present */
3378 if ($arow['CommanderPresent']=='yes') $T='Personal'; else $T='Report';
3379 message($arow["Commander"], "Battle Results", $mymsg, $T);
3380 }
3381 }
3382
3383 $Loot=round($Loot);
3384 if ($debug>15) { echo "Battlefield Loot: $Loot units.<br>\n"; }
3385 db_query("update Regions set BattleLoot=BattleLoot+$Loot where ID=$Here");
3386
3387 /* stop takeover attempts unless takeoverrealm is among the victors */
3388 list($TO, $TORealm) = db_fetch_single("select ID,Realm_ID from Takeovers where Region_ID=$Here");
3389 if ($TORealm) {
3390 if (db_fetch_single("select count(*) from RunCombat where Realm=$TORealm and CombatRole in ('$Winners') and CombatLine<10")>0) {
3391 /* we're still here, takeover continues */
3392 } else {
3393 /* takeover stopped */
3394 if ($debug>15) { echo "Takeover stopped!<br>\n"; }
3395 list($RegName, $RegRealm) = db_fetch_single("select Name, Realm from Regions where ID=$Here");
3396 $msg = "The takeover attempt in $RegName has been stopped.";
3397 message(db_get_array("select ID from Players where active='yes' and Realm in ($RegRealm, $TORealm)"), "Takeover stopped", $msg);
3398 db_query("delete from Takeovers where ID=$TO");
3399 }
3400 }
3401
3402 /* message to other players of involved realms */
3403 $Coms = db_get_list("select Commander from RunCombat where Commander is not NULL");
3404 if ($Coms) $mod=" and ID NOT IN ($Coms)"; else $mod="";
3405 if ( !$RealmList ) {
3406 $RealmList = "0";
3407 }
3408 message(db_get_array("select ID from Players where active='yes' and Realm in ($RealmList) and Realm>0 $mod"), "Battle in $RegName", $ShortSummary, "Report");
3409
3410 /* Ratings and Diplomatic effects */
3411 /* winner side allies realms gain popview */
3412 if ($Winners!="") {
3413 $WinnerRealms = db_get_list("select distinct Realm from RunCombat where CombatRole='$Winners'");
3414 if (strstr($WinnerRealms,",")) db_query("update Diplomacy set PopView=LEAST(100,PopView+1) where Left_ID in ($WinnerRealms) and Top_ID in ($WinnerRealms)");
3415 /* losers hate all winners, and ratings */
3416 $LoserRealms = db_get_list("select distinct Realm from RunCombat where CombatRole!='$Winners' and CombatRole!='neutral'");
3417 db_query("update Diplomacy set PopView=GREATEST(1,PopView-1),Rating=Rating-1 where Left_ID in ($LoserRealms) and Top_ID in ($WinnerRealms)");
3418 $TotalCS=$StartAS+$StartDS;
3419 if ($TotalCS<1000) $Score=1;
3420 else if ($TotalCS<5000) $Score=2;
3421 else if ($TotalCS<10000) $Score=3;
3422 else $Score=4;
3423 db_query("update Diplomacy set Rating=Rating+$Score where Left_ID in ($WinnerRealms) and Top_ID in ($LoserRealms)");
3424 db_query("update Diplomacy set Rating=Rating-$Score where Left_ID in ($LoserRealms) and Top_ID in ($WinnerRealms)");
3425 }
3426
3427 /* Remove temporary table */
3428 db_query("DROP TABLE RunCombat");
3429
3430 /* huge battles are reported world-wide */
3431 if ($HugeBattle) {
3432 $ShortSummary="Rumours spread and tales are sung about a huge battle in [Region:$RegName]:<br>".$ShortSummary;
3433 $VeryShortSummary="Rumours spread of a huge battle in $RegName:<br>".$VeryShortSummary;
3434 worldnews("Realm not in ($RealmList) and Location!=$Here", db_string($VeryShortSummary), db_string($ShortSummary), "Huge Battle Fought");
3435 }
3436
3437} /* end of combatloop */
3438db_query("DROP TABLE IF EXISTS RunCombat");
3439//db_query("delete from Troops where Type='Peasants'");
3440
3441/* settling in */
3442db_query("update Troops set Position='normal' where Position='fresh' and Travel is NULL");
3443
3444/* removing dead hero units */
3445$Dead = db_get_list("select ID from Players where Status='dead'");
3446if ($Dead) db_query("delete from Troops where Commander in ($Dead) and Type not in ('Undead','Monsters')");
3447
3448if ($debug>15) { echo "$PHP_SELF (World $World): End: ".strftime("%T")."<br>\n"; }
3449db_query("replace Globals set Value='complete', Var='$turn'");