Tehadon

Kommentare anzeigen Worklog abonnieren
Gehe zu Seite Zurück  1, 2, 3, 4, 5 ... 10, 11, 12  Weiter

Worklogs Tehadon

Ein paar Dinge

Sonntag, 1. Februar 2009 von peacemaker
Hallo,

zunächst mal, ein paar Dinge die sich im Team etwas geändert haben. Durch das Abspringen von Willi, dem Programmierer, wurde ein Platz frei. Da ich ein paar Tage zuvor noch die Physikengine von Noobody eingebaut habe, kam dies gerade richtig, da dies Noobody dazu bewog, bei uns als temporärer Mitarbeiter, für eine mehr oder weniger kurze Zeit, einzusteigen.
Er hat sich bereit erklärt die Physik und die GUI zu machen. Ihr glaubt ja nicht, wie uns das gefreut hat Smile
So, nachdem sich Noobody ans Werk machte, tat seine Physikengine auch das, was sie tun sollte: sie funktionierte. NPCs sterben nun um einiges schöner über Ragdoll, als das sie es früher taten. (sie wurden einfach in der Luft zerfetzt. Ein komischer Bug)

Ich war auch nicht faul, und hab mich sogleich an zwei Dinge gemacht: an die Visualisierung des Tag / Nacht-Wechsels, sowie die externen NPC-States.
Beim Tagnacht-Wechsel wird bisher nicht allzu viel gemacht. Einfach die Skybox und die Lichtfarbe wird auf die momentane Farbe angepasst. Die Farben werden für jede Stunde definiert, und werden aus einer Bilddatei, die 24x1 Pixel gross ist, gelesen. Für jede Stunde, ein Pixel. Die Farben werden natürlich schön interpoliert.

Dann noch externe States. (Ohne technischen Kram geht gar nix)
NPCs haben ja States, zu Deutsch Zustände. Das könnte z.B. sein "Angreifen", "Ausweichen", "Sitzen", "Rumstehen", und und und. Die sind alle fest programmiert, man hat kaum was daran zu rütteln.
Das ist für solche States wie "Freuen" oder "rauchen" etwas blöd. Der Aufwand, so etwas zu inplementieren ist unerhört hoch, weil das recht einfache States sind, und BlitzBasic nicht die Features bringt, die es für solche Dinge bräuchte. Das wären z.B. Funktionsreferenzen, und noch ein paar Dinge mehr. Also macht man sowas lieber geskriptet, schon dadurch weil unsere Skriptsprache solche Dinge kann, und es so auch schön extern flexibel bleibt.
Für etwas komplexere States wie für Kampfstates ist das aber nicht gedacht, jedoch immernoch recht einfach möglich.

Ich zeig euch zuerst mal ein Bild, auf welchem man einen NPC in der späten Morgendämmerung hämmern sieht. Das hämmern wurde auch extern geskriptet.

user posted image

States werden nicht durch irgendeine Klasse oder so gehandhabt. EiN State ist schlichtweg ein String, welcher die Funktionen beschreibt, die in verschiedenen Situationen aufgerufen werden. Dieses State heisst 'AI_STATE_REPAIR'. Die Definition sieht dann so aus:

Code: [AUSKLAPPEN]
void AI_STATE_REPAIR_START ()
{
   $this->attachItem (copy ($ItHammer)); // Nimmt den Hammer in die Hand
   $this->animateSeq (336,352,1); // Hämmer-Animation abspielen
};

void AI_STATE_REPAIR ()
{
};

void AI_STATE_REPAIR_END ()
{
};

Jede Funktion beinhaltet den Namen 'AI_STATE_REPAIR'. Nur hat es zuoberst und zuunterst noch ein _START bzw. ein _END am Namen. Das sind schlichtweg Substates. Wird das State vom NPC ausgeführt, wird _START einmalig ausgeführt. Ist das State aktiv, wird AI_STATE_REPAIR, solange ausgeführt bis das State beendet wird. Will man das State frühzeitig beenden, muss man in dieser Funktion einfach ein return (STATE_END) machen.
Am Schluss, wenn das State fertig ausgeführt wird, wird noch einmal die _END-Funktion ausgeführt, woraufhin das State aus der Queue gelöscht wird, um dem nächsten Platz zu machen.
So sagt man dem NPC, das er ein State durchackern soll:
Code: [AUSKLAPPEN]

$this->addState (AI_STATE_EXTERN, "AI_STATE_REPAIR");

Fertig. Schön simpel, aber sehr nützlich.

mfG

Terrain, Physik, ....

Mittwoch, 28. Januar 2009 von peacemaker
Hallo,
Wird mal wieder Zeit, das ein neuer Eintrag kommt. Weiterhin hat sich auch bei uns einiges getan, sodass wir einige neue Features und Bilder vermelden/zeigen können.

Fangen wir mal an mit was sichtbarem: den Terrains. Ich hab ja schonmal geschrieben, das wir uns nun endgültig entschieden haben, auf Meshterrains umzusatteln. Es stimmt schon, sie sehen einfach viel echter aus.
Dazu hat Jo0oker mal ein System geschrieben, welches auch das mit dem LOD recht gut beherrscht, sodass wir es bald komplett in Tehadon inplementieren können. Vorerst müssen wir uns jedoch nocht überlegen, wie wir das am besten in die Map einpflegen.

Das hat grosserboss und quantarie, 3D-Männer vom Dienst, dazu bewogen Meshterrains zu machen. Zuerst einmal seht ihr hier Quantaries Werk. Ihr müsst bitte beachten, das die Texturen nicht richtig final platziert wurden, da noch Übergänge fehlen, etc.

user posted image

Nun das Werk von Grosserboss. Hier sind die Texturen schon etwas ausgereifter. Die Szene ist in 3ds Max gerendert, das Wasser wird später nicht so aussehen.

user posted image

Wo wir gerade beim Wasser sind. Ich hab einmal ein Flussystem ins Spiel integriert, nur wurde es bisher nie genutzt, da der Editor das nicht unterstützt hat. Dem hat Jo0oker nun entgegengewirkt und auch hier ein bequem zu handhabendes System gemacht, um Flüsse zu erstellen und zu bearbeiten.

Dann steht da ja als zweites Physik. Noobody hat mir schonmal eine erste Version seiner Physikengine zukommen lassen, die schonmal Ragdoll unterstützt. Ich hab beim Einbau wohl irgendetwas falsch gemacht, denn nun fliegen die NPCs etwas komisch umher.
Aber wird schon.

Dann kann man jetzt schon kämpfen. Die Steuerung ist zwar arg verkorkst, aber es funktioniert einigermassen. Hier zwei Bilder aus einer Auseinandersezung:

user posted image

user posted image

Das wars erstmal,
mfG

Copy, CNpc und Demo

Samstag, 17. Januar 2009 von peacemaker
Hallo,

Es ist mal wieder etwas her, seit der letzte Eintrag verfasst wurde. Sind wieder mal einige Dinge geschehen, ich führ mal die auf, an die ich mich noch erinnern kann.

Wir haben unserer Webseite nun eine weitere Galleriesektion für Renderings hinzugefügt. Das sind vorberechnete Bilder mit Meshes die auch im Spiel vorkommen. Hier mal eine Auswahl davon. (Alle stammen von grosserboss)

user posted image user posted image

Weitere findet ihr hier .

Zuerst mal hat HDSS ein neues Schlüsselwort spendiert bekommen: copy. Damit kopiert man eine Instanz. Die Wichtigkeit ist höher als manche sich denken können, vor allem bei den Items. Items werden durch die 'CItem'-Klasse gehandhabt, jede Instanz dieser Klasse steht für exakt ein Item auf der Welt, und nicht etwa für einen Typen.
Also müsste man wenn man mehreren NPCs beispielsweise das 'Feuerschwert' geben will, mehrere Instanzen machen. So funktioniert das schon etwas einfacher:
Code: [AUSKLAPPEN]

$npc->addItemToInv (copy ($ItFeuerSchwert));

Das ganze ermöglicht nun auch Prototypen. Man kann z.B. ne NPC-Instanz namens $NPC_Human machen, dort kann man einige Standard-Werte wie Mesh, Animationsfile, Kampf-KI, etc. festlegen.
Dann einfach anstatt new (npc) zu machen, copy ($NPC_Human). Die Eigenschaften kann man natürlich immernoch anpassen, also z.B. Kampf-KI ändern, usw.

Nächster Punkt: vor einiger Zeit berichtete ich davon, das der Spielercharakter im Spiel selber durch einige globale Variabeln. Die Problem die daraus folgen sind teilweise gravierend: man muss für NPCs und Spieler einige Dinge komplett anders machen.
Auch Multiplayerpart wäre so unmöglich (nein, ich plane kein MMORPG oder einen Multiplayer).
Das hat sich nun nach geändert. Der Spieler ist nun auch eine CNpc-Instanz, also ein NPC, der einfach steuerbar ist. Eigentlich wiederspricht das jeder Logik, da NPC ja für NonPlayerCharakter steht, aber egal, pfeifen wir mal drauf.
Dafür muss man jetzt aber den Spieler auch extern als NPC instanzieren und dann mit dem Befehl SetHeroNpc () als Spieler deklarieren.
Das hatte zur Folge, das ich die Steuerung neu machen musste. Und hier gibt es teilweise schlimme Bugs, aber auch die sind schon so gut wie im Nirvana.

Desweiteren habe ich in unserem Channel die letzte Teamdemo (vom Oktober 2008) rausgegeben. Sie ist weder spielerisch hochwertig, noch sonstwie spannend, es ist mehr eine Techdemo, primär um das Skriptsystem zu zeigen.
Immerhin kann man das Ding schon vollständig modden, Quests hinzufügen, etc. etc.
Ich werde den Link hier nicht aufführen, da das ganze eher so halbpublik ist. Wer ihn trotzdem möchte kann mir ne pn schreiben oder mal in unserem Channel vorbeischauen.
Eine richtige Demo sollte es aber bald auch geben, auch mit Dingen wie Kampf, interessanteren Quests, etc.

Dann wäre da noch ein Punkt... Kampf-KI. Da es verschiedene NPCs gibt, die auch verschiedene Kampf-KIs besitzen, habe ich das ja auch auf HDSS ausgelagert. Davon habe ich schon mal vor längerer Zeit berichtet.
Ich habe mal nachgedacht wie ich das am besten mache, hab mich jedoch gegen eine OO-Lösung entschieden, da es zu viel Aufwand darstellte.
Das funktioniert nun so:
Code: [AUSKLAPPEN]

// Wenn Gegner angreift
void FAI_Human_Attack ()
{
 $this->addState (AI_FIGHT_MOVE_LEFT, ""); // Nach links ausweichen
 $this->addState (AI_FIGHT_ATTACK_STRONG, ""); // Starker Angriff
};

// Wenn er stark angreift
void FAI_Human_Attack_Strong ()
{
 $this->addState (AI_FIGHT_DODGE_BEHIND, ""); // Nach hinten ausweichen
 $this->addState (AI_FIGHT_MOVE_RIGHT, ""); // Nach rechts ausweichen

 if (rand (1,3) == 1)
 {
  $this->addState (AI_FIGHT_ATTACK_STRONG, "");
  return (0);
 };

 $this->addState (AI_FIGHT_ATTACK, "");
};

Und so setzt man die FAI für einen NPC:
Code: [AUSKLAPPEN]

var $npc = new (npc);
// ...
$npc->fai = "FAI_Human";
// ...

Die Engine macht aus dem FAI_Human dann später immer automatisch das State des Gegners, und ruft die Funktion auf. Simpel, aber effektiv.
Ich denk das wäre erstmal alles.

mfG

Gepriesen seien die Includes

Freitag, 9. Januar 2009 von peacemaker
Hallo Worklogleser,

die Zeit für einen neuen Eintrag ist da. Es sind wieder kleinere Dinge eingebaut worden, ich erzähle mal von ein paar davon.
Ich habe bis heute angenommen, das Includes in HDSS gar nicht funktionieren. Beim durchschauen des Precompilers hab ich aber plötzlich gemerkt, das Includes theoretisch möglich sein sollen. Der #include-Befehl hat auch tatsächlich gut funktioniert. #includeDir nicht. Dieser Befehl ist, welch wunder, dazu da, einen Ordner zu durchsuchen, alle Skripts die darin sind zu inkludieren, und auch alle unterordner zu durchsuchen.
Diese beiden Konstrukte ermöglichen endlich, etwas besser strukturiertere Skripts. Wer das Skript zum letzten Video gesehen hat, wird vielleicht verstehen wie nützlich die beiden Befehle sind.
Beispielweise #includeDir: Aller Storycontent, wie z.B. NPCs kommen also in den Unterordner content\npc\, für jeden NPC ein Skriptfile. jetzt einfach #includeDir "content\npc\" und schon hätt sichs.

Etwas, was nun auch hinzugekommen ist, sind einige TMF-Befehle. TMF, zur Erinnerung: Tehadon Map File. Damit lassen sich Maps laden, einzelne Sektionen selektieren, das dynamische Nachladen überwacht werden, etc.
Ich hab versucht das einigermassen OO zu strukturieren, dafür gibts jetzt einfach eine Singleton-Klasse Namens 'tmfManager'. In Action:
Code: [AUSKLAPPEN]

var $tmf = new (tmfManager);
$tmf->load ("data\test.tmf");

Ist sicher praktisch das extern auszulagern.

Dann, mal was Grafiktechnisches. Ich hab mich nun definitiv entschieden, auf Meshterrain umzusteigen, allein wegen der Bearbeitung und Texturierung, desweiteren sind damit wirklich echtere Terrains möglich.
Jo0oker, unser Tool-Mann, hat bereits ein System für Meshterrains geschrieben, welches zugleich auch LOD und weitere Dinge supportiert. Jetzt ist es nur noch eine Frage der Zeit, bis Terrains reinkommen.

Noch ein Wörtchen bezüglich Demo (wurde ja letztes mal erwähnt): Es steht gar nichtmal so übel drum, etwas grosses, das allerdings nun fehlt, ist Kollision, ich hab die B3D-Kollision wieder rausgenommen. Die Kollision ist natürlich Sache der Physikengine, und hier warte ich nach wie vor auf Noobody.
Wo wir gerade bei dem werten Herren sind. Vor einiger Zeit habe ich geschrieben, das ich nach wie vor auf der Suche nach einem System bin, welches 2D-Grafiken auf 3D-Basis rendert. Die Draw3D war lange in Tehadon drin, aber es gab einige Punkte, die es etwas schwierig machten, das zu inplementieren. Es ist wirklich ein gutes, schnelles, ausgereiftes System, das will ich natürlich nicht bestreiten.
Noobody fand das wohl auch, und hat sich selber so ein System gebastelt. Es ist exakt gleich wie Blitz2D, und funktioniert wirklich angenehm flott, und bietet einige interessante Features. Ich denke die GUI wird in Zukunft definitiv mit diesem System laufen.

mfG

Leichen, Kisten, plündern

Freitag, 2. Januar 2009 von peacemaker
Ich habe nun auch einen weiteren Dialog in Sachen Items hinzugefügt: den Plünderungsdialog. Wenn man tote NPCs im Fokus hat, und klickt, eröffnet sich ein Dialog, wo das komplette Inventar des NPCs gezeigt wird. Dort kann man dann auswählen, welche Items man nehmen will. Es besteht natürlich auch die Möglichkeit alle Items zu nehmen.
Das ist nicht besonderes und bei dem schlichten GUI-System auch schnell gemacht.

Hier schliesst etwas weiteres an: Itemcontainer. Itemcontainer sind statische Objekte, die ein Inventar haben. Das können z.B. Kisten, Schatztruhen, etc. sein.
Man kann die Dinger nun schonmal per Skript erstellt, und irgendwo positionieren. Das würde dann so aussehen:
Code: [AUSKLAPPEN]

var $truhe;
$truhe = new (ItemContainer);
$truhe->meshpath = "data\modelle\platzhalter\AUSS_Truhe.B3D";
$truhe->wp = "WP_Truhe_01"; // Positioniert an diesem WP
$truhe->name = "Truhe"; // Wird im Fokus angezeigt
$truhe->additem ($ItAltjemenSword);
$truhe->addItem ($ItKrug);
$truhe->additem ($ItKaese);

Das Ergebnis: (die Truhe ist von mir modelliert, ihr werdet das Aussehen sicherlich verstehen)
Das Objekt fokussiert:

user posted image


Der Plünderungsdialog an der gleichen Truhe:

user posted image

Was noch nicht funktioniert ist Items in die Kiste zurücklegen, bzw. lagern. Nimmt man einmal ein Item aus der Kiste, ist es auch weg.

Nun, ich will jetzt keine grossen Ankündigungen machen, aber mit dem hinzufügen vom Handeln sowie dieses Plünderungsfeatures, eröffnen sich gleich recht neue Wege für interessantere Quests.
Fehlt noch ein besseres Kampfsystem, und Tehadon wäre bereit für eine Demo.

Wir arbeiten nach wie vor nach dem "When it's done"-Prinzip, ausserdem steht uns trotz allem noch vieles bevor. Physik beispielsweise. Wie es ausschaut, werden wir die Physikengine von Noobody benutzen, eine extra für BB konzipierte Engine. Falls es damit nichts wird, dann werden wir wohl auf eine der herkömmlichen Engines umsteigen müssen. Ich denke am ehesten ODE, da es kostenlos ist.
Auch ein Magiesystem fehlt, wobei hier anzumerken ist, das sowas eher schnell inplementiert ist.
Nach wie vor müssen wir irgendwann noch komplette GUI-System anpassen, denn so wie se im Moment ist, ist es nicht spieltauglich, primär vom optischen Aspekt her.

Dann wollte ich irgendwann noch das Schiffssystem neumachen. Es ist nun angedacht, das man nicht wie bisher direkt das Schiff steuern kann. Es gibt Schiffe, die eine bestimmte Route haben, die man selber nicht festlegen kann. Dann gibt es solche, wo man zu Beginn der Fahrt die Route einzeichnet (in 3D, in so einer Art "Strategieperspektive"), die dann abgefahren wird.
Während der Fahrt selber wird man auf dem Schiff normal herumlaufen können, wie am Festland, Schiffe sind schlussendlich nichts anderes als bewegliche Mapabschnitte.

mfG

Storybereich und Magie

Freitag, 2. Januar 2009 von peacemaker
Sei gegrüsst Worklog-Leser!

Um endlich auch mal mit einigen Storytechnischen Informationen rauszurücken, haben wir einen Bereich für die Story in die Webseite integriert.
Gleichzeitig haben wir auch eine längere Sequenz veröffentlicht, die die Magie von Tehadon etwas genauer erklärt. Fragen, Kritik und Anregungen sind uns natürlich jederzeit willkommen.

Zum Storybereich

edit: Noch wegen der momentan etwas schlechte Formatierung auf der Webseite, hier nochmal die ganze Sequenz:
Zitat:

„Lies mir...“, Leila zögerte einen kurzen Moment, als sie mit ihrem kleinen Zeigefinger über die Buchrücken strich. „Lies mir aus dem vor!“ Und sie griff einen alten, in rotem Leder gebundenen Folianten aus dem Regal, auf dessen Rücken in schwarzer Farbe eine hässlich grinsende Fratze geprägt war.
'Vom Anfang aller Tage' hieß es auf der ersten Seite in großen, verschlungenen Lettern.
„Bist du sicher, meine Kleine?“, fragte der Großvater lächelnd. „Die Geschichten darin sind ziemlich schaurig.“
„Ich hab keine Angst. Du bist doch bei mir.“ Geschwind kletterte Leila in ihr weiches Bett, zog sich die Decke bis unters Kinn und lächelte ihren Großvater erwartungsvoll an.
„Na gut, aber wenn es dir zu gruselig wird -“, begann der Alte, bevor er jäh unterbrochen wurde.
„Großvater!“
„Oh, tut mir Leid, also, dann wollen wir mal...“ Er schlug das Buch auf und blätterte ein wenig durch die pergamentenen Seiten, flüsterte ab und an einige Titel wie „Vom Untergang Al'tjemens“ oder „Vom Nachtmensch Kiraman“ vor sich hin, bis er fand, was er suchte.
„'Von den Worten des Wanderers', eine Geschichte über Magie und wie sie in unsere Welt kam. Klingt das gut?“
Das kleine Mädchen klatschte unter seiner Decke in die Hände und nickte eifrig.
„Es war einmal, vor langer, langer Zeit, noch als die alten Reiche des Westens erblühten...“

...ein Dieb namens Darius, ein Meister seines Fachs, wenn auch ein wenig gierig. Schon oft saß er in den Kerkern Tanhems ein, wenn er in seiner Gier auch nach dem letzten Goldstück ein zu großes Wagnis einging, doch ebenso oft konnte er wieder entkommen.
Auch dieses mal wurde ihm seine Gier zum Verhängnis. Als er in die Hütte des Dorfvogts einbrach, um sich an dessen Wertsachen gütlich zu tun, erblickte er eine Kette mit einem kleinen, aber fein geschliffenen Diamanten, die er unbedingt haben musste. Leider befand sich diese am Hals des schlafenden Hausbesitzers. Kaum das Darius sie in Händen hielt, erwachte der Vogt und rief die Wachen. Auch unter Dieben gibt es Anstand - er tötete niemanden -, und so landete unser Gauner bald wieder in den feuchten Kerker der Stadt.
Man warf ihn in eine Zelle mit einem alten Greis, dessen Haut aussah wie dunkles, altes Leder, und der leis vor sich hin kicherte. Darius kümmerte sich nicht um ihn, wartete eine Weile ab, bis die Wache endlich eingenickt schien und machte sich daran, die drei Schlösser an der Tür zu knacken.
'Ist das ein Leben für dich?' krächzte es da aus der Ecke. Der Dieb drehte sich um und setzte zu einer bissigen Bemerkung an, bis er in die stahlgrauen Augen des Alten blickte. Er zögerte.
'Ein Meister wie du als Kleinstadträuber in der Provinz? Meinst du nicht auch, du wärst zu Höherem berufen?' Der Greis zeigte sein zahnloses Grinsen. 'Es gibt da eine Geschichte bei uns im Norden...'
Darius setzte sich nieder und lauschte gebannt den Worten des Fremden. Von Schnee und Eis und alten Tempeln und verlassenen Höhlen und gigantischen Bergen auf denen die Götter hausten. Und von Magie. Von der Macht der Götter.
'Die Macht der Götter...', flüsterte der gierige Dieb, als der alte Mann geendet hatte. Mit einem kalten Lächeln auf den Lippen und vor Erregung zittrigen Fingern öffnete er im Handumdrehen die Tür und schlich sich ins Freie, trunken von den Verheißungen des Greises.

„Wenige Tage später erreichten Darius und sein Esel die Hänge der Nordberge. Mit leuchtenden Augen -“
„Was ist aus dem alten Mann geworden?“ fragte Leila in kindlicher Neugier.
Der Großvater lächelte. „Das ist eine Geschichte, die ich dir vielleicht ein anderes Mal vorlese.“
Das Mädchen überlegte kurz, bis es fragte: „Gab es da noch keine Magie?“
„Nein, nein, darum geht es doch in der Geschichte. Die Magie gehörte einst nur den Göttern. Also, wo waren wir? Mit leuchtenden Augen...“

...starrte er an den zerklüfteten Gipfeln hinauf in den wolkenverhangenen Himmel, wo die Götter wohnten. Bei sich hatte er kaum mehr genug Proviant für seinen Aufstieg, doch wer die Macht der Götter besaß, der brauchte keine Nahrung mehr. So machte er sich über die schmalen Grate hinauf zum höchsten Gipfel des Gebirges. Tage und Nächte starben im kalten Schnee dahin, bis er eine alte Grotte erreichte, die in die Tiefe des Berges führte. Sein Esel war längst gestorben, nur die Gier hielt Darius am Leben, als er in die Düsternis trat und dem alten Gang in die Tiefe des Berges folgte. Nach einer Weile gelangte er an eine Treppe, die ihn nach oben führte und in der Dunkelheit des Berges schien es ihm, als würde er endlose Wochen nur den Stufen folgen. Doch dann erblickte er ein Licht und als er mit zusammengekniffenen Augen durch den kunstvollen Torbogen ins Freie trat, raubte es ihm fast den Atem. Ein fruchtbares grünes Tal erstreckte sich inmitten der steilen Berge, tausende und abertausende Meter über dem Meer. Doch er kannte sein Ziel. Den imposanten Palast, der inmitten des Talkessels thronte. Er schlich durch blühenden Gärten, über die marmornen Wege, vorbei an prächtigen Abbildern der Götter, und hinein in die glitzernde Schönheit des Palastes. Mit jedem Schritt, den er in dieses wundervolle Reich tat, wuchs sein Wunsch, auch solche Dinge erschaffen zu können, solch Macht zu besitzen.

„Es gab keine Wachen -“
„Großvater, warum sind es immer Götter? Vater Abreus sagt, es gibt nur einen Gott und das ist Aman!“
Was für ein kluges Mädchen seine Enkelin doch war. Er lächelte liebevoll. „Früher glaubten die Menschen noch an die vielen falschen Götter, außerdem ist es ja auch eine Geschichte!“
Leila überlegte. „Lies bitte weiter“, sprach sie schließlich.
„Es gab keine Wachen...“

...im Palast, denn wer sollte es wagen die Götter zu hintergehen? Und so gelangte Darius ungehindert in die innerste Kammer des Palastes. Sie war kreisrund und in ihrer Mitte stand ein ebenso runder Altar, auf dem ein schwarzer Stein lag, kaum größer als die Handfläche eines Mannes. Auf ihr brannte ein verschlungenes Zeichen und Darius glaubte flüsternde Stimmen zu hören. Er blickte angstvoll um sich, doch der Palast war wie ausgestorben. Also griff er von Verlangen gepeinigt zu. Doch als er den Runenstein berührte und ihn seine Macht erfüllte, erkannte er, was er getan hatte. Seine Zunge wand sich in seinem Mund, ohne dass er sie hätte kontrollieren können, seine Finger klebten geradezu am kalten, brennenden Stein. Er erkannte, was das Wesen der Magie war, er sprach Worte, die er nicht kannte, als er Flammen und Eis und Winde und Felsen beschwor, er stürzte zu Boden, als sich die Macht der Götter selbst entfesselte und in den Gedanken der Menschen Einzug hielt.

„Von da an war den Menschen die Magie geschenkt.“ Der Großvater schaute auf und in das vor Spannung hingerissene Gesicht des Mädchens. „Möchtest du das ich weiter lese? Denn jetzt wird es wirklich gruselig.“
„Bitte, bitte, lies weiter!“
„Na gut, wenn du unbedingt willst. Da eilten die erschrockenen Götter...“

...in den Palast und fanden den hilflosen und schreienden Mann, dem all das Wissen der Welt zu Teil wurde und nun über die Lippen strömte.
Der älteste von ihnen nahm Darius den Stein aus der Hand und betrachtete das nunmehr unbewegliche Zeichen, das darauf eingebrannt war. 'Ihre Macht ist...erschöpft.' teilte er mit ausdrucksloser Stimme den anderen mit.
'Wir müssen ihn bestrafen!' rief ein anderer.
Und ein anderer meinte: 'Verbannen wir den Menschen für seine Habgier!'
Und wieder ein anderer: 'Wohin ist die Magie verschwunden?'
Und ein großer Streit begann. Der Älteste starrte derweil stumm auf den reglosen Leib des Sterblichen zu seinen Füßen, ehe er mit grollender Stimme Ruhe gebot.
'Wir können nicht allen Menschen die Zunge nehmen, die die Magie spricht. Viele werden sich, nun, da sie die Macht gekostet haben, wehren. Doch wir können nicht zulassen, dass alle Fantasie der Menschen wahr wird.'
Und er entsandte die Götter in alle Himmelsrichtungen, um den Menschen ihre neuen Mächte zu nehmen. Doch war es ihnen bis heute nicht möglich, allen Sterblichen die schwarze Zunge zu nehmen. Und so wurde das Volk der Druya geboren.
Der älteste Gott hob nun Darius empor und strafte ihn, als Mahnung an alle Sterblichen, die es wagten, die Götter zu betrügen, mit dem ewigen Unleben. Der von der schweren Reise verzehrte Leib des Mannes ging in die Welt der Toten ein und war auf immer dazu verdammt, in die unsere Welt zu blicken. Bis heute giert die verdammte Seele, die man den Wanderer nennt, nach dem Leben, dass er allzeit durch das schützende Netz der Magie, dass die Welten trennt, betrachten kann. Er irrt durch die Totenlande und sucht nach einem Schlupfloch, durch dass er zurückkehren kann.

„Denn er sinnt nach Rache.“ Der Großvater schloss das Buch leise und schaute seine Enkelin sorgenvoll an.
„War doch gar nicht so gruselig!“ sagte diese, obwohl er ihr leises Zittern wahrnahm.
„Es ist nur eine Geschichte. Hab keine Angst...“
„Ich habe keine Angst!“, schnappte Leila empört.
Der alte Mann lächelte. „Na dann wirst du ja bestimmt gut schlafen und einen wunderschönen Traum haben. Gute Nacht, meine Liebe!“ Und er legte das Buch beiseite, beugte sich zu ihr herab, küsste sie auf die Stirn und verließ das kleine Zimmer mit dem Kerzenstummel, der ihm während des Lesens Licht spendete.
Leila kuschelte sich in ihr Kissen und schlief wenig später in der Dunkelheit der Nacht ein.
Sie träumte von einem dürren alten Mann mit einer Kutte, der mit leeren Augen durch ein schimmerndes Netz nach ihr griff. Sie zitterte, als es in ihrem Zimmer kälter wurde.


mfG

Handeln macht Spass

Dienstag, 30. Dezember 2008 von peacemaker
Ave,

wie der Titel vielleicht vermuten lässt, habe ich am Handelssystem gearbeitet. Man kann nun schon komplett mit NPCs handeln, also Items verkaufen, kaufen, direkt-Tausch usw.
Das tauschen selber funktioniert im Moment nicht allzu besonders: man sieht das Inventar des Spielers und das des TauschNPCs, und schiebt nun die Items hin und her.

Um das ganze zu machen, musst ich die GUI um folgende Elemente erweitern:
  • Windows
  • Labels
  • neue Itembox
  • Buttons
Dabei gibt es jetzt auch ein Parent-System, d.H. alle Elemente gehören einem Fenster an, verschiebt man das Fenster, so werden die Elemente auch verschoben.
Die GUI sieht im moment noch sehr hässlich und billig aus, wird dies jedoch erstmal bleiben, da ich eigentlich nicht für GUI-Sachen verantwortlich bin. Aber sie funktioniert.
Später wird ja das ganze mit dem GUI-Itemlistsystem von Willi gemacht. Zur Erinnerung, hier noch einmal eine kleine Demo diesbezüglich.

Nun, wie funktioniert das Handelssystem? Der Preis JEDES Items basiert auf drei Werten: der Itemwert, der NPC-Verkaufswert, der NPC-Kaufswert.
Der Itemwert wird immer beim erstellen des Items angegeben. Natürlich ist er daraufhin veränderbar, wie auch fast alle anderen Werte der Items und co.
Nun kommen noch zwei weitere Faktoren auf Seiten des NPCs hinzu: der Verkaufs- und Kaufwert. Wozu? Das ganze ermöglicht, das die NPCs verschiedene Preise haben. Das ist eigentlich ganz sinnvoll, nehmen wir mal an der Spieler trifft einen Händler mitten im Nirgendwo, beispielsweise in einer Wüste, wo sonst keiner ist.
Da der NPC der einzige Händler weit und breit ist, verkauft er seine Items sehr teuer, und kauft Items sehr billig. Also wäre der Verkaufswert z.B. 2.0, der Einkaufswert 0.5. Will der Spieler ihm nun einen Krug, der eigentlich den Geld-Wert 15 hat verkaufen, bekommt aber nur 7.5. Will er nun eine Feldflasche mit Wasser, welche den Normalwert 5 hat, kaufen, müsste er 10 dafür hinblättern.
Auch diese Verkaufs- und Kaufwerte sind im Laufe des Spiels veränderbar. Es gibt öfters zuerst noch einen kleinen Dialog, in welchem man ein bisschen die Preise modifizieren kann. Z.B. wenn man dem Händler hilft, kriegt man alles billiger, usw.
So kann der Spieler mit ein bisschen Köpfchen und einigen Beziehungen viel Geld verdienen und die Items billig bekommen.

Zum Schluss noch ein Bild vom Tauschdialog.

user posted image

mfG

Inventar: Spieler und NPCs kriegen Taschen

Montag, 29. Dezember 2008 von peacemaker
Schon ist es etwas her, seit der letzte Eintrag gemacht wurde.
Mittlerweile könnt ihr euch das Gameplay-Video auch in etwas höherer Qualität anschauen. Hier noch einmal der Link.

Das wichtigste, was geschehen ist, ist das komplette Inventar-System. Es wurde so ziemlich komplett neu gemacht, vor allem der Core, also der Kern des ganzen Systemes wurde verändert.
Ach, noch eine Warnung, dieser Eintrag wird sehr... programmierspezifisch sein. Solche, die noch nie mit BlitzBasic gearbeitet haben, werden also kaum etwas verstehen.
Es gibt zwei verschiedene Grund-Charakter-Arten: Spieler und NPC. In Tehadon sind die NPCs alles "Type-Instanzen" der "Klasse" (Also des Types) CNpc.
Dies birgt sehr viele verschiedene Fields, es sind etwas mehr als 60. Darunter z.B. der Name, die Attribute, usw.
Der Spieler hingegen besitzt keine Instanz. Er ist eine Ansammlung aus globale Variabeln. Wieso? Wäre doch viel besser, das mit einer CNpc-Instanz zu machen.... Nun, es gibt viele Dinge, die für den Spieler nicht gebraucht werden. Das wären dann z.B. der Name, die nächste Route, der nächste Dialog, etc.
Das ganze war zugegeben eine Designentscheidung, die auch heute noch einige Nachwirkungen hat. Jetzt alles zu ändern... nein, das tu ich mir nicht an. Vielleicht später irgendwann, aber vorerst ist es nicht geplant.
Bei Subsystemen wie z.B. Inventar ist sowas sehr störend. Bzw. war es bisher. Inventare funktionierten simpel: es gab einen Array, der Handels der CItem-Instanzen beinhaltete. Es gab einen globalen Array für das Spielerinventar, und jeder NPC hatte noch ein Field welches wiederum auch so eine Liste war.
Wollte man Spieler und NPC-Inventar (z.B. beim Tauschen) anzeigen, so mussten komplett zwei verschiedene Systeme gemacht werden. Eine zum Anzeigen der Spieler Items, und eins für die NPCs.

Jetzt habe ich dieses Problem ganz simpel gelöst, ich hab Inventar nämlich einfach auf eine andere Ebene abstrahiert. Es gibt die "CInventory"-Klasse, wessen Instanz für je ein Inventar in der Welt stehen. Dabei ist egal ob Spieler oder NPC.
Diese beinhaltet einen Array für die Items, und noch die sonstigen relevanten Informationen. Dazu gibt es noch einige Funktionen, zum inserten der Items in ein Inventar, löschen, zählen, usw. usw.
All diese Funktionen kriegen einfach direkt die Instanz als Parameter. Das löst sogleich alle Probleme. Es gibt z.B. eine globale Variabel namens playerInventory.CInventory. Diese steht für das Spieler-Inventar. Dann hat jeder NPC ein Field namens inventory.CInventory. Dies steht für das NPC-Inventar.
Natürlich, es hört sich recht einfach an, aber es gab doch hier und da ein paar Problemchen. Jetzt funktioniert das ganze, und so kann man ohne irgenwdelchen Aufwand, auch problemlos das Inventar eines NPCs anzeigen. Z.B. wenn man einen NPC plündern will, erweist sich dies als nützlich.

Noch eine kleine Erzählung zum Schluss. Ich habe jetzt fast zwei Tage einen HDSS-Bug durchsucht, der ... wirklich sehr peinlich ist.
Mich hat es genervt, das IDEal mir immer die Variabel 'i' die ich immer zum iterieren bei For-Schleifen brauche, rot gehilightet, da sie nie deklariert war. Also hab ich sie als Global erklärt.
Jetzt ist etwas dummes beim Auftauchen von normalen Invokes, also Befehlen, passiert. Es wurde durch die Parameter iteriert, und dann für jeden Parameter rekursiv die Funktion compileLine () aufgerufen. Diese selber benutzte auch einige male i als iterator einer For-Schleife, sodass sich der Wert änderte. Und da die Variabel global war, übertrugen sich die Änderungen auch auf andere Funktionen.
Nun wurde die ganze zeit ein Parameter kompiliert, unaufhörlich. Dummer Noob-Bug Embarassed

mfG

Perceptions: die NPCs lernen zu sehen

Sonntag, 14. Dezember 2008 von peacemaker
Ich habe heute mal etwas getan, was ich schon länger tun wollte. Den komplette AI-Sourcecode durchschauen und aufräumen. Was ich da zu Tage befördert habe.... unglaublich. Naja, jedenfalls habe ich die NPC-"Klasse" mal aufgeräumt und ein bisschen schöner strukturiert. So fühlt man sich doch gleich viel wohler.
Dabei sind einige Systeme rausgeflogen, so z.B. das Alte Tagesablauf-System und noch einige anderen. Darunter das Perceptionssystem von früher. Solcher Code sollte verboten werden Laughing
Nun, desshalb habe ich dann auch angefangen, ein neues Perceptionsystem zu schreiben. Spieler - NPCs geht schonmal, NPCs - NPCs, der wirklich schwierige Part, ist zwar auch schon drin, nur ist das saumässig lansgam, weil da für jeden NPC, nochmal alle NPCs durchgegangen werden müssen.
Das sind bei 20 NPCs 400 Durchgänge.
Auch habe ich das Fraktionssystem gemacht. Das ist denkbar simpel: Es gibt Fraktionen, die haben einen Namen, ein Attribut für die politische Stärke und den Ruf des Spielers bei der Fraktion.
Dann gibt es noch die Beziehungen, die das Verhalten zwischen den NPCs - NPC oder NPC - Spieler verwalten. Gehört der Spieler Fraktion A an, und NPC der Fraktion B, und diese Fraktionen haben eine schlechte Beziehung, so greift der NPC gleich an.
Das Updaten dieses Systemes wird später in einem bestimmten Intervall getätigt, sodass da nicht jeden Frame immerzu diese Überprüfungen stattfinden müssen.
Ich habe Testweise eine HDSS-Event dazu gemacht: seeNpc. Dieses wird ausgeführt, wenn ein NPC, einen anderen sieht. Oder ein NPC den Spieler sieht. Es kriegt zwei Parameter. $this, die Instanz des NPCs, und $other, die Instanz des gesehenen NPCs oder des Spielers.
Es wird sowohl die Distanz, als auch der Winkel geprüft. Die Distanz ist variabel, so kann es NPCs geben, die kaum sehen, oder solche die sehr weit sehen.
Code: [AUSKLAPPEN]

void seeNpc ()
{
 if ($this == $test_npc)
 {
  message ($other->name);
 };
};


mfG

NPC Messagequeue

Samstag, 13. Dezember 2008 von peacemaker
Ave,

die erste Grundlage für die Restrukturierungen in der Kampf-AI steht: das Nachrichten-System der NPCs. Eigentlich gabs dieses System schon einmal, nur war es dazumal komplett anders. Alle Nachrichten, wurden in einem globalen Pool gesammelt. Jeder NPC ging nun alle Nachrichten durch, und suchte nach allen, die für ihn adressiert waren.
Mittlerweile haben sich so einige Nachteile gezeigt, sodass ich heute dieses System komplett neugeschrieben habe. Es funktioniert nun, mit einer Queue, einer Warteschleife.
Es gibt nun einen Sender, einen Receiver, einen Listener, der zugleich noch als Schnittstelle zur AI des NPCs dient.
Der Sender, bringt Funktionen, zum versenden von Nachrichten, von einem NPC, zu einem anderen. Der Receiver empfängt diese, und leitet sie dem Listener weiter. Dieser prüft die Nachrichten, und teilt sie gegebenfalls dem NPC mit.

Ein Beispiel: Ein Gruppenkampf ist in Gange. Es kämpfen z.B. fünf gegen fünf. Jeder NPC weiss immer, mit wem und gegen wem er kämpft. So wird die Zusammenarbeit ermöglicht. Betrachten wir den Kampf als einen Art Channel. Jeder neue Kämpfer, wird allen beteiligten mitgeteilt. Wie werden neue Kämpfer erkannt?
Dafür haben die NPCs das Perception-System. Dieses System sorgt dafür, das der NPC seine Umwelt immer erkennt. Mithilfe dieses Systemes, reagieren die NPCs auch sofort, wenn ein feindlicher NPC in Sicht tritt.
Also, kommt ein neuer, kampfbereiter NPC, mit gezogenem Schwert, realisiert einer der NPCs dies immer. Sofort wird eine Nachricht im Umlauf geschickt, sodass alle auch diesen NPC in ihrer Freund / Feind-Liste aufnehmen.

Also, der Kampf ist im Gange. Plötzlich merkt einer der NPCs, das seine Chancen schlecht sind. D.H. seine Lebenspunkte sind tief, die des Gegners hoch. Also sendet er allen NPCs, in seiner Partnerliste eine Nachricht vom Typen AI_MSG_FIGHT_NEED_BACKUP. Nun bemerkt der Listener jedes NPCs dies, und prüft, ob der jeweilige NPC, in der Lage ist, dem anderen zu helfen. Ist dies der Fall, wird alles nötige in die Wege geleitet, und der NPC kriegt Hilfe.
So wird das Verhalten des NPCs, durch diese Nachrichten teilweise verändert. Dies wird immer im Queuelistener entschieden, und ist auch situationsabhängig.

Ein handfestes Beispiel, das bereits funktioniert:
Code: [AUSKLAPPEN]

void sendMsgTest ()
{
 $arogar->sendMsg ($irothen, AI_MSG_TYPE_DO_HDSS_FUNC, fid(recMsg));
};

void recMsg ()
{
 message ($this->name) ; // Ausgabe ist "Irothen"
};

In diesem Fall, schickt Arogar Irothen eine Nachricht, die bewirkt, das beim updaten von Irothens AI, die HDSS-Funktion recMsg mit dem Parameter $this, der die NPC-Instanz beinhaltet, durchgeführt wird.
Der dritte Parameter von sendMsg () ist fid (recMsg). Das müsste doch eigentlich fref () sein, oder? Ja, eigentlich schon. Nur habe ich hier, als ich diesen Befehl einbaute, etwas nicht beachtet. fref () liefert intern einfach nur den Namen der Funktion. FID () hingegen, die ID, eine Zahl.
Das wäre schnell geändert, nur müsste ich noch einen Haufen weiterer Systeme anpassen, so z.B. das Quest- Item-System.

mfG

Gehe zu Seite Zurück  1, 2, 3, 4, 5 ... 10, 11, 12  Weiter