UPDATE: This is an error to do with importing files. It runs fine as a single file. I also have a two-file version that runs OK until it gets to the time.sleep() interval near the end.
…
I’m part way into Ex45. My code is fine syntax-wise, but for me the logic is the biggest problem. This is my first real programming language (I can do some stuff in R and MySQL).
I based my game very much on the Gothon one, in large part because I stuggle a bit with the logic. So, it’s not as original as some but I am learning something in the process.
Error is:
ex45_maps.py", line 4, in Map
‘intro’: Intro(),
NameError: name ‘Intro’ is not defined
‘intro’ is the equivalent of ‘central_corridor’. It is defined as a class like CentralCorridor. It is called by a_game.play
I have four files:
The base file with imports and code to run the game (ex45.py).
The engine
The map file
The scenes.
ex45.py:
from sys import exit
from random import randint
from textwrap import dedent
from ex45_engine import *
from ex45_maps import *
from ex45_scenes import *
a_map = Map('intro') # a_map is a class Map called 'intro'
a_game = Engine(a_map) # a_game is a class Engine that calls a_map
a_game.play() # from a_game get the play function
ex45_engine.py
class Engine(object):
def __init__(self, scene_map):
self.scene_map = scene_map
def play(self):
current_scene = self.scene_map.opening_scene()
last_scene = self.scene_map.next_scene('success')
while current_scene != last_scene:
next_scene_name = current_scene.enter()
current_scene = self.scene_map.next_scene(next_scene_name)
# be sure to print out the last scene
current_scene.enter()
ex45_maps.py
class Map(object):
scenes = {
'intro': Intro(),
'village': Village(),
'hunker_down': HunkerDown(),
'artillery_observation': ArtilleryObservation(),
'fire_control_one': FireControlOne(),
'fire_control_two': FireControlTwo(),
'observe_ffe': ObserveFFE(),
'failure': Failure(),
'success': Success(),
}
def __init__(self, start_scene):
self.start_scene = start_scene
def next_scene(self, scene_name):
val = Map.scenes.get(scene_name)
return val
def opening_scene(self):
return self.next_scene(self.start_scene)
ex45_scenes.py
class Scene(object):
def enter(self):
print("This scene doesn't get called, at least not to print.")
print("Subclass it and implement enter().")
exit(1)
class Failure(Scene):
def enter(self):
print("""
Killed, wounded, taken captive or still out there?
We don't know, but Sergeant Lyev's mission was a brave one
and his name will be spoken of fondly by comrades as we march westwards.
""")
exit()
class Success(Scene):
def enter(self):
print("""
You and you men made a vital contribution to driving the fascists
from Smerovo! Onwards! For the motherland! To Berlin!
""")
exit()
class Intro(Scene):
def enter(self):
print("""
On the Ukrainian front in April 1944, several companies of fascist forces (about 500 men)
occupy the village of Smerovo. Clear ground lies between the woods in which we have massed
a tank battalion (39 T-34 tanks) plus infantry and the edges of the village, 2km away
up a gentle slope. Captured fascist soldiers have told us they are well dug in with
anti-tank weapons and machine guns plus tanks and infantry in reserve in the village,
where the command post is set up. They expect an attack and are well-prepared, with
artillery reference points already set on the approaches to the village. The river Glavny
lies to the south (our left) of the village so approach from that side is not possible.
To all other sides of the village there are no natural obstacles for many kilometres.
Immediately in front of the village as we look at it are thickets that give good cover.
Behind them, rising higher, are walls and banks where the fascist defences are dug in.
We have two companies of artillery at our disposal set up several km to our rear.
Our commanding officer has formulated a plan that requires a feint attack on the
village's defences in front of our positions while sending the bulk of our forces
around to attack their left flank. To do that depends on a reconnaissance group finding
the location of the command centre and calling in artillery to destroy communications
in the fascist rear. A reconnaissance squad of four men led by Sergeant Lyev will set off
after dark. Shall we brief Sgt Lyev?
.
.
.
.
.
.
Sgt Lyev, you must decide on the approach to take to the village.
There are thickets that give cover up to the walls of the village if you approach
it directly, but you will be in the open for some time and will have to find a gap
in the defences when you get there. You could also travel along the river bank.
It is muddy and may be visible to enemy forces on the other side of the river but
it is hidden by its steep banks from the village's defenders. Whatever you choose,
your squad will depart at 9pm under cover of darkness.
""")
action = input("direct or riverbank?> ")
if action == "direct":
print("""
You walk, run and crawl across no-man's land for 1.5km before a German MG opens up
and pins you down, badly wounding one of your men. Luckily, the fire has been seen
and heard from our lines. A mortar barrage stops the machine gun, but the Germans
are twitchy. Shots ring out for some time. You stay still for a couple of hours before things
become quiet again. Finally, you make it through the undergrowth and the rest of the
way to the village walls and find a gap between dug-in fascist troops.
""")
return 'village'
elif action == "riverbank":
print("""
Your team makes it 1km along the oozing, thick mud of the river bank
before being spotted by German soldiers on the other bank. They send up a flare
and open fire. You and one of your men are badly wounded and are dragged back to
your lines by the other men.
""")
return 'failure'
else:
print("Speak up, man!")
return 'intro'
class Village(Scene):
def enter(self):
print("""
You heard the voices of the Germans dug in to the right of you as you crept past
the outer defences. They were still tense and excited from the earlier firing.
Now all seems quiet in front of you as you peer into the gloom of the village.
But you must now choose which direction to go. From yard to yard among the houses
on the road towards the village centre, or left and through the back lanes?
""")
action = input("road or lanes?> ")
if action == "road":
print("""
Going along the main road, all is quiet as you head towards the village centre.
You and your men move in and out between the wooden lap-built houses as you proceed.
Then, an eruption of squawking as Avimov stumbles against a chicken shed. You soon hear
German voices, agitated, pulling clothes on and readying weapons. You fire first,
but are soon spotted. A firefight ensues, with two of your men killed almost straight away.
You fight to the last bullet.
""")
return 'failure'
elif action == "lanes":
print("""
You move left, and lead your men towards the edges of the village, taking a round-about
route to cut back in further on. Taking each step carefully, each man tries to move as
silently as possible, to not breathe too loudly. Going behind the houses and nearer the
river you come to a wider road coming from the left. Peering right, about 75m away you
see officers' vehicles and some activity around a larger building in the village centre.
You note the coordinates of the command post and turn away towards the river, where you
will find a spot to dig in and radio them back to your regiment. You aim to be within
sight of the command post so you can guide artillery fire the next day. You are under
strict orders not to use the radio again until the morning.
""")
return 'hunker_down'
class HunkerDown(Scene):
def enter(self):
print(""" .
Your squad succeeded in finding the fascist command post in Smerovo. You will surely
be recommended for an award. The first artillery barrage is scheduled for 3am.
This will target the village defences in front of the woods, lay down smoke to the
right, and attempt to knock out the command post in the village centre. At the same
time a third of our tanks plus infantry will head towards the village on a direct route.
Meanwhile, the main force will proceed under cover of smoke to the right of the village
where it will turn in to take the objective from the unprotected flank. The success of
that mission depends on you guiding the artillery to destroy the centre of the enemy's
command and communications in the village so that its reserve forces are not sent in
time to defend from the real attack.
""")
return 'artillery_observation'
class ArtilleryObservation(Scene):
def enter(self):
print("""
Time to wake up!
It is 0245. After dozing uncomfortably in a hedge by a wall in the cold dampness of
the April night you rouse your men into life. Soon the guns will start, but nothing stirs
for now. You stay hidden, waiting. At 0300 precisely all hell opens up to
the east. It's the first sheaf of shells aimed at the village defences. Then, a
louder whistling, seemingly heading straight for you, and a single shell slams into the
farmland somewhere west of the command post - to its left. It is the first range-finding
shell. You wind the radio into life and make contact with the artillery commander to give
him targeting corrections.
""")
return 'fire_control_one'
class FireControlOne(Scene):
def enter(self):
print("""
You want the next shell to fall shorter. Do you tell him east 25m, 50m or 75m?
""")
action = input("25, 50 or 75?> ")
if action == "25":
print("""
Within a minute you hear another shell whistling in. The ground shakes but
still it has over-shot the command post.
""")
return 'fire_control_one'
elif action == "50":
print("""
Within a minute you hear another shell whistling in. The ground shakes but
still it has over-shot the command post.
""")
return 'fire_control_one'
elif action == "75":
print("""
Within a minute you hear another shell whistling in. The ground shakes and a
plume of dirt rises high in the air. But it looks quite far beyond the command
post building. You get the commander on the radio again to correct fire to
the south, towards the command post, but also towards your hiding place.
""")
return 'fire_control_two'
class FireControlTwo(Scene):
def enter(self):
print("""
You want the next shell to fall shorter. Do you tell him north 25m, 50m or 75m?
""")
action = input("25, 50 or 75?> ")
if action == "25":
print("""
Within 40 seconds another shell comes in. This time again it hits way off
to the other side of the command post.
""")
return 'fire_control_two'
elif action == "50":
print("""
Uurraaah! The single range-finding shell lands right next to the command post
sending a motorcycle and sidecar flying through the air. You get back on the
radio as quickly as possible to ask for a full sheaf of fire. Hunker down and
observe the fire.
""")
return 'observe_ffe'
elif action == "75":
print("""
Seconds later. Your head feels like it is being hit with a hammer. You can hardly
see and you can't hear. You look around to see your men covered in dirt and all
of you scattered several metres from where you were hidden. You can see ripped
cloth and the red of exposed flesh on one man. The shell made its impact 30m
in front of you; too close. You feel a sense of panic as you look for the radio set.
""")
return 'failure'
class ObserveFFE(Scene):
def enter(self):
print("""
You watch as the shells come raining in. Soon the old building is destroyed, a
pile of burning wooden beams, the remains of vehicles blazing nearby. You feel pity
for any poor devils that got caught in that.
""")
action = input("Press x to see damage report> " )
damage = random.randint(0, 9)
if damage <= 4:
print("""
A direct hit with the first sheaf! That artillery commander is good. You tell him
you'll drink vodka with him when you see him! 10 minutes later our tanks arrive
at the village centre and head off to the right. Success!
""")
return 'success'
elif damage > 4:
print("""
A direct hit. You wait. And you wait some more. After a while you hear the sounds of
fighting to the north. Then you see aircraft diving in too – they look German.
Things don't look good. Something must have gone wrong and the attack has failed.
You'll need to get back to our lines, but probably best to wait until dark.
It's going to be a long time until you are safe again.
""")
return 'failure'