Iliran

Kommentare anzeigen Worklog abonnieren
Gehe zu Seite 1, 2  Weiter

Worklogs Iliran

Türen, Inhalt und Erweiterungen bei den NPCs

Freitag, 28. Dezember 2012 von Lador
Sehr lange ist der letzte Eintrag mal wieder her. Und weil nun Weihnachten ist und die Welt noch steht, wollte ich noch meine Fortschritte des letzten Jahres vorstellen.


Vor geraumer Zeit, nachdem ich die Indoor-Maps für das Dorf Bringht nahezu fertiggestellt hatte, hab ich den Übergang von Outdoor- zu Indoor-Map verbessert bzw. erweitert. Es gibt Häusereingänge, bei denen man eine Tür öffnen muss, und welche, bei denen man einfach darauf loslaufen kann. Neu sind auch seitliche sowie nördliche Eingänge; bis jetzt waren lediglich südliche möglich. Türen, die man mit Enter öffnen muss, existieren jedoch nur auf der südlichen Häuserseite. Diese werden dann durch eine schicke Animation überzeichnet. Außerdem wird jeder Map-Wechsel durch einen gemütlichen schwarzen Alpha-Effekt begleitet, sodass man nicht mehr aprupt von einer Map in die nächste springt. Die Hauptmap (also die Outdoor-Welt) wird zudem von Anfang an in einem eigenen Array IliranMap[] gespeichert, sie wird also nicht bei jedem Wechsel dorthin neu geladen, was einiges an Ladezeit und Rechenleistung spart.
Inzwischen gibt es auch Eingänge, die nicht nur ein Tile breit und ein Tile hoch sind, sondern auch große Tore, die z.B. 3x2 Tiles groß sind. Dementsprechend gibt es natürlich auch verschiedene Türen mit eigenen Animationen.


Besonders bei den NPCs hat sich vieles getan. So sind nun etwa Gesprächs- bzw. Ereigniswechsel bei Nichtspielern ohne Zutun von Quests möglich (man erinnere sich vielleicht nocht an den Eintrag über den Quest-Editor vor vielen Jahren). Das hat zur Folge, dass diese nun (meistens) nicht mehr andauernd den selben Satz sagen müssen, falls sie nicht in eine Quest involviert sind, und demzufolge natürlich auch mehr Arbeit für mich bei der Erstellung der Gespräche. ^^
Dazu wird einfach am Ende des Gesprächs in die Textdatei "[Ereignis=xy]" geschrieben, wobei xy das Sprung-Ereignis ist, welches mittels Byte("xy") zu einem Byte umgewandelt wird. Einstellige Zahlen werden dadurch ausgedrückt, das x = " " (ein Leerzeichen) ist. Mehr als zwei Stellen werden wohl nicht nötig sein.
Als kleine Ergänzung zu den Gesprächen machen NPCs nun nach den Zeichen Punkt, Komma, Ausrufe-, Fragezeichen und Gedankenstrich eine kurze Pause. Bei Satzzeichen (am Ende eines Satzes) ist diese etwas länger. Das wird einfach mittels Mid() und Millisecs() realisiert. NPCs, die sich nicht zufällig in der Welt bewegen, sondern an derselben Stelle stehen bleiben, drehen sich nach einem Gespräch auch wieder in ihre ursprüngliche Richtung zurück. Dazu habe ich ein

Code: [AUSKLAPPEN]
Field OrSFrame:Byte


(für: OriginalStartFrame) beim NPC-Type eingefügt, das - im Gegensatz zum "normalen" SFrame:Byte und analog zu vielen anderen Or-Variablen - im gesamten Programm mehr als Backup für die ursprüngliche Information genutzt wird, und nur selten bis gar nicht verändert wird.

Die wohl größte und umfangreichste Neuerung bezüglich der NPCs ist, dass diese nach getaner Arbeit in ihr Haus zum Schlafen gehen und die Türe hinter sich verschließen. Sie haben also so etwas wie ihren eigenen kleinen Tagesablauf. Durch diesen Algorithmus ist es mit einer kleinen Abwandlung auch möglich, dass sie zu bestimmten Uhrzeiten auch einfach in der Welt umherwandern. Manchen NPCs kann man sogar beim Schlafen zusehen, nämlich wenn sie in einer Herberge schlafen, die ja auch für den Spieler zugänglich ist.
Dazu habe ich den NPC-Type um folgende Felder ergänzt:

Code: [AUSKLAPPEN]
Field Pathx:Short
Field Pathy:Short
Field Uhrzeit1:Byte
Field Uhrzeit2:Byte
Field Hausx:Short
Field Hausy:Short
Field HausMap:String
Field InHausx:Byte
Field InHausy:Byte
Field LastSFrame:Byte
Field WegList:TList = New TList
Field OrWegList:TList = New TList
Field NachHause:Byte


Pathx und Pathy sind die angestrebte Position, die der NPC haben soll, damit er nach Hause laufen kann, also die Startposition für den Weg nach Hause. Relevant ist dies vor allem für Charaktere, welche sich sonst zufällig bewegen, da sie ja stets abweichende x- und y-Werte haben. Zur Vereinfachung kann man beide Variablen in der externen Datei mit 0 deklarieren und das Programm setzt sie dann auf die Startwerte der NPC-Startposition, welche sie zu Beginn des Programms innehaben.
Die beiden Uhrzeit-Variablen stehen für die Stundenzahl des Schlafengehens (Uhrzeit1) bzw. des Aufstehens (Uhrzeit2). Ist die "Weltzeit" größer oder gleich Uhrzeit1, so geht der NPC schlafen, analog bei Uhrzeit2. Hierbei ist zu beachten, dass Uhrzeit1 immer größer Uhrzeit2 ist, weil die Charaktere (im Normalfall) etwa in der ersten Tageshälfte (von 0-12 Uhr) aufstehen und in der zweiten Tageshälfte (13-24 Uhr) schlafen gehen. Außerdem können die NPCs auch erst dann aufstehen, wenn sie zuvor schlafen gegangen sind; letzteres hat also die höhere Priorität und wird zuerst ausgeführt, doch dazu später mehr.
Hausx und Hausy sind die Position von dem Eingang des Hauses bzw. ein Tile davor, wenn es sich um eine Tür handelt. Demzufolge wird dies die Endposition sein, die der Nichtspieler erreicht hat, wenn er den Weg abgelaufen ist. Es sei denn natürlich, er ist einer der bereits genannten "Wanderer", welche in der Welt umherlaufen. Dann ist der Wert beider Variablen gleich 0, weil sie ja kein Haus erreichen wollen.
Befindet sich der NPC auf der Position Hausx/Hausy, dann dreht er sich in Richtung von LastSFrame, sein MapName wird auf HausMap gesetzt und seine Position auf InHausx/InHausy. Letzteres ist aber nur entscheidend für Figuren, denen man beim Schlafen zusehen kann. Diejenigen, die in ihr Haus gehen und dann die Tür absperren, verschwinden einfach von der Bildfläche. Dann wird die Liste aller Verbindungen (s. Worklog Häuser-Editor) nach der entsprechenden durchforstet und deren Field Schloss:Byte auf 102 gesetzt (wenn es vorher 0 war), was einem Schloss entspricht, das man nur mit einem Schlüssel öffnen kann (s. Worklog Schlösserknacken). Wenn der NPC wieder aufsteht, wird das Haus auch nur dann geöffnet (also auf 0 gesetzt), wenn das Schloss gleich 102 ist, denn sonst würde der NPC ja ein vorhandenes Schloss versehentlich selbst öffnen.
Zu guter Letzt speichert WegList die Richtungen, in die ein NPC gehen muss, um zu seinem Haus zu gelangen. Geht er wieder zur Arbeit, werden die Richtungen einfach umgedreht; es ist also keine zusätzliche Liste dafür nötig. Übrigens ist NachHause die Variable, die den derzeitigen Status des Nachhause-Gehens bzw. Aufstehens speichert und OrWegList ist - natürlich - die originale Liste, weil der WegList bei jedem Schritt nach Hause das erste bzw. bei jedem Schritt zur Arbeit das letzte Element entfernt wird und diese daraufhin leer ist.


So, das war mal wieder ein sehr langer Worklogeintrag, der längst überfällig gewesen ist. ^^ Zum Schluss noch ein neuer Screenshot:
user posted image
Auf diesem Bild könnt ihr das ehemalige Gebirgsdörfchen Aaelo im Westen von Iliran sehen, das früher einmal beim Bergbau und der Rohstoffverarbeitung führend war, jedoch inzwischen wegen seiner schlechten Lage abgelöst wurde und kaum noch besiedelt wird. Wie man an den Büschen, Pilzen und Baumstämmen sehen kann, funktioniert die Halbtransparenz inzwischen ohne Probleme (s. Screenshot letzter Eintrag). ^^ Feedback (egal ob positiv oder negativ) ist erwünscht.


An dieser Stelle würde ich auch gerne all diejenigen talentierten Mapper unter euch aufrufen, die gerne mit mir und Gabbes zusammen an Iliran arbeiten möchten, sich bei mir zu melden. Wir suchen vor allem noch Dungeon- und Outdoor-Designer. Also, wenn ihr Lust habt, dann würden wir uns freuen, euch in unserem Team begrüßen zu dürfen. ^^

Schriftrollen, Ausbilder und Erfahrung bei Quests

Montag, 30. Januar 2012 von Lador
Nach fast einem Jahr melde ich mich auch mal wieder, damit es nicht so aussieht, als wäre ich die ganze Zeit auf der faulen Haut gelegen. ^^


Zum Einstieg hab ich diesmal einen Screenshot von der originalen Welt mitgebracht (keine Testmap):
user posted image
Gabbes kümmert sich um die Outdoor-Map. Auf diesem Bild ist ein Wasserfall ganz im Süden von Iliran zu sehen, der ins Meer mündet. Dieser und das Wasser werden im späteren Spiel dann noch animiert. Auffällig nervig sind hier die grauen Flächen unter Bäumen und Pflanzen; diese werden später die Schatten darstellen, ich suche derzeit auch schon fieberhaft nach einer Lösung (ich glaube das Stichwort heißt Halbtransparenz?).

In Iliran kann man ja schon länger Zauber anwenden. Wenn man nun jedoch einen auf Kampf spezialisierten Charakter hat, dann ist die meiste Magie nutzlos schwach bzw. man kann wegen des wenigen vorhandenen Manas teils gar nicht zaubern. Es kann aber sein, dass manche Gegnertypen sich von ein paar Schwerthieben und Stichwunden nicht beeindrucken lassen. Dann muss auch der Krieger zu magischen Hilfsmitteln greifen, die sogar er anwenden kann: Schriftrollen. Diese kosten kein Mana, jedoch geht eine längere Nutzung auf Dauer in die Börse, denn für Schriftrollen verlangen Händler relativ hohe Preise. Man wird sie aber auch öfter finden bzw. in bestimmten Quests bekommen, wenn man sie braucht. Auch Magier können durch Schriftrollen schon auf frühen Stufen bessere Zauber wirken.
Der Einbau von Schriftrollen in mein Programm war eigentlich einigermaßen simpel: Der Zauber-Type erhält einfach noch ein Feld Schriftrolle:Byte (entweder True oder False) und ein Feld Anzahl:Byte (wie oft die Schriftrolle im Zauberinventar vorhanden ist). Nun musste nur noch überprüft werden, ob der ausgerüstete Zauber auf einer Schriftrolle basiert oder nicht. Wenn ja, wird bei jeder Anwendung einfach die Anzahl um 1 verringert, wenn sie gleich 0 ist, wird das Feld im Zauberinventar gelöscht.

Wieder eine mögliche Situation im Spiel: Sagen wir, man braucht ganz dringend gegen einen bestimmten Gegnertyp eine spezielle Waffengattung. Jedoch macht man nicht genügend Schaden damit, weil man diese Fertigkeit bisher vernachlässigt hat. Nun wäre es doch hilfreich, wenn man diese schnell und unkompliziert steigern könnte. Dafür gibt es nun Ausbilder bzw. Trainer. Bei ihnen kann man bestimmte Fähigkeiten bis zu einem gewissen Level verbessern.
Code: [AUSKLAPPEN]
'Ausbildung-Type
Type TAusbildung
   Field ID:Short
   Field Name:String
   Field Inhalt:TList = New TList
End Type

Name:String speichert den Namen des Ausbilders und Inhalt ist eine Liste aller angebotenen Ausbildungen. Für die Objekte darin habe ich eine eigene Klasse erstellt:
Code: [AUSKLAPPEN]
'A(us)B(ildung)Einheit-Type
Type TABEinheit
   Field ID:Short
   Field Fertigkeit:Byte
   Field MaxLevel:Byte
   Field Kosten:Float
End Type

Das ausbildbare Talent wird in Fertigkeit:Byte (1-15) gespeichert, das maximal ausbildbare Level dieser Fertigkeit in MaxLevel:Byte. Kosten:Float gibt hier den Preis "pro Level" an, ist man zum Beispiel gerade mit dem Talent Lange Klingen auf Stufe 20, betragen die Kosten für die Ausbildung auf Stufe 21 eben 20 mal Kosten:Float.
Ein NPC kann entweder ein Händler oder ein Ausbilder (natürlich auch keins von beiden ^^) sein. Bei Händlern ist das Feld Handeln = 1, bei Ausbildern gilt Handeln = 2. Spricht man nun mit einem Charakter, dann wird eben jene Variable überprüft und es erscheint ein entsprechender Button.

Als letzte große Neuerung in diesem Eintrag möchte ich gerne etwas über die Erfahrung loswerden. Durch Besiegen eines Gegners, Anwenden eines Zaubers oder einfaches "Verteidigen" (bei jedem Angriff von einem Gegner bekommt die jeweils aktuelle Rüstungsfähigkeit Erfahrung; bei gemischten Rüstungen gilt das Verhältnis 50%/30%/20% von Brustpanzer/Schild/Helm, zum Beispiel schwerer Brustpanzer, leichtes Schild und kein Helm würde bei 10 Erfahrungspunkten pro Schlag 5 Erfahrung zum Talent "Schwere Ruestung", 3 Erfahrung zu "Leichte Ruestung" und 2 Erfahrung zu "Keine Ruestung" addieren) erhält die jeweilige Fertigkeit Erfahrung durch Anwendung (s. Elder Scrolls). Bei anderen bekannten Spielen erhält der Charakter Erfahrung (v.a. durch Quests) und steigt selbstständig auf, die Fertigkeiten nicht (zum Beispiel Two Words oder auch MMORPGs). Mit dem aktuellen System hätten dann nur leider die Quests weniger Sinn, abgesehen von etwas Gold und ein paar Gegenständen (s. Schriftrollen oben ^^). Deswegen bekommt man für einige Quests auch Erfahrung für ein bestimmtes Talent. Dieses richtet sich dann nach dem Auftraggeber: Absolviert man etwa einen Auftrag für die Kriegergilde, so erhält man Erfahrungspunkte für eine Kampffähigkeit.
Auch hier ist die Implementierung wieder relativ leicht: Der Quest-Type braucht einfach noch die Felder Erfahrung:Short (Erfahrungspunkte) und Fertigkeit:Byte (aufgewertetes Talent). Wenn beides größer als 0 ist, erhält man nach Abschluss der Quest eine Nachricht.

Zum Schluss möchte ich noch einmal meine innenarchitektischen (?) Künste beweisen. Ich werde mich nämlich künftig selbst um die Indoor-Maps des Spiels kümmern.
user posted image
Ein Haus in einem alten Bauerndorf im Süden Ilirans. Der weiße Rand ist Teil meines MapEditors. ^^


Als nächstes werde ich mich wahrscheinlich wie gesagt um die Halbtransparenz, also die Schatten kümmern (auch wieder sehr schön sichtbar am Tisch im Indoor-Screenshot). Wenn ich eine schöne und schnelle Möglichkeit dafür finde. ^^

Stufenaufstieg, Beschwören, Charaktermenü

Montag, 14. Februar 2011 von Lador
Da ich nun in den letzten Wochen mal wieder etwas Zeit fand, mich um mein Riesenprojekt zu kümmern, hab ich mir überlegt, welche Grundlagen in der Engine noch fehlen (weil Inhalt gibts immer noch nur auf dem Papier^^). Ich bin dann auf einen alten Ordner namens "Stufenaufstieg" gestoßen.

Das Prinzip ist relativ simpel: Die 15 Fertigkeiten sind in 5 Haupt- und 10 Nebenfertigkeiten aufgeteilt. Hat man zehn Aufstiege der Hauptfertigkeiten, steigt man eine Stufe auf, wobei sich die Attribute (Stärke, Intelligenz, Geschicklichkeit) erhöhen. Dies macht das Programm wiederum nicht von alleine, sondern der Spieler muss das erledigen. Es gibt jeweils fünf Fertigkeiten, die ein Attribut "unterstützen", d.h. je mehr man diese Gruppe von Fertigkeiten trainiert, desto höher kann das Attribut beim Stufenaufstieg erhöht werden. Das Stichwort heißt (bei mir) "Multiplikator". Die Anzahl an Fertigkeitenaufstiegen wird halbiert, und diese Zahl ergibt dann den Multiplikator.
Pro Stufenaufstieg kann man 12 Punkte auf drei Haupt- und jeweils zwei (also insgesamt sechs) Unterattribute verteilen. Ein Hauptattribut kostet drei Punkte, wird aber auf beide Unterattribute verteilt. Ist der Multiplikator dieses Attributs jedoch größer als eins, kann es nur einmal erhöht werden. Ein Unterattribut kostet nur einen Punkt, kann aber bei einem Multiplikator des Hauptattributs größer als eins alleine nicht erhöht werden. Kompliziert? Ich hoffe ihr könnt das in ein paar wenigen Monaten selbst im Spiel oder einer Vorabversion testen.

Auch ist mir aufgefallen, dass das Beschwören von Monstern zwar schon funktioniert, ich das Beschwören einer Waffe oder einer Rüstung aber noch nicht einmal eingebaut hatte. Wird der Zauber ausgeführt, wird einfach nur die aktuelle Rüstung bzw. Waffe durch die herbeigezauberte Waffe ersetzt. Der Zauber speichert die ItemID dann wird einfach dieses Item geladen, ob man es im Inventar hat oder nicht.

Gestern hab ich dann noch das Charaktermenü etwas erweitert. Zuerst einmal wird nun angezeigt, ob und wie sich die Höhe von (Unter-)Attributen, Schaden und Fertigkeiten verändert hat (z.B. durch Ringe, Zauber, Stichwort: Zustände). Positive Veränderungen werden grün z.B. mit "+12" hinter dem jeweiligen Attribut bzw. der Fertigkeit angezeigt, negative Veränderungen rot z.B. mit "-5" dahinter. Des Weiteren werden nun die Resistenzen bzw. Anfälligkeiten (Feuer-, Eis-, Blitz-, Erd-, Gift-, Todes-Magie) im Charaktermenü angezeigt und ebenfalls deren Veränderungen grün bzw. rot. Hat der Charakter (oder auch der Gegner) einen Feuerresistenz-Wert von 0.4, ist er 40% gegen Feuer resistent und erleidet nur 60% des ursprünglichen Feuer-Schadens. Hat er einen Feuerresistenzwert von -0.2, ist er 20% anfälliger für Feuer und erleidet dementsprechend 120% des ursprünglichen Feuer-Schadens, also 20% mehr. Gegner haben noch Resistenzen/Anfälligkeiten gegenüber Klingen (Lange und Kurze Klingen, Äxte), Stichwaffen (Speere, Pfeile) und Schlagwaffen (Keulen, Stäbe).

Schon wieder ein neuer Mapdesigner

Sonntag, 3. Oktober 2010 von Lador
Die Abstände zwischen den Worklogs werden immer größer. ^^ Ich muss mir leider eingestehen, dass ich jetzt zum Schluss wirklich sehr schlecht voran komme. Die Sommerferien habe ich GAR nicht zum Programmieren genutzt, nur zum Schluss hat mich noch ein kleiner Motivationsschub erreicht. Da Skabus selbst viel zu tun hat, habe ich mich bereit erklärt, zumindest die Indoor-Maps auf meine Kappe zu nehmen. Skabus wird also weiterhin die Außenwelt designen. Und damit ihr euch mal ein kleines Bild (genauer gesagt zwei ^^) von meinen Fähigkeiten machen könnt:

user posted image
Das hier ist die Kneipe im südlichen Hafenkaff Zhak (man sieht nur einen Teil, aber das meiste). Dort treiben sich viele Piraten rum, die man jetzt nur noch nicht sieht. ^^

user posted image
Ein Schlafraum in der Festung Enarco (Hauptstadt Ilirans). Dort wird man im Spiel anfangen. Mehr werde ich allerdings noch nicht verraten. ^^

Würde mich über Kritik freuen. Diese beiden Maps sind auch eigentlich soweit fertig, außer ihr habt noch etwas daran auszusetzen. ^^ Übrigens ist es nicht die Originalgröße aus dem Spiel, im MapEditor sind die Tiles nur 32x32, damit es etwas übersichtlicher ist. Im Spiel ist es 48x48 (erkennt man vielleicht auch in der Demo).


Mehr hab ich leider nicht zu berichten. Wer das BlitzMax-Allgemein Forum mitverfolgt, hat vielleicht mitbekommen, dass ich demnächst noch Fackeln/Beleuchtung und einen Blur-Effekt einbauen werde. Auch animiertes Wasser steht noch weit oben auf meiner To-Do-Liste.

Nachrichten, Zustände und Schlösser knacken

Dienstag, 13. Juli 2010 von Lador
In den letzten Wochen habe ich den Worklog (aber auch das Programmieren) leicht vernachlässigt. Das liegt hauptsächlich daran, dass es mir an Motivation fehlte, weil mir eigentlich nicht mehr ganz so wichtige Sachen einfallen, die ich noch implementieren muss (mal abgesehen vom ganzen Spielinhalt ^^), aber auch daran, dass mir wenig Zeit zur Verfügung stand.

Wie versprochen, habe ich mich um die Nachrichten gekümmert. Das sind einfache, kurze, einzeilige (für mehrzeilige müsste ich dann mehrere Nachrichten machen) Anzeigen am linken Bildschirmrand in Textform. Sie machen deutlich, ob etwas besonderes im Spiel passiert ist, etwa einen Stufenaufstieg, Tagebucheintrag, eine Krankheit etc.
Die Nachrichten werden als einfache TNachricht-Instanz im Nachrichten-Array gespeichert. Bis jetzt sind maximal 5 möglich (vielleicht erweitere ich es noch ein bisschen, wenn der Platz reicht), die neueste steht immer an oberster Stelle. Wenn alle 5 "Plätze" voll sind, wird einfach die älteste gelöscht und die neue Nachricht hinzugefügt. Zuerst einmal der Type:

Code: [AUSKLAPPEN]

'Nachricht-Type
Type TNachricht
   Field Text:String
   Field Alpha:Float
   Field Aktiv:Byte
End Type


Alpha deutet schon auf eine transparente Schrift hin. Die Nachrichten werden immer durchsichtiger, je länger sie aktiv sind. Der Wert Alpha fängt bei 0 an, und wird dann immer um 0.002 größer, bis er den Wert 1.8 erreicht hat, dann ist die Nachricht inaktiv und wird nicht mehr angezeigt. Der Alpha-Wert fängt bei 2 an, wodurch die Schrift erst einmal längere Zeit unverändert bleibt und bei 0.2 wird die Nachricht automatisch gelöscht, weil sie dann fast unlesbar und uralt ist ^^.


Ein weiterer Punkt waren die Zustände. Sie geben einen besonderen Bonus oder Malus an, der von begrenzter, aber auch von unbegrenzter Dauer sein kann (zum Beispiel durch die Wahl der Rasse/Klasse oder durch bestimmte Ausrüstungsgegenstände). Der Type:

Code: [AUSKLAPPEN]

'Zustand-Type
Type TZustand
   Field Art:String
   Field Dauer:Byte
   Field Start:Int
   Field Fortschritt:Byte
End Type


Art:String ist der eigentliche Code des Zustands, zum Beispiel "Staerke + 5". Dieser wird im Programm manuell festgelegt.
Ist Dauer:Byte (in Sekunden) gleich 0, dann ist der Zustand dauerhaft.
Start:Int wird mit MilliSecs() der Startzeitpunkt zugewiesen.
Fortschritt:Byte gibt an, ob der Zustand bereits aktiviert wurde oder schon wieder deaktiviert (also gelöscht) wird.


Zum Schluss noch kurz etwas zum Schlösser knacken. Dafür habe ich ausnahmsweise mal keinen neuen Type gemacht, sondern einfach nur bei TVerbindung (liegt lange Zeit zurück, s. zweiter Eintrag) und TBehaelter das Field Schloss:Byte hinzugefügt, welches angibt, ob es sich um ein offenes bzw. geöffnetes Schloss handelt (=0), ein versperrtes Schloss, das man mit einem Dietrich oder Zauber öffnen kann (=1-100) oder ob man einen Schlüssel dafür braucht (=101). Schlüssel sind normale TItem-Objekte, bei denen Typ:String der Name der StartMap der Verbindung bzw. der Map des Behälters, Schaden1 = x und Schaden2 = y entspricht.
Dazu musste ich nun auch die Dietriche einbauen. Diese haben unterschiedliche Qualitätsstufen, zum Beispiel 25%. Das bedeutet dann, dass die Fertigkeit des Spielers nur zu 25% genutzt werden kann.


Ich hoffe, ich habe nichts vergessen (sonst füg ich das dann noch einfach nachträglich hinzu ^^). Demnächst werde ich wahrscheinlich noch einmal den Quest-Editor überarbeiten, da dieser für mich später für die Implementierung der Spielinhalte sehr wichtig ist und deshalb auch gut handzuhaben sein sollte.

Kleine Demo

Donnerstag, 20. Mai 2010 von Lador
So, wie versprochen, habe ich in den letzten Tagen an einer Demo gearbeitet.

https://www.blitzforum.de/upload/file.php?id=8622

Ich musste noch ein paar Bugs beheben (leider sind immer noch einige vorhanden, ich wollte nur nicht noch länger auf die Testversion warten lassen ^^). Außerdem noch ein bisschen am Balancing feilen etc.
Auch habe ich einige Sachen noch nicht eingebaut. Ihr könnt ja anhand dieses Worklogs einigermaßen mitverfolgen, was ich schon gemacht habe bzw. was ich noch machen muss. Ich wollte eigentlich schon für die Demo eine Hintergrundmusik einbauen, allerdings konnte ich kein Programm finden, dass .mid-Dateien in .ogg oder ähnliches umwandeln kann. Normalerweise mache ich das immer mit Audacity, nur ist bei meiner (Onboard)-Soundkarte die Aufnahmefunktion kaputt und deshalb funktioniert das so nun auch leider nicht mehr.
Kampf- und Zauberfaktor (siehe voriger Worklog) habe ich noch nicht eingebaut. Auch die Ringe im Inventar haben noch keinen Nutzen.

Steuerung:
Pfeiltasten - Bewegen
Strg links - Angreifen
Enter - Reden/Behälter öffnen
Maus - im Interface agieren (Hinweis: mit Rechtsklick kann man einen Gegenstand im Inventar ablegen, wenn er ausgerüstet ist)
Strg links + Mausklick links - im Inventar Gegenstände bewegen/auf Hotkeyslot legen
I - Inventar öffnen
C - Charaktermenü öffnen
H - Hotkeyleiste abschalten
J - Tagebuch öffnen
1-0 - Hotkeys
F12 - Screenshot (wenn ihr wollt ^^)
Ich hoffe, ich habe nichts vergessen.

Euer Held ist ein Krieger, demzufolge nicht ganz so gut in Magie und Fernkampf. Ausprobieren könnt ihr es aber trotzdem. Im Charaktermenü (C) könnt ihr auch eure Fertigkeiten ansehen.
Ich weiß, dass ich einiges vielleicht recht schlampig gelöst habe...

Wie gesagt, es kann sehr gut sein, dass ihr noch den einen oder anderen Fehler entdeckt. Wenn das der Fall ist, wäre es nett, wenn ihr diesen entsprechen posten könntet. Für ein paar Fehler hat auch die Zeit jetzt nicht mehr gereicht, sie zu beheben, aber im fertigen Spiel sind sie dann weg. ^^


Jetzt aber viel Spaß. ^^ Über Lob, Kritik und Verbesserungsvorschläge würde ich mich wie immer freuen.

Erweiterungen im Inventar, Zauber handeln...

Montag, 10. Mai 2010 von Lador
In letzter Zeit habe ich mich vor allem mit dem Inventar befasst. Es war ja eigentlich schon fertig, ich habe nur noch kleinere (bzw. auch größere) Verbesserungen vorgenommen.


Zum Einen habe ich nun Fernkampfwaffen eingebaut (sprich: Pfeil und Bogen). Dazu musste ich erst einmal ein neues Ausrüstungsfeld hinzufügen. Es gibt nun also zwei Felder für ausgerüstete Waffen. Das erste ist nur für "normale" Waffen, also Nahkampf- und Fernkampfwaffen gedacht. Das zweite ist belegt, wenn man entweder eine zweihändige Nahkampfwaffe, Pfeile für seinen Bogen oder ein Schild ausgerüstet hat. Ein Schuss mit dem Bogen kostet aber auch einen Pfeil. ^^ Im Falle eines Treffers werden Schaden von Bogen und Pfeil addiert, d.h., es wird im fertigen Spiel auch verschiedene Pfeile geben, die verschieden großen Schaden anrichten. Die Bögen haben auch verschiedene Schussgeschwindigkeiten, meistens sind sie aber schneller als Zauber.

Vorhin schon erwähnt, kann man sich jetzt auch mit einem Schild ausrüsten. Und es ist sogar (anders als die Waffen) am Charakter sichtbar. Übrigens (das ist aber schon länger eingebaut), wird die Erfahrung bei den Rüstungs-Fertigkeiten so verteilt, wie man gerade ausgerüstet ist. Es gibt ja keine, leichte und schwere Rüstung. Diese kann man auch kombinieren. 50% der Erfahrung bekommt die Rüstungsfertigkeit, 30% die des Schildes und 20% die des Helmes. Und neu eingebaut habe ich auch die Verzögerungsfaktoren. Das heißt, je "schwerer" man ausgerüstet ist, desto länger braucht man für eine Attacke bzw. einen Zauber. Bei leichter Rüstung kann ein Waffenangriff bis zu 25% länger dauern, ein Zauberangriff bis zu 50%. Bei schwerer Rüstung ein Waffenangriff bis zu 50%, ein Zauberangriff sogar bis zu 100% länger (Werte noch nicht final).

Auch neu sind nun Ringe. Man kann bis zu zwei davon ausrüsten, allerdings haben sie bis jetzt noch keine Wirkung, die baue ich aber als nächstes ein (Zustände). Dadurch musste ich die Anzahl an Ausrüstungsfeldern noch einmal um zwei erhöhen.
Bei Händlern kann man nun auch Zauber kaufen und verkaufen, insofern sie welche anbieten.

Wie im letzten Worklogeintrag erwähnt, habe ich auch Behälter für tote Gegner/NPCs eingebaut. Dabei wird einfach nur überprüft, ob einer der geladenen Behälter denselben Namen wie ein toter Gegner hat und ob das Feld NPC:Byte des Behälters gleich 1 ist.


Zum Schluss noch ein kleiner Screenshot vom neuen Inventar:
user posted image

Als nächstes werde ich dann erstmal Textnachrichten einbauen, also kurze Nachrichten, die über der Hotkey-Leiste erscheinen, z.B. "Ihr wurdet vergiftet!" oder "Eure Fertigkeit Schwere Ruestung ist gestiegen!" etc. Danach werde ich mich an die Zustände machen, also z.B. Vergiftung, Stärke um 5 erhöhen usw. Dicht damit verbunden sind natürlich auch die Krankheiten, die man bekommen kann.

Falls größeres Interesse an einer Demoversion bestehen sollte, würde ich mich bereiterklären, in den nächsten 1-2 Wochen einmal etwas (derartiges ^^) vorzubereiten und hochzuladen. Sagt mir einfach bescheid.

Zauber erweitert

Donnerstag, 22. April 2010 von Lador
In den letzten Tagen habe ich mich vor allem mit den Zaubern beschäftigt. Diese waren ja auch schon teilweise eingebaut (siehe Video), jedoch nicht besonders komfortabel. Kostprobe?

user posted image
(Das bei der Hotkeyleiste keine Zahlen dastehen, liegt daran, dass ich das Bild erst nach dem Erstellen des Screenshots eingefügt habe, weil ich sie während des Programms ausgesschaltet hatte, und die Zahlen werden erst im Programm eingefügt. Durch die fehlende Hotkeyleiste sah die Gegner-Lebensanzeige etwas komisch aus, so mitten auf dem Bildschirm ^^.)

Wie man vielleicht erkennen kann, ist dies ein Flächenzauber. Dieser wird aber nur auf Tiles gezeichnet, auf denen der Spieler auch laufen kann (deswegen brennen z.B. die Bäume auch nicht, aber hinter/unter ihnen brennt es, weil der Spieler dort laufen kann und die Blätter über ihm gezeichnet werden). Für diese gibt es den Type TFlaechenschaden:

Code: [AUSKLAPPEN]

'Flächenschaden-Type
Type TFlaechenschaden
   Field x:Short
   Field y:Short
   Field Aktiv:Byte
   Field Zeichnen:Byte
End Type


x und y sind die Koordinaten (in Tiles, also Map-Koordinaten). Wenn Aktiv:Byte gleich True ist, dann wirkt der Zauber auf dieser Fläche noch (das heißt, die Gegner können noch davon Schaden bekommen, auch wenn sie bereits einmal Schaden durch diesen Zauber bekommen haben). Aktiv ist z.B. auf nicht begehbaren Flächen False, oder auf Stellen, auf denen bereits ein Gegner "Feuer gefangen" hat (auch wenn es nicht nur Feuer-Flächenzauber geben wird). Allerdings können Gegner auch nur kurze Zeit Flächenschaden nehmen, solange die Animation läuft. Und da der Flächenzauber im fertigen Spiel auch mehr Mana verbrauchen wird, als ein normaler Zauber, lohnt er sich wahrscheinlich eher, wenn viele Gegner auf kleinerer Fläche sind.
Zeichnen:Byte ist wie Aktiv, nur dass Zeichnen auch noch True ist, wenn Aktiv durch einen Gegner False wurde.
Der Type wird dann in einem Array, dass Zauber.FlaechenBreite breit (x) und Zauber.FlaechenLaenge hoch (y) ist, verwendet. Übrigens: Dreht sich der Spieler, dreht sich auch der Zauber. Breite wirkt immer von links nach rechts vom Spieler aus gesehen, und Laenge wirkt immer von hinten nach vorne gesehen.

Vielleicht erkennt der ein oder andere auch, dass der Zauber "Feuersturm" im Bild ein Nahkampfzauber ist. Das habe ich ebenfalls neu eingebaut. Diese funktionieren ähnlich wie die Nahkampfangriffe. Der Spieler muss direkt neben einem Gegner stehen und in seine Richtung sehen, sonst kann die Attacke nicht ausgeführt werden. Nahkampfzauber werden weniger Mana brauchen, weil der Spieler Schaden auf sich nehmen muss, wenn er sie einsetzen will.

Nicht so gut im Screenshot erkennt man die nächste Neuerung: Zauber können eine gewisse Zeit lang wirken. Das muss nicht heißen, dass das auch jeder Zauber macht, aber es wird viele Zauber im Spiel geben, die eine Wirkungsdauer haben (die kosten dann aber auch mehr Mana ^^). Bei Kampf- oder Heilzaubern wird dann der Schaden bzw. die Wirkung jede Sekunde vom Gegner abgezogen bzw. dem Spieler hinzugefügt. Steigerungs- und Senkungszauber (z.B. Attribute wie Stärke usw.) wirken dann einfach so lange, also z.B. Stärke wird für 30 Sekunden um 20 erhöht.

Ansonsten gab es ein paar kleinere Änderungen im Zaubermenü (Zauberinventar) und im "normalen" Inventar.


Demnächst werde ich dann noch das Inventar erweitern. Dort fehlen mir noch Fernkampfwaffen, Schilde und (verzauberte) Ringe. Außerdem werde ich noch einbauen, dass getötete Gegner, die einen Gegenstand bei sich tragen (also eher NPCs, die zu Gegnern wurden), diesen dann fallen lassen und man ihn dann aufheben kann, wenn das Inventar nicht voll ist.

Lob, Fragen, Anregungen und Kritik sind gerne willkommen. ^^

Tagebuch-Funktion

Montag, 12. April 2010 von Lador
Samstag Abend habe ich mich mit dem Tagebuch im Spiel beschäftigt. Dort werden aktualisierte Questereignisse niedergeschrieben. Zuerst einmal ein Bild zur Verdeutlichung:

user posted image

Das Tagebuch ist eine TList (genannt TagebuchList:TList). Diese besteht aus den Instanzen Eintrag:TEintrag. Der Eintrag-Type sieht folgendermaßen aus:

Code: [AUSKLAPPEN]

'Tagebucheintrag-Type
Type TEintrag
   Field ID:Short
   Field QuestName:String
   Field Tag:Short
   Field UhrZeit:String
   Field Inhalt:String[25]
End Type


ID gibt an, an welcher Stelle im Tagebuch der Eintrag ist (sichtbar unten an der Seitenzahl, es gibt immer nur einen Eintrag pro Tagebuchseite).
Der QuestName ist der Name der Quest (in diesem Falle "Die Medizin fuer den Alten", steht oben in der zweiten Zeile).
Der Tag speichert die Zahl des Tages im Spiel, zu welcher der Tagebucheintrag enstand (erste Zeile).
UhrZeit speichert die Stunden- und Minutenzahl, zu welcher der Tagebucheintrag entstand (ebenfalls erste Zeile; wer das Bild genau unter die Lupe nimmt, erkennt unter den Balken für Lebens-, Mana- und Fertigkeitsanzeige auch noch die Uhrzeit "16:02 Uhr" ^^).
Der Inhalt ist ein Array, in dem die einzelnen Zeilen des Tagebucheintrages gespeichert sind (es sind maximal 25 möglich, mehr passen auch nicht auf eine Seite).

Hinzu kommt außer der TagebuchFunktion(), die beim Drücken von J aufgerufen wird, vor allem noch die Funktion TagebucheintragHinzufuegen(ID:Short,QuestName:String). In Ihr wird ein neuer Eintrag:TEintrag erstellt. Für das Field ID habe ich eine Variable EintragID:Short mitlaufen lassen, der nach jedem erstellten Eintrag +1 hinzugefügt wird. Tag und UhrZeit werden einfach direkt aus dem Hauptprogramm übernommen, und der Parameter ID der Hinzufügen-Funktion dient dazu, die richtige Datei zu laden.

Für die TagebuchFunktion() gibt es noch die Variable TagebuchSeite:Short, die angibt, auf welcher Doppelseite man sich gerade befindet, also TagebuchSeite=0 heißt, man sieht die Seiten 1+2, TagebuchSeite=1 heißt, man sieht die Seiten 3+4. Die Variable wird mit klicken auf den Schwertpfeil unten rechts vergrößert, und unten links verkleinert, vorausgesetzt, man hat schon genug Einträge.

Wahrscheinlich werden die Tagebucheinträge eher so kurz wie der obige gehalten werden, deswegen mache ich evtl. noch den Abstand zwischen den Zeilen und/oder die Schriftgröße größer.

Lange Pause, neuer Mapdesigner, Behälter, Handeln...

Montag, 15. März 2010 von Lador
Ich wollte auch mal wieder ein Lebenszeichen von mir geben. Seit dem letzten Worklog-Eintrag ist auch wieder einiges in Iliran passiert.

Zuerst hatte ich Probleme mit den neuen Editoren, die nicht so wollten wie ich wollte. Dann war mein Computer 2 Monate lang kaputt und ich fand anfangs keine Motivation, an meinem Projekt weiterzumachen. Zusätzlich sagte mir auch noch mein Mapdesigner Cireva mangels Zeitgründen ab (schon wieder einer...^^). Deshalb möchte ich nun auch herzlich Skabus in meinem Team begrüßen, der neben seinem Projekt Aves Certim die Maps für Iliran macht.

Neben zahlreichen Kleinigkeiten, habe ich mich in letzter Zeit überwiegend mit Behältern und mit dem Handeln beschäftigt. Mit Behälter meine ich z.B. Truhen, Kisten, Fässer etc., die eine Liste aus Items beinhalten. NPCs, mit denen man Handeln kann, sind auch eine Art Behälter. Falls ein Behälter ein NPC ist, ist der Eintrag "NPC:Byte" im Type TBehaelter gleich True, und die x/y-Werte sind in diesem Fall auch egal (also 0/0), da diese Behälter nicht wie die anderen geöffnet werden können. Desweiteren ist im NPC-Type ein Field BehaelterID, das sich die ID-Nummer des Behälters merkt und der Eintrag Handeln wird gleich True.

Code: [AUSKLAPPEN]
Type TBehaelter
   Field ID:Short
   Field Name:String
   Field NPC:Byte
   Field x:Short
   Field y:Short
   Field Inhalt:TList = New TList
End Type


Normalerweise öffnet man einen Behälter, indem man sich davor stellt und Enter drückt. Bei den NPCs muss man diese erst ansprechen und kann dann auf einen Button "Handeln" klicken.

Des weiteren habe ich letzte Woche auch noch eingebaut, dass NPCs zu Gegnern (vor allem während Quests) werden können. Dazu muss eine eigene Gegner-Instanz in der GegnerList reserviert werden. Bei dieser Instanz ist die Position wieder 0/0, und der Eintrag NPC:Byte im Type TGegner ist gleich True. Im NPC-Type wird noch der Eintrag GegnerID eingefügt, der sich die ID-Nummer des Gegners merkt. Wenn nun während einer Quest der Befehl gegeben wird, dass der NPC x feindlich wird, dann wird auch die entsprechende Variable Feindlich:Byte im NPC-Type gleich True und dann erfolgt die Funktion NPCzuGegner():

Code: [AUSKLAPPEN]
Function NPCzuGegner()
   For g:TGegner = EachIn GegnerList
      If g.ID = NPC.GegnerID And g.NPC = True Then
         g.Image = NPC.Image
         g.px = NPC.px
         g.py = NPC.py
         g.ppx = g.px*48
         g.ppy = g.py*48
         g.NPC = False
         ListRemove(NPCList,NPC)
      EndIf
   Next
End Function


Man sieht, dass sich beide Verfahren teilweise sehr ähnlich sind.

Gehe zu Seite 1, 2  Weiter