Morrowing

Die letzte Morrowing Episode (*schnief*) führt einen neuen Charakter ein, der mit dem Spieler spricht und abhängig vom Gesprächsverlauf unterschiedlich reagiert: er kann fortfliegen (wörtlich!) oder mit dem Spieler kämpfen. Ich werde mich nicht auf den Code für den Dialog konzentrieren; die Funktionsweise des Dialogsystems ist in AUM 49 ausführlich erklärt.
action enemy2 // attached to the berzerka.mdl model
{
var enemy_speed;
var trace_temp;
var right_fist; // will store the coordinates of a vertex on the right fist
var left_fist; // will store the coordinates of a vertex on the left fist
var lines_on = 0; // makes sure that the lines aren't repeated several times
my.health = 200; // this enemy has got 200 health points
my.passable = on; // and is passable
my.transparent = on; // and invisible at first
my.alpha = 0;
while (mace == null) {wait (1);} // wait until the player picks up and uses
the
mace
my.passable = off;
while (my.alpha < 95) // make the enemy fade in nicely
{
my.alpha += 5 * time;
wait (1);
}
snd_play (beast2_wav, 100, 0); // play a frightening sound
my.alpha = 100; // the enemy is supposed to be opaque here
my.transparent = off;
Die ersten Zeilen deklarieren einige lokale Variablen; die Wichtigsten sind right_fist und left_fist, die für den unbewaffneten Kampf benutzt werden. Das Monster hat 200 Punkte Gesundheit und ist zu Beginn unsichtbar und passierbar; es wartet bis der Spieler den Streitkolben aufhebt und anlegt (mace != null) und wird dann unpassierbar und sichtbar, indem der Alpha Wert in einer Schleife vergrößert wird. Wenn das Monster nicht mehr transparent ist, gibt es ein Geräusch von sich (beast2.wav).
while (my.health > 0) // as long as the enemy is alive
{
if ((vec_dist (my.x, player.x) < 2000) && (player.health > 0))
// if the player is alive and comes closer than 2000 quants to the enemy
{
lines_on += 1; // increment lines_on
if (lines_on == 1) // don's repeat these lines (say them
only once)
{
// text processing starts here
dialog_number = 7; // player's line will be processed
by the "if
(dialog_number == 7)" branch inside the panelstexts.wdl file
str_cpy(temp_str, line16_str); // "Hey!
What are you doing in my tent?"
process_their_strings();
wait (1);
theysay_txt.string = their_lines_str;
theysay_txt.visible = on;
wait (3);
stop_player = 1; // stop the player for now
sleep (2); // wait for 2 seconds
isay1_txt.string = line17_str; // "Me? It
must be some sort of a misunderstanding, sir!"
isay2_txt.string = line18_str; // "Stop
bugging me! I'm only trying to get some equipment!"
isay1_txt.visible = on; // give the player the
possibility to answer (this will bring up the my_pan panel as well)
isay2_txt.visible = on;
show_pointer = 1; // display the mouse pointer
while (their_pan.visible == on) {wait (1);} //
stop the enemy until this panel disappears
stop_player = 0; // allow the player to move
again
// text processing ends here
}
Der Feind greift an, solange seine Gesundheit positiv ist; wenn der Spieler lebt und näher ist als 2000 Quants, erhöhen wir lines_on und falls lines_on gleich 1 ist (das Gespräch soll nur einmal stattfinden) wird der Text verarbeitet: dialog_number wird auf 7 gesetzt (die Dialoge aus AUM 49 endeten mit dialog_number = 6), wir stellen die korrekten Textzeilen für das Monster und den Spieler ein, zeigen sie an und warten, bis their_pan unsichtbar ist; dies geschieht, wenn der Dialog vom Bildschirm verschwindet. Die letzte Codezeile erlaubt dem Spieler die Bewegung, aber nur wenn die Texte fort sind.
if (dialog_number == 8) // the player is a chicken?
then fly away
{
snd_play(startup_wav, 60, 0); // "initiating
the startup sequence
sleep (2.5); // wait until the previous sound
has stopped
snd_play(launched_wav, 100, 0); // play the launching
sound
while (my.z < 50000) // start flying
{
my.z += 300 * time; // increase enemy's
z
my.pan += 50 * time; // and rotate it while
it is moving upwards
my.scale_x -= 0.15 * time; // decrease
the size of the monster (create the illusion that it shrinks faster)
my.scale_y = my.scale_x;
my.scale_z = my.scale_x;
wait (1);
}
break; // get out of here if the monster has disappeared
}
Falls dialog_number == 8 ist dann heißt das, dass der Spieler zu feige war (und dies hat sich in panelstexts.wdl entschieden) und das Monster wird ein (lustiges?) “Initiating Startup Sequence”-Geräusch von sich geben, warten bis es verklungen ist und dann launched.wav abspielen. Der Feind wird sich dann mit hoher Geschwindigkeit nach oben bewegen und sich dabei um die eigene Achse drehen. Zugleich skalieren wir das Monster in allen Richtungen nach unten, um die Illusion zu erzeugen, dass es sich mit enormer Geschwindigkeit vom Spieler fortbewegt (schließlich ist die Levelgröße begrenzt). Die letzten Codezeilen beenden die Schleife.
enemy_speed.x = 30 * time; // "walk" speed
ent_move(enemy_speed, nullvector);
ent_cycle("walk", my.skill19); // play walk frames animation
my.skill19 += 7 * time; // "walk" animation speed
my.skill19 %= 100; // loop the animation
if (vec_dist (my.x, player.x) < 400) // if the player comes
closer than 400 quants attack him
{
my.skill20 = 0; // reset the "attack" frames
snd_play (beast2_wav, 30, 0);
while ((my.skill20 < 100) && (player.health > 0))
{
vec_for_vertex (right_fist, my, 3); //
get the position of the right fist (3rd vertex in Med)
vec_for_vertex (left_fist, my, 138); //
get the position of the left fist (138th vertex in Med)
if ((vec_dist (right_fist.x, player.x) < 100)
|| (vec_dist (left_fist.x, player.x) < 100))
// hit the player?
{
if (vec_dist(right_fist.x,
player.x) < 200)
// the player was hit with the right fist?
{
player.pan -= 1;
// rotate him in that direction
}
if (vec_dist(left_fist.x, player.x) < 200)
// the player was hit with the right fist?
{
player.pan += 1;
// rotate him in the opposite direction
}
Der obige Code wird ausgeführt, wenn der Spieler sich für den Kampf entschieden hat; das Monster bewegt sich und spielt dabei die "walk" Animation ab. Falls der Spieler näher als 400 Quants ist, ertönt erneut das beast2.wav Geräusch und wenn der Spieler lebt, wird right_fist und left_fist auf die Koordinaten des 3. Und 138. Vertexes gesetzt. Ich hätte die gleiche Trace-Methode für den Kampf verwenden können wie vorher, aber ich dachte, dass eine neue Art interessant sein könnte, die speziell für Nahkämpfe gut funktioniert. Ich ermittele die beiden Position der Fäuste und falls die Distanz zwischen beiden und dem Origin des Spielers kleiner ist als 100 Quants (experimenteller Wert), nimmt der Spieler Schaden. Wenn der Spieler getroffen wird, drehe ich ihn ein wenig; das macht das Töten des Monsters etwas schwerer, aber trotzdem sollte es machbar sein, den schwerfälligen Feind zu erledigen.
// the player loses health
more easily if its armor is damaged (or off) and if its shield isn't used
player.health -= 4 * (2 + armor_damaged
- shield_on) * time;
player.strength -= 0.7 * time;
if (player.strength < 0)
{
armor_damaged =
1; // remove the body armor and make the player more sensitive to hits
}
ent_playsound (my, sword_wav,
50); // sword sound
}
ent_cycle("attack", my.skill20);
// play attack frames animation
my.skill20 += 5 * time; // "attack" animation
speed
wait (1);
}
sleep (0.1); // slows down the enemy and reduces
the number of traces per second
}
while (their_pan.visible == on) {wait (1);} // stop the enemy
until this panel disappears
}
Hier wurde der Spieler getroffen; seine Gesundheit wird verringert, je nach Zustand seiner Rüsung und des Schuldes und dann verwenden wir das alte sword.wav Geräusch vom Skelett. Das Monster wird mit seinen "Attack” Frames animiert mit der Geschwindigkeit 5*time, die zugleich die Angriffsrate festlegt. Die letzte Zeile stoppt das Monster, wenn ein anderer Dialog auf dem Bildschirm erscheint.
else // the player is farther than 2000 quants away
{
enemy_speed.x = 40 * time;
my.skill47 += ent_move(enemy_speed, nullvector);
if (my.skill47 > 400) // play with 400
{
snd_play(beastwalk_wav, 100, 0);
if (random(1) > 0.5)
{
camera.roll = 2;
}
else
{
camera.roll = -2;
}
my.skill47 = 0;
}
ent_cycle("run", my.skill21); // play stand frames animation
my.skill21 += 5 * time; // "stand" animation speed
my.skill21 %= 100; // loop the animation
}
Wenn der Spieler weiter als 2000 Quants entfernt ist, beginnt das Monster mit einem grauenhaften beastwalk.wav Geräusch auf ihn zuzurennen und sorgt dafür, dass die Kamera durch Änderung des Roll-Winkels wackelt. Die letzten 3 Zeilen kümmern sich um die “Run” Animation.
vec_set(temp, player.x); // rotate the enemy towards the player
all the time
vec_sub(temp, my.x);
vec_to_angle(my.pan, temp);
my.tilt = 0; // set a proper "tilt" angle
wait (1);
camera.roll = 0;
enemy_speed.y = 0;
vec_set (trace_temp, my.x);
trace_temp.z -= 10000;
trace_mode = ignore_me + ignore_passable + use_box;
enemy_speed.z = -trace (my.x, trace_temp.x) - 1; // place enemy's
feet on the ground
move_mode = ignore_passable + ignore_passents;
}
while (my.skill22 < 80) // the enemy is dead here
{
ent_cycle("death", my.skill22); // play death frames
animation
my.skill22 += 1 * time; // "death" animation speed
wait (1);
}
my.passable = on; // the corpse can't be hit by the sword from now
on
player.experience += 15; // increase player's experience by 15
}
Der letzte Teil Code stellt sicher, dass das Monster den Spieler die ganze Zeit ansieht, 1 Frame wartet (das wird aufgrund der übergeordneten Schleife benötigt) und setzt dann die Bewegungsgeschwindigkeit in y und z-Richtung (Gravitation). Die letzte Schleife ist für die “Death” Animation zuständig und macht das Monster dann passierbar, während der Spieler 15 Erfahrungspunkte erhält.
Dieser Artikel beendet die Morrowing Serie. Sie können jetzt weitermachen, das erste Skelett treffen und (hoffentlich) bezwingen und den Eingang erreichen. Ich habe die Feinde sehr schwach gemacht, aber Sie können (und sollten) deren Gesundheit erhöhen, um dem Spieler eine größere Herausforderung zu bieten.
Morrowing
war eine kürzere Serie, aber ich plante ohnehin, den Inhalt
und das Layout von AUM zu ändern und Ausgabe 50 klang nach einem schönen
runden Wert. Wir sehen uns in AUM 51 mit neuem Layout, neuen Thema und – halten
Sie sich fest – einer Suchfunktion für das Magazin.