-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy patharmcom_defs.py
1168 lines (1089 loc) · 47.6 KB
/
armcom_defs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: UTF-8 -*-
##########################################################################################
# Definitions for Armoured Commander #
##########################################################################################
##########################################################################################
#
# Copyright 2015-2017 Gregory Adam Scott (sudasana@gmail.com)
#
# This file is part of Armoured Commander.
#
# Armoured Commander is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Armoured Commander is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with Armoured Commander, in the form of a file named "LICENSE".
# If not, see <http://www.gnu.org/licenses/>.
#
##########################################################################################
# national definitions: defines ranks and decorations
# ranks for USA
USA_RANKS = [
('Pvt.', 'Private', 0), # no insignia
('Pfc.', 'Private First Class', 0), # one stripe (pointing upwards)
('Cpl.', 'Corporal', 0), # two stripes
('Sgt.', 'Sergeant', 0), # three stripes (commander starts here)
('S/Sgt.', 'Staff Sergeant', 500), # three stripes, joined together in a half circle
('2nd Lt.', 'Second Lieutenant', 1000), # single gold bar, upright
('1st Lt.', 'First Lieutenant', 2000), # single silver bar, upright
('Capt.', 'Captain', 3000) # double golden bars, upright
]
# decorations for USA
USA_DECORATIONS = [
('Bronze Star', 'for heroic service', 80),
('Silver Star', 'for gallantry in action', 100),
('Distinguished Service Cross', 'for extraordinary heroism', 120),
('Congressional Medal of Honor', 'for conspicuous gallantry and intrepidity', 140)
]
# ranks for UK and Commonwealth
UKC_RANKS = [
('Tpr.', 'Trooper', 0),
('LCpl.', 'Lance Corporal', 0),
('Cpl.', 'Corporal', 0),
('Sgt.', 'Sergeant', 0),
('S/Sgt.', 'Staff Sergeant', 500),
('2nd Lt.', 'Second Lieutenant', 1000),
('Lt.', 'Lieutenant', 2000),
('Capt.', 'Captain', 3000)
]
# decorations for UK and Commonwealth
UKC_DECORATIONS = [
('Military Medal', 'for bravery in the field', 80),
('Military Cross', 'for acts of exemplary gallantry', 100),
('Distinguished Service Order', 'for meritorious service', 120),
('Victoria Cross', 'for valour in the face of the enemy', 140)
]
# characters and colours for animations
import libtcodpy as libtcod
HE_HIT_ANIMATION = [
(libtcod.CHAR_RADIO_UNSET, libtcod.dark_yellow, 220),
(libtcod.CHAR_LIGHT, libtcod.dark_red, 240),
(libtcod.CHAR_LIGHT, libtcod.red, 200),
(libtcod.CHAR_BLOCK1, libtcod.darker_grey, 300),
]
AP_HIT_ANIMATION = [
(libtcod.CHAR_RADIO_UNSET, libtcod.dark_yellow, 220),
(libtcod.CHAR_RADIO_UNSET, libtcod.dark_red, 240),
(libtcod.CHAR_RADIO_UNSET, libtcod.red, 200),
(libtcod.CHAR_RADIO_UNSET, libtcod.darker_grey, 300),
]
# list of stats to track in the campaign object, as well as text to use in campaign stats
# display window
C_STATS = [
'Map Areas Captured',
'Tanks Lost',
'Crewmen Sent Home',
'Crewmen KIA',
'Infantry Destroyed by Player',
'Infantry Destroyed by Allies',
'AT Guns Destroyed by Player',
'AT Guns Destroyed by Allies',
'Tanks & SPGs Destroyed by Player',
'Tanks & SPGs Destroyed by Allies',
'Other Vehicles Destroyed by Player',
'Other Vehicles Destroyed by Allies',
'Quests Assigned', 'Quests Completed'
]
# list of possible full screen resolutions to try
FS_RES_LIST = [(1366, 768), (1680, 1050), (1920, 1080)]
# Crew Skill defintion
# holds information relating to a type of crew skill
class CrewSkill:
def __init__(self, name, desc, restrictions, levels):
self.name = name
self.desc = desc
self.restrictions = restrictions
self.levels = levels # if always active: [100]
def __repr__(self):
return str(self.levels)
SKILLS = []
# Commander
SKILLS.append(CrewSkill('Fire Direction', 'Increases modifier for directing fire by +1.',
['Commander'], [3,5,7]))
SKILLS.append(CrewSkill('Driver Direction', 'Increases modifier for movement-related ' +
'rolls by +1.', ['Commander'], [3,5,7]))
SKILLS.append(CrewSkill('Battle Leadership', 'Increases chance of all other crew skill ' +
'activations for the encounter turn in which it activates.', ['Commander'], [2,4,6]))
# current effect is +5% chance of activation
SKILLS.append(CrewSkill('Keen Senses', 'Decreases chances of being ambushed at the start ' +
'of an Advance or Battle encounter, increases chances of ambushing enemy in a ' +
'Counterattack encounter.', ['Commander'], [10,20,30]))
# Gunner
SKILLS.append(CrewSkill('Quick Trigger', 'Bonus to Rate of Fire roll.', ['Gunner'], [5,10,15]))
SKILLS.append(CrewSkill('Knows Weak Spots', 'An unmodified roll of 3 counts ' +
'as a critical hit if activated.', ['Gunner'], [5,10,15]))
SKILLS.append(CrewSkill('Target Tracking', 'No negative to-hit modifier for firing at a moving target.',
['Gunner'], [5,10,15]))
SKILLS.append(CrewSkill('Gyrostabilizer', 'Gunner must have at least one level ' +
'of this skill to fire main gun while moving. If skill activates, to-hit penalty ' +
'is +2, otherwise it doubles to +4. This skill only becomes available after first ' +
'refit period of campaign.', ['Gunner'], [10,20,40,80,100]))
# Loader
SKILLS.append(CrewSkill('Fast Hands', 'Bonus to Rate of Fire roll.', ['Loader'], [5,10,15]))
SKILLS.append(CrewSkill('Shell Juggler', 'If activated, reloaded shell is taken from ' +
'general stores instead of ready rack.', ['Loader'], [3,5,7]))
SKILLS.append(CrewSkill('Scrounger', 'More rare ammo types for main gun available if activated.',
['Loader'], [20,40,60,80]))
# Driver
SKILLS.append(CrewSkill('Drag Racer', 'If tank is moving from a stopped position, ' +
'bonus to movement roll.', ['Driver'], [10,20,30]))
SKILLS.append(CrewSkill('Eye for Cover', 'If hatch is open, receives a bonus to achieve ' +
'Hull Down status.', ['Driver'], [3,5,7]))
SKILLS.append(CrewSkill('Tough Mudder', 'If hatch is open, receives a bonus to unbogging ' +
'roll.', ['Driver'], [3,5,7]))
SKILLS.append(CrewSkill('Cautious Driver', 'Greater chance for tank to start an encounter ' +
'Hull Down, otherwise tank starts the encounter Moving.', ['Driver'], [5,10,15]))
# Asst Driver
SKILLS.append(CrewSkill('Apprentice Gunner', 'Bonus to to-kill roll when firing bow MG.',
['Asst. Driver'], [10,20,30]))
SKILLS.append(CrewSkill('Shell Tosser', 'Doubles bonus to Rate of Fire roll when passing ' +
'ammo.', ['Asst. Driver'], [10,20,30]))
# Most
SKILLS.append(CrewSkill('Eagle Eyed', 'This crewman has an uncanny ability to spot and identify enemy units' +
' when spotting though an open hatch.', ['Commander', 'Loader', 'Driver',
'Asst. Driver'], [5,10,15]))
# All
SKILLS.append(CrewSkill('Pocket Bible', 'Chance to ignore a Dead result when wounded.',
[], [20,40,60,80]))
SKILLS.append(CrewSkill('Gymnast', 'Bonus to Bail Out roll.', [], [20,40,60,80]))
SKILLS.append(CrewSkill('Lightning Reflexes', 'Chance to ignore wound from collateral ' +
'damage when crewman is exposed (open hatch, etc.)', [], [20,40,60,80]))
SKILLS.append(CrewSkill('True Grit', 'Better odds of recovering from negative status ' +
'effects, resisting Stun, plus more likely that a wound will be less severe.',
[], [20,40,60,80]))
SKILLS.append(CrewSkill('Mechanic', 'Bonus to repair a tank malfunction.',
[], [20,40,60,80]))
# highest level that a crew member can reach
LEVEL_CAP = 40
# possible ammo types for player tanks
AMMO_TYPES = ['HE', 'AP', 'WP', 'HCBI', 'HVAP', 'APDS']
# hex location system
# hx, hy, range, list of sectors
HEXES = [
# long range hexes
(0, -3, 2, 4), (1, -3, 2, 4), (2, -3, 2, 5), (3, -3, 2, 5), (3, -2, 2, 5),
(3, -1, 2, 0), (3, 0, 2, 0), (2, 1, 2, 0), (1, 2, 2, 1), (0, 3, 2, 1),
(-1, 3, 2, 1), (-2, 3, 2, 2), (-3, 3, 2, 2), (-3, 2, 2, 2),
(-3, 1, 2, 3), (-3, 0, 2, 3), (-2, -1, 2, 3), (-1, -2, 2, 4),
# medium range hexes
(0, -2, 1, 4), (1, -2, 1, 4), (2, -2, 1, 5), (2, -1, 1, 5), (2, 0, 1, 0),
(1, 1, 1, 0), (0, 2, 1, 1), (-1, 2, 1, 2), (-2, 2, 1, 2),
(-2, 1, 1, 3), (-2, 0, 1, 3), (-1, -1, 1, 4),
# close range hexes
(0, -1, 0, 4), (1, -1, 0, 5), (1, 0, 0, 0), (0, 1, 0, 1),
(-1, 1, 0, 2), (-1, 0, 0, 3),
# player hex: special because only player tank can exist there, and range is -1
(0, 0, -1, -1)
]
# CrewOrder class
# defines the description and restrictions of crew orders
class CrewOrder:
def __init__(self, name, desc, spot, position_list):
self.name = name
self.desc = desc
self.spot = spot
self.position_list = position_list
# crew order definitions
# Order Name, Order description, Can Spot (bool)
# List of crew positions that can use this order (if list is empty, any crew
# member can use this order)
CREW_ORDERS = []
# None order available to several crew
CREW_ORDERS.append(CrewOrder('None', 'The crew member does nothing this turn.',
True, ['Commander', 'Gunner', 'Loader', 'Asst. Driver']))
# Commander
CREW_ORDERS.append(CrewOrder('Direct Movement', 'Help direct the movement of your ' +
'tank. Reduces the chance of a thrown track or bogging down. Full effect ' +
'if commander directing from open hatch, half effect if buttoned up and ' +
'tank has a vision cupola. Otherwise no effect. No effect on firing.',
True, ['Commander']))
CREW_ORDERS.append(CrewOrder('Direct Main Gun Fire', 'Help direct the fire of the main gun, ' +
'increasing the chances of a hit.',
True, ['Commander']))
CREW_ORDERS.append(CrewOrder('Direct Co-ax MG Fire', 'Help direct the fire of the co-ax ' +
'machine gun, increasing the chances of destroying the target. No effect if this ' +
'MG is not fired this turn.', True, ['Commander']))
CREW_ORDERS.append(CrewOrder('Direct Bow MG Fire', 'Help direct the fire of the bow ' +
'machine gun, increasing the chances of destroying the target. No effect if this ' +
'MG is not fired this turn.', True, ['Commander']))
# Gunner
CREW_ORDERS.append(CrewOrder('Fire Main Gun', 'Fire the main gun at an enemy target. Gun ' +
'must already have a shell loaded in order to fire. Turret can be rotated before ' +
'firing, but if so then the first shot will be at a penalty.', False, ['Gunner']))
CREW_ORDERS.append(CrewOrder('Fire Co-Axial MG', 'Fire the Co-axial MG at an enemy target. ' +
'Turret can be rotated before firing, but if so then the shot will be at a ' +
'penalty.', True, ['Gunner']))
CREW_ORDERS.append(CrewOrder('Rotate Turret', "Rotate turret to face any sector. Gunner " +
"may only spot in the sector in front of the turret's new facing", True,
['Gunner']))
CREW_ORDERS.append(CrewOrder('Help Repair', 'Assist any crewman attempting to repair a ' +
'malfunction. Only effective if another crewman is on a repair order.', False,
['Gunner']))
# Loader
CREW_ORDERS.append(CrewOrder('Reload', "Reload the main gun if it's fired. No effect if " +
"main gun is malfunctioning. May only spot if main gun is not fired.", True,
['Loader']))
CREW_ORDERS.append(CrewOrder('Repair Main Gun', 'Attempt to repair a malfunctioning ' +
'main gun.', False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Repair Co-ax MG', 'Attempt to repair a malfunctioning ' +
'co-axial machine gun.', False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Repair Turret Traverse', 'Attempt to repair a broken turret ' +
'traverse gear.', False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Repair Radio', 'Attempt to repair a broken turret radio.',
False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Repair Intercom', 'Attempt to repair a broken tank intercom.',
False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Fire Smoke Mortar', 'Fire the 2" smoke mortar, creating a smoke ' +
'marker at Close range to the turret front. Also reloads the mortar if any rounds ' +
'are still available.', False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Change Gun Load', 'Change the type of round loaded in ' +
'the main gun to any round available. Will also reload the main gun if fired, but ' +
'cannot maintain RoF if Loader is on this order.',
False, ['Loader']))
CREW_ORDERS.append(CrewOrder('Restock Ready Rack', 'Refill the ready rack with any ' +
'rounds still available. Main gun will not be reloaded if it is fired this turn.',
False, ['Loader']))
# Driver
CREW_ORDERS.append(CrewOrder('Stop', 'Stop the tank.', True, ['Driver']))
CREW_ORDERS.append(CrewOrder('Forward', 'Move the tank forward.', True, ['Driver']))
CREW_ORDERS.append(CrewOrder('Forward to Hull Down', 'Move the tank forward and ' +
'attempt to move into a hull down position.', True, ['Driver']))
CREW_ORDERS.append(CrewOrder('Reverse', 'Move the tank backward.', True, ['Driver']))
CREW_ORDERS.append(CrewOrder('Reverse to Hull Down', 'Move the tank backward and ' +
'attempt to move into a hull down position.', True, ['Driver']))
CREW_ORDERS.append(CrewOrder('Pivot Tank', 'Pivot tank to face any sector. Counts as ' +
'moving, so may not fire main gun, and any hull down position is lost.',
True, ['Driver']))
CREW_ORDERS.append(CrewOrder('Attempt Unbog', 'Attempt to free the tank from ' +
'being bogged down. Bonus if commander is directing movement from an ' +
'open hatch, penalty if driver is buttoned up.', False, ['Driver']))
# Assistant Driver
CREW_ORDERS.append(CrewOrder('Fire Bow MG', "Fire the bow MG in the sector to the " +
"tank's front. May not fire if tank is hull down. Subtract crew member's " +
"skill from the To Kill roll.", True, ['Asst. Driver']))
CREW_ORDERS.append(CrewOrder('Repair Bow MG', 'Attempt to repair a malfunctioning ' +
'bow MG.', False, ['Asst. Driver']))
CREW_ORDERS.append(CrewOrder('Pass Ammo', 'Pass ammo to the Loader to improve reload ' +
'time. Increases chance of maintaining Rate of Fire. Has no effect when loading ' +
'from the ready rack.', False, ['Asst. Driver']))
# Orders available to several crew members
CREW_ORDERS.append(CrewOrder('Throw Smoke Grenade', 'The crew member throws a smoke grenade ' +
'out of an open hatch, creating one smoke factor in the player hex. No effect if ' +
'no hatch or hatch is shut.',
True, ['Commander', 'Loader']))
CREW_ORDERS.append(CrewOrder('Fire AA MG', 'Fire the .50 cal MG mounted on the top of the ' +
'tank turret. Crew member must have an open hatch, and if Loader it must be a split ' +
'hatch rather than an oval one. The crew member is much more vulnerable to being ' +
'wounded while on this order, since they must venture outside of the tank.',
True, ['Commander', 'Loader']))
CREW_ORDERS.append(CrewOrder('Repair AA MG', 'Attempt to repair a malfunctioning ' +
'AA machine gun. Crew member must have an open hatch. and if Loader it must be a ' +
'split hatch rather than an oval one. The crew member is much ' +
'more vulnerable to being wounded while on this order, since they must venture ' +
'outside of the tank.', False, ['Commander', 'Loader']))
# Bail out order available to all, only activated if one or more crew is incapacitated or worse
CREW_ORDERS.append(CrewOrder('Abandon Tank', 'Order all crewmen to bail out of the tank, ' +
'risking injury but heading back to friendly lines. Only one crewman needs to ' +
'have this order to bail out all crewmen.', False, ['Commander', 'Gunner',
'Loader', 'Driver', 'Asst. Driver']))
# list of possible random tank names for player's tank
TANK_NAMES = [
'Fury', 'Vengeance', 'Cobra King', 'Hannibal', 'Thunderbolt', 'Blood & Guts',
'Colorado', 'Condor', 'Apache', 'Ironside', 'Lucky Legs', 'Cairo',
'Colbert', 'Hurricane', 'Hellbound', 'Lucky Lady', 'ALF', 'Barnbuster',
'Caribou', 'Flare Path', 'Steadfast', 'Maiden Castle', 'Little John',
'Goldcrest', 'Folkestone', 'Predator',
'Anapola', 'Arsenic', 'Astoria', 'Athena', 'Avenger', 'Bastard Bill',
'Battling Annie', 'Bed Bug', 'Beelzebub', 'Beowulf', 'Betty',
'The Black Orchid', 'Block Buster', 'Bomb', 'Boomerang', 'Bright Eyes',
'Buffalo', 'Buck Private', 'China Gal', 'Clodhopper', 'Comet', 'Corsair',
'Cougar', 'Davy Jones', 'Draftee', 'Eternity', 'The Flying Scot', 'Hot Box',
'Hot Lips', 'Hot Pants', 'Hyena', "Jeanne D'Arc", 'King Kong', 'Lady Liberty',
'Murder Inc.', 'Nightmare', 'Old Faithful', "Pistol Packin' Mama",
'Rachel', 'Shaman', 'Snafu', 'The Stag', 'Stampede', 'Squirrel', 'War Bride'
]
# list of first names for crewmen
FIRST_NAMES = [
'Gregory', 'Shane', 'Lee', 'Andre', 'Mario', 'Louis', 'Stephen', 'Kenneth',
'Angelo', 'Oliver', 'Edward', 'Joshua', 'Ronald', 'Victor', 'Eli', 'Mario',
'Dallas', 'Arthur', 'Anderson', 'Dylan', 'John', 'Quentin', 'Alexander',
'Timothy', 'Wesley', 'Spencer', 'Leonardo', 'Edgar', 'Bob', 'Chewy',
'Frank', 'Dmitry', 'Jens', 'Conrad', 'Eric',
'Robert', 'James', 'William', 'Charles', 'George', 'Joseph', 'Richard',
'Donald', 'Thomas', 'Frank', 'Harold', 'Paul', 'Raymond', 'Walter', 'Jack',
'Henry', 'Kenneth', 'Albert', 'David', 'Harry', 'Eugene', 'Ralph', 'Howard',
'Carl', 'Willie', 'Louis', 'Clarence', 'Earl', 'Roy', 'Fred', 'Joe', 'Francis',
'Lawrence', 'Herbert', 'Leonard', 'Ernest', 'Alfred', 'Anthony', 'Stanley',
'Norman', 'Gerald', 'Daniel', 'Samuel', 'Bernard', 'Billy', 'Melvin', 'Martin',
'Warren', 'Michael', 'Leroy', 'Russell', 'Leo', 'Andrew', 'Edwin', 'Elmer',
'Peter', 'Floyd', 'Lloyd', 'Ray', 'Fredrick', 'Theodore', 'Clifford', 'Vernon',
'Herman', 'Clyde', 'Chester', 'Philip', 'Alvin', 'Lester', 'Wayne', 'Vincent',
'Gordon', 'Leon', 'Lewis', 'Charlie', 'Glenn', 'Calvin', 'Martin', 'Milton',
'Jesse', 'Dale', 'Cecil', 'Bill', 'Harvey', 'Roger', 'Victor', 'Benjamin',
'Wallace', 'Sam', 'Allen', 'Arnold', 'Willard', 'Gilbert', 'Edgar', 'Oscar'
]
# list of last names for crewmen
LAST_NAMES = [
'Abraham', 'Adler', 'Allen', 'Ankins', 'Applegate', 'Avery',
'Bacon', 'Baker', 'Barnham', 'Belanger', 'Bentz', 'Bessler', 'Best', 'Blakely',
'Bleeker', 'Bouche', 'Brant', 'Brawley', 'Bretz', 'Brock', 'Brockman',
'Bruce', 'Buchman', 'Burnett', 'Burns', 'Butterfield',
'Caffey', 'Christopher', 'Cleary', 'Codere', 'Collins', 'Coutu', 'Cowell',
'Cowman', 'Cox', 'Craig', 'Crankovitch', 'Cuthburt', 'Cuttling',
'Darwin', 'Davis', 'Delarosa', 'Douglass', 'Dorman',
'Eakley', 'Eddie', 'Edwards', 'Elliott', 'Ellis', 'Elsner', 'English',
'Fanbrick', 'Farwell', 'Feigel', 'Felten', 'Fenske', 'Feigel',
'Fields', 'Fillman', 'Finley', 'Firske', 'Fournier', 'France', 'Franklin',
'Freeman', 'Furlong',
'Gallaway', 'Garvin', 'Germain', 'Gilchrist', 'Gillespie', 'Gohl', 'Goodwin',
'Gray', 'Greenwald', 'Greenwalt', 'Griffen', 'Griffith',
'Hahn', 'Halsted', 'Hammermeister', 'Hancock', 'Harmal', 'Hass', 'Hastings',
'Hayes', 'Heminger', 'Henchal', 'Hessen', 'Hilt', 'Hollister', 'Hollman',
'Howell', 'Hyde',
'Jordon',
'Kaiser', 'Kasper', 'Kegley', 'Kinney', 'Kleeman',
'Laird', 'Leach', 'Lehman', 'Lesatz', 'Levard', 'Lindh', 'Lynch',
'Madison', 'Manse', 'Matchinski', 'Mathews', 'Mauldin', 'McAlpine', 'McBurney',
'McCain', 'McCarney', 'McCown', 'McCutchen', 'McCutcheon', 'McDonald', 'McGraw',
'Medeiros', 'Merrick', 'Metic', 'Mondt', 'Morris', 'Moses',
'Navarro', 'Nickels', 'Normandeau', 'Norval',
"O'Connell", 'Olson', "O'Neal", 'Ozanich',
'Patterson', 'Patzer', 'Peppin', 'Petrovich', 'Petty', 'Perkins', 'Porter',
'Posch', 'Price',
'Rapin', 'Rapp', 'Raslo', 'Razner', 'Rifenberg', 'Riley', 'Ripley', 'Robertson',
'Rooney', 'Rosental', 'Rossini', 'Russell', 'Rychech',
'Sawyer', 'Schafer', 'Schmidt', 'Schroeder', 'Schwartz', 'Scott', 'Shattuck',
'Shaw', 'Simmons', 'Slack', 'Smith', 'Speltzer', 'Stern', 'Stewart', 'Stone',
'Strenburg', 'Strong', 'Swanson', 'Syveran',
'Tenker', 'Thomas', 'Traver', 'Vallier', 'Vann', 'Wagner', 'Walsted', 'Warner',
'Webber', 'Weir', 'Welch', 'Westin', 'White', 'Winters', 'Woods', 'Wolff'
]
import libtcodpy as libtcod # The Doryen Library
HIGHLIGHT = (libtcod.COLCTRL_1, libtcod.COLCTRL_STOP)
# menu bar
MENU_BAR1 = '%cESC%c:Menu | '%HIGHLIGHT
MENU_BAR2 = (
'%cF1/1%c:Help | '%HIGHLIGHT +
'%cF2/2%c:Tank Info | '%HIGHLIGHT +
'%cF3/3%c:Crew Info | '%HIGHLIGHT +
'%cF4/4%c:Settings | '%HIGHLIGHT +
'%cF5/5%c:Campaign Stats | '%HIGHLIGHT +
'%cF6/6%c:Screenshot | '%HIGHLIGHT +
'%cF7/7%c:Sound'%HIGHLIGHT
)
# select spot sector
SPOT_SECTOR_INFO = [
'[%cW/S/Up/Down%c] Select crew'%HIGHLIGHT,
'[%cA/D/Left/Right%c] Rotate selected spot sector'%HIGHLIGHT,
'[%cSpace/End%c] Proceed to Spotting Phase'%HIGHLIGHT
]
# instructions for orders phase
ORDERS_PHASE_INFO = [
'[%cW/S/Up/Down%c] select crewman'%HIGHLIGHT,
'[%cA/D/Left/Right%c] change order for selected crew'%HIGHLIGHT,
'Select [%cO%c]rder for selected crew from a menu'%HIGHLIGHT,
'[%cR%c] cycle through ammo types to use when Reloading the main gun'%HIGHLIGHT,
'[%cT%c] toggle use of the Ready Rack for reloading the main gun'%HIGHLIGHT,
'[%cH%c] toggle Hatch status for selected crew member'%HIGHLIGHT,
'[%cSpace/End%c] finish Orders and proceed to Crew Actions'%HIGHLIGHT
]
# instructions for selecting an order to issue
ORDER_INFO = [
'[%cW/S/Up/Down%c] Move order selection'%HIGHLIGHT,
'[%cO%c] Set the selected order'%HIGHLIGHT,
'[%cBackspace%c] Cancel and keep current order'%HIGHLIGHT
]
# instructions for pivoting tank
PIVOT_INFO = [
'[%cA/D/Left/Right%c] Pivot to new facing'%HIGHLIGHT,
'[%cEnter/End%c] Complete pivot'%HIGHLIGHT
]
# instructions for rotating turret
ROTATE_INFO = [
'[%cA/D/Left/Right%c] Rotate turret'%HIGHLIGHT,
'[%cEnter/End%c] Set turret facing and continue'%HIGHLIGHT
]
# instructions for firing main gun
FIRE_GUN_INFO = [
'[%cA/D/Left/Right%c] Rotate turret'%HIGHLIGHT,
'[%cTab%c] Next target'%HIGHLIGHT,
'[%cF%c] Toggle Area and Direct Fire'%HIGHLIGHT,
'[%cR%c] Change ammo type to use when reloading'%HIGHLIGHT,
'[%cT%c] Toggle use of Ready Rack for reloading'%HIGHLIGHT,
'[%cEnter%c] Fire main gun'%HIGHLIGHT,
'[%cSpace/End%c] Finish firing and proceed to resolve hits or to next phase'%HIGHLIGHT
]
# instructions for firing MGs
FIRE_MGS_INFO = [
'[%cA/D/Left/Right%c] Rotate turret (if co-ax can fire)'%HIGHLIGHT,
'[%cM%c] Cycle active MG'%HIGHLIGHT,
'[%cTab%c] Cycle between available targets'%HIGHLIGHT,
'[%cEnter%c] Fire an MG'%HIGHLIGHT,
'[%cSpace/End%c] Finish firing and proceed to next phase'%HIGHLIGHT
]
# Campaign - check adjacent area instructions
CHECK_AREA = [
'Check an Adjacent Area',
'',
'[%cTab%c] Cycle through adjacent areas (Shift to reverse)'%HIGHLIGHT,
'[%cEnter%c] Check selected area for enemy resistance level'%HIGHLIGHT,
'[%cBackspace%c] Cancel action'%HIGHLIGHT
]
# Campaign - move into an area
MOVE_AREA = [
'Move into an Adjacent Area',
'',
'[%cTab%c] Cycle through adjacent areas (Shift to reverse)'%HIGHLIGHT,
'[%cEnter%c] Move into area'%HIGHLIGHT,
'[%cBackspace%c] Cancel move'%HIGHLIGHT
]
# info on enemy infantry units, displayed when player right-clicks on a unit
UNIT_INFO = {
'Light Weapons Infantry': """\
A squad of seven to ten riflemen, one of whom likely has a machine gun. Can attack and
destroy friendly infantry. No threat to your tank, unless they attack and a crew member
has an open hatch, or if they are in close range and attack with a Panzerfaust AT weapon.
Only HE or Machine Gun attacks will damage them; AP hits will have no effect.""",
'MG Team': """\
A team of enemy infantry armed with a medium or heavy machine gun. Can attack and destroy
friendly infantry. No threat to your tank, unless they attack and a crew member has an
open hatch. Only HE or Machine Gun attacks will damage them.""",
'50L': """\
The PaK 38 Anti-Tank Gun was developed in 1938 and first used in 1941 against Russian tanks.
By 1944 it was relatively underpowered compared to the heaviest tank armour then in use,
but was still widely used in the defense of France and Germany.""",
'75L': """\
The PaK 40 Anti-Tank Gun was developed between 1939 and 1941 and was the most widely-used
german AT gun of the latter part of the war. Its 75mm gun is also mounted on tank
destroyers.""",
'88LL': """\
The PaK 43 Anti-Tank Gun is a 88mm gun developed in 1943 as an anti-aircraft gun, but was
also widely used in an anti-tank role. With a maximum range of over 8 miles, it has
enough punch and firepower to knock out virtually any Allied tank."""
}
##########################################################################################
# List of possible crew statements #
##########################################################################################
CREW_TALK_HEAVY_RES = [
'Might want to call in some support, Commander.',
'I guess we could go around.',
'Maybe we could go around?',
"Can't we find another route?",
"We're not going in there, are we?",
"This doesn't look too good.",
"I guess it's our job to take care of it.",
"If we don't deal with them, somebody else will have to.",
"He who runs away lives to fight another day.",
"We've seen worst. Then again, we've seen better...",
"Germans. Always, more Germans."
]
CREW_TALK_ARTY_STRIKE = [
'Thanks guys!',
"I love that sound. At least when it's far away.",
"Better outgoing than incoming!",
"I never thought I'd come to love the sound of artillery.",
"I hope these shells find 'em."
]
CREW_TALK_NO_ARTY_STRIKE = [
'What are they doing over there?',
'How are we supposed to capture territory without proper artillery support?',
"Looks like all the fun is going to be ours once again.",
"We could use some help over here.",
"All right. We still have a job to do!",
"Conserving ammunition? What about our lives?",
"Thanks for nothing guys..."
]
CREW_TALK_NO_RES = [
"It's quiet. Too quiet.",
'They must have repositioned.',
"Somebody must have told them we were coming.",
"Where are they hiding?",
"I thought we were going to see some action.",
"I guess they moved somewhere else."
]
CREW_TALK_THROWN_TRACK = [
"That's not good!",
"We're immobilized!",
"We need to repair that track ASAP!",
"We're sitting ducks.",
"Busted another track..."
]
CREW_TALK_ARMOUR_SAVED = [
'Whoa! That was close!',
'Incoming AT!',
"My head is ringing.",
"Saved by the tin box again.",
"IS THAT ALL YOU GOT?!?",
"Come on! You hit like my granny!"
]
CREW_TALK_SHOT_MISSED = [
'That was close. Too close.',
'We got lucky on that one.',
"Good thing they can't aim.",
"They won't be missing forever!",
"Our turn now.",
"Don't let them fire again!"
]
# List of hometowns for USA
# based on http://www.census.gov/population/www/documentation/twps0027/tab17.txt
USA_HOMETOWNS = [
'New York, NY',
'Chicago, IL',
'Philadelphia, PA',
'Detroit, MI',
'Los Angeles, CA',
'Cleveland, OH',
'Baltimore, MD',
'St. Louis, MO',
'Boston, MA',
'Pittsburgh, PA',
'Washington, DC',
'San Francisco, CA',
'Milwaukee, WI',
'Buffalo, NY',
'New Orleans, LA',
'Minneapolis, MN',
'Cincinnati, OH',
'Newark, NJ',
'Kansas City, MO',
'Indianapolis, IN',
'Houston, TX',
'Seattle, WA',
'Rochester, NY',
'Denver, CO',
'Louisville, KY',
'Columbus, OH',
'Portland, OR',
'Atlanta, GA',
'Oakland, CA',
'Jersey City, NJ',
'Dallas, TX',
'Memphis, TN',
'St. Paul, MN',
'Toledo, OH',
'Birmingham, AL',
'San Antonio, TX',
'Providence, RI',
'Akron, OH',
'Omaha, NE',
'Dayton, OH',
'Syracuse, NY',
'Oklahoma City, OK',
'San Diego, CA',
'Worcester, MA',
'Richmond, VA',
'Fort Worth, TX',
'Jacksonville, FL',
'Miami, FL',
'Youngstown, OH',
'Nashville, TN',
'Hartford, CT',
'Grand Rapids, MI',
'Long Beach, CA',
'New Haven, CT',
'Des Moines, IA',
'Flint, MI',
'Salt Lake City, UT',
'Springfield, MA',
'Bridgeport, CT',
'Norfolk, VA',
'Yonkers, NY',
'Tulsa, OK',
'Scranton, PA',
'Paterson, NJ',
'Albany, NY',
'Chattanooga, TN',
'Trenton, NJ',
'Spokane, WA',
'Kansas City, KS',
'Fort Wayne, IN',
'Camden, NJ',
'Erie, PA',
'Fall River, MA',
'Wichita, KS',
'Wilmington, DE',
'Gary, IN',
'Knoxville, TN',
'Cambridge, MA',
'Reading, PA',
'New Bedford, MA',
'Elizabeth, NJ',
'Tacoma, WA',
'Canton, OH',
'Tampa, FL',
'Sacramento, CA',
'Peoria, IL',
'Somerville, MA',
'Lowell, MA',
'South Bend, IN',
'Duluth, MN',
'Charlotte, NC',
'Utica, NY',
'Waterbury, CT',
'Shreveport, LA',
'Lynn, MA',
'Evansville, IN',
'Allentown, PA',
'El Paso, TX',
'Savannah, GA',
'Little Rock, AR',
'Honolulu, HT' # i.e. Hawai`i Territory
]
# List of hometowns for Canada, duplicate entries represent high populations and chances
# or a crewman being from there
CAN_HOMETOWNS = [
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Toronto, ON',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Montreal, QC',
'Vancouver, BC',
'Vancouver, BC',
'Vancouver, BC',
'Vancouver, BC',
'Vancouver, BC',
'Vancouver, BC',
'Vancouver, BC',
'Calgary, AB',
'Calgary, AB',
'Calgary, AB',
'Calgary, AB',
'Calgary, AB',
'Edmonton, AB',
'Edmonton, AB',
'Edmonton, AB',
'Edmonton, AB',
'Edmonton, AB',
'Ottawa, ON',
'Ottawa, ON',
'Ottawa, ON',
'Ottawa, ON',
'Gatineau, QC',
'Gatineau, QC',
'Gatineau, QC',
'Quebec City, QC',
'Quebec City, QC',
'Quebec City, QC',
'Quebec City, QC',
'Quebec City, QC',
'Winnipeg, MB',
'Winnipeg, MB',
'Winnipeg, MB',
'Winnipeg, MB',
'Winnipeg, MB',
'Hamilton, ON',
'Hamilton, ON',
'Hamilton, ON',
'Hamilton, ON',
'Kitchener, ON',
'Kitchener, ON',
'Kitchener, ON',
'Kitchener, ON',
'London, ON',
'London, ON',
'London, ON',
'London, ON',
'Victoria, BC',
'Victoria, BC',
'Victoria, BC',
'Victoria, BC',
'Halifax, NS',
'Halifax, NS',
'Halifax, NS',
'Halifax, NS',
'Oshawa, ON',
'Oshawa, ON',
'Oshawa, ON',
'Oshawa, ON',
'Windsor, ON',
'Windsor, ON',
'Windsor, ON',
'Windsor, ON',
'Saskatoon, SK',
'Saskatoon, SK',
'Saskatoon, SK',
'Regina, SK',
'Regina, SK',
'Regina, SK',
'Barrie, ON',
'Barrie, ON',
'Barrie, ON',
'Abbotsford, BC',
'Abbotsford, BC',
'Kelowna, BC',
'Kelowna, BC',
'Sherbrooke, QC',
'Sherbrooke, QC',
'Trois-Rivieres, QC',
'Trois-Rivieres, QC',
'Guelph, ON',
'Guelph, ON',
'Kingston, ON',
'Kingston, ON',
'Moncton, NB',
'Moncton, NB',
'Sudbury, ON',
'Sudbury, ON',
'Chicoutimi-Jonquiere, QC',
'Chicoutimi-Jonquiere, QC',
'Thunder Bay, ON',
'Thunder Bay, ON',
'Kanata, ON',
'Kanata, ON',
'Saint John, NB',
'Saint John, NB',
'Brantford, ON',
'Red Deer, AB',
'Nanaimo, BC',
'Lethbridge, AB',
'White Rock, BC',
'Peterborough, ON',
'Sarnia, ON',
'Milton, ON',
'Kamloops, BC',
'Chateauguay, QC',
'Sault Ste. Marie, ON',
'Chilliwack, BC',
'Drummondville, QC',
'Saint-Jerome, QC',
'Medicine Hat, AB',
'Prince George, BC',
'Belleville, ON',
'Fredericton, NB',
'Fort McMurray, AB',
'Granby, QC',
'Grande Prairie, AB',
'North Bay, ON',
'Beloeil, QC',
'Cornwall, ON',
'Saint-Hyacinthe, QC',
'Shawinigan, QC',
'Brandon, MB',
'Vernon, BC',
'Chatham, ON',
'Joliette, QC',
'Charlottetown, PE',
'Airdrie, AB',
'Victoriaville, QC',
'St. Thomas, ON',
'Courtenay, BC',
'Georgetown, ON',
'Rimouski, QC',
'Woodstock, ON',
'Sorel-Tracy, QC',
'Penticton, BC',
'Prince Albert, SK',
'Campbell River, BC',
'Moose Jaw, SK',
'Cape Breton-Sydney, NS',
'Midland, ON',
'Leamington, ON',
'Stratford, ON',
'Orangeville, ON',
'Timmins, ON',
'Orillia, ON',
'Walnut Grove, BC',
'Spruce Grove, AB',
'Lloydminster, AB',
'Lloydminster, SK',
'Alma, QC',
'Bolton, ON',
'Saint-Georges, QC',
'Stouffville, ON',
'Okotoks, AB',
'Duncan, BC',
'Parksville, BC',
'Leduc, AB',
"Val-d'Or, QC",
'Rouyn-Noranda, QC',
'Buckingham, QC'
]
# Damage type class
# defines types of tank damage that can possibly be repaired by a crewman, or damage that
# can result from a failed repair attempt
class Damage:
def __init__(self, name, order, repair_score, break_score, break_result, auto_repair):
self.name = name # identifying name of the damage
self.order = order # order required to repair ('' if NA)
self.repair_score = repair_score # score required to repair (0 if NA)
self.break_score = break_score # minimum roll to break (0 if NA)
self.break_result = break_result # new damage type to apply if broken ('' if NA)
self.auto_repair = auto_repair # automatically repaired after an
# encounter unless break score rolled
DAMAGE_TYPES = []
DAMAGE_TYPES.append(Damage('Main Gun Malfunction', 'Repair Main Gun', 4, 11, 'Main Gun Broken', True))
DAMAGE_TYPES.append(Damage('Main Gun Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Gun Sight Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Engine Knocked Out', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Turret Traverse Malfunction', 'Repair Turret Traverse', 4, 0, 'Turret Traverse Broken', True))
DAMAGE_TYPES.append(Damage('Turret Traverse Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Radio Malfunction', 'Repair Radio', 6, 12, 'Radio Broken', True))
DAMAGE_TYPES.append(Damage('Radio Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Intercom Malfunction', 'Repair Intercom', 8, 12, 'Intercom Broken', True))
DAMAGE_TYPES.append(Damage('Intercom Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('AA MG Malfunction', 'Repair AA MG', 8, 12, 'AA MG Broken', True))
DAMAGE_TYPES.append(Damage('AA MG Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Co-ax MG Malfunction', 'Repair Co-ax MG', 8, 12, 'Co-ax MG Broken', True))
DAMAGE_TYPES.append(Damage('Co-ax MG Broken', '', 0, 0, '', False))
DAMAGE_TYPES.append(Damage('Bow MG Malfunction', 'Repair Bow MG', 8, 12, 'Bow MG Broken', True))
DAMAGE_TYPES.append(Damage('Bow MG Broken', '', 0, 0, '', False))
# return a pointer to a given damage type
def GetDamageType(name):
for d in DAMAGE_TYPES:
if d.name == name: return d
return None
# types of damage that allow us to choose to head back to HQ
ENDING_DAMAGES = ['Gun Sight Broken', 'Main Gun Broken', 'Turret Traverse Broken']
HELP_TEXT = [
('AP', """\
AP refers to an Armour-piercing gun shell. As the shell is designed to punch through armour,
it has a minimal explosive charge and thus will do no significant damage to infantry units,
including AT guns. Only Direct Fire mode can be used with this type of shell. Enemy tanks,
SPGs, and AT guns will always use AP fire against you and friendly armour.
"""),
('HVAP', """\
High velocity Armour-piercing gun shell. Produced for the 76mm guns on American tank
destroyers, they consist of a dense tungsten carbine core surrounded by an aluminium casing.
The shell was able to penetrate armour at much further ranges than the standard 76mm AP
shell. They were normally only issued to Tank Destroyers. Their use by M4 Sherman crews in
this and other simulations is not supported by historical evidence, but rather represents
a few shells 'appropriated' from supplies.
"""),
('APDS', """\
Armour-Piercing Discarding Sabot gun shell. A type of shell with a dense core surrounded by
pedal-shaped sabots that separate from the core in flight. Very effective against armour.
APDS rounds in British and Commonwealth forces were rare up to late 1944.
"""),
('HE', """\
HE refers to a High-explosive gun shell. These shells are designed for use against lightly
or unarmoured vehicles, gun teams, and other infantry. Fully armoured vehicles will normally
only be damaged by HE in the case of a Critical Hit. HE can be fired in either Direct or Area
fire mode. En route to your starting location, you will use a random number of HE shells
suppressing infantry attacks. You can also use HE as advancing fire when moving into an
enemy-held area.
"""),
('WP', """\
WP refers to a White Phosphorus smoke-producing shell. WP burns quickly producing a blanket of
smoke. They are harmful to anyone nearby, and thus are only used against enemy positions. WP
must be fired in Area Fire mode. A successful hit with WP produces 1 Smoke Factor in the target's
hex. Infantry units hit by a WP must pass a Pin test or be pinned.
"""),
('HCBI', """\
HCBI refers to a Hexachlorothane-Base Initiating smoke-producing shell. HCBI produces a great deal
of smoke, with the benefit of being safe to use near friendly forces. Only a limited number
of HCBI shells are available each day. HCBI must be fired in Area Fire mode. A successful hit
with HCBI produces 2 Smoke Factors in the target's hex.
"""),
('M4 Sherman', """\
A medium tank produced by the United States and in service from 1942 to 1955 in the American
armed forces. There were over a dozen variants of this tank produced, plus other vehicles that
were built on its chassis or hull. The original M4 was intended for infantry support and mobile
attack, and was vastly outclassed by most other medium and heavy German tanks in the later part
of the war.
"""),
('Hidden', """\
Hidden units are enemy units that you know are in the area, but to which you do not have a direct
line of sight. Hidden units cannot be targeted by your tank, but nor can they initiate attacks
against you. Units remain hidden until either they or you change their position; no spotting checks
can reveal them unless one of you moves.
"""),
('Unspotted', """\
Unspotted units are enemy units that have been reported by friendly observers but which have not yet
been spotted by the crew of your tank. Unspotted units can attack you and friendly units, but you
cannot attack them until they are spotted.
"""),
('Unidentified', """\
Unidentified units have been spotted by the crew of your tank, but you do not yet know what specific
type of tank, self-propelled gun, or AT gun they are until they are Identified. Unidentified units
attack and can be targeted as normal, but you do not know how powerful your enemy is until you
can successfully identify it.
"""),
('Call Artillery', """\
Call Artillery is an action used on an adjacent enemy-controlled area in the campaign day map. If
successful, an artillery strike is called in on the map area. The action takes 15 mins. of
time. The chance of success depends on your current artillery chance, which decreases by one