Beiträge von Der Mentat

    Invasionen starten


    Nachdem die obige Idee für die Programmierung eines Angriffs auf eine Stadt doch nicht so gut funktioniert, habe ich noch eine zuverlässigere Alternative gefunden: Mit dem Befehl "MoveHero( "Jazaz", 21, 163 )" kann man einen Helden (hier:Jazaz) an bestimmte Koordinaten auf der Karte schicken. Das Ziel muss nicht innerhalb eines Tagesmarsches erreichbar sein, das Script funktioniert auch über mehrere Züge:


    function NewDay()
    if GetDate(DAY) == 2 then
    DeployReserveHero( "Jazaz", 5,122, GROUND);
    sleep(2);
    EnableHeroAI( "Jazaz", nil );
    sleep(2);
    MoveHero( "Jazaz", 21, 163 );
    end;
    if GetDate(DAY) == 4 then
    if IsHeroAlive("Jazaz") == true then
    EnableHeroAI( "Jazaz", not nil );
    end;
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "NewDay" );



    Erklärung


    Die Invasion wird über einen Zeitauslöser initiiert. In der dritten Zeile wird der Held auf der Karte eingefügt (vgl. den letzten Abschnitt). Die darauffolgende sleep-Zeile sollte ausreichend Zeit geben, um diese Aktion auszuführen. Bevor man "MoveHero" verwenden kann, muss die KI-Kontrolle über den Held mit "EnableHeroAI( "Jazaz", nil )" ausgeschaltet werden.


    Als Zielkoordinaten, hier (21,163), kann man den Eingang einer Stadt wählen; das ist dann gleichbedeutend mit einem Angriff auf die Stadt. Auf meiner Karte brauchte der Held zwei Tagesreisen bis zum Ziel. Deshalb wird am Tag 4 überprüft, ob er noch am Leben ist, er also die Stadt erobert hat. Wenn das zutrifft, gibt "IsHeroAlive("Jazaz")" den Wert "true" aus und man kann in der nächsten Zeile die KI-Steuerung wieder aktivieren.


    Ein Held, der mit MoveHero gesteuert wird greift auch neutrale Kreaturen (und vermutlich feindliche Helden), die den Weg versperren, an. Nach der offiziellen Beschreibung des Scripts kann er aber keine Portale durchqueren oder Schiffe benutzen.

    Verwende mal den REGION_ENTER_AND_STOP_TRIGGER und teste ob der Held stehen bleibt, wenn er die Region betritt. Wenn er weiterläuft liegt der Fehler bei der Region oder beim Trigger, ansonsten in der messagebox

    function Held1( heroname )
    if GetObjectOwner(heroname) == 1 then
    AddHeroCreatures( heroname, CREATURE_ARCHANGEL, 1 );
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "region", nil );
    end;
    end;


    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "region", "Held1" );


    function Held2( heroname )
    if GetObjectOwner(heroname) == 2 then
    AddHeroCreatures( heroname, CREATURE_ARCHANGEL, 5 );
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "region2", nil );
    end;
    end;


    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "region2", "Held2" );


    Dieses Script habe ich inzwischen auch schon überprüft. Es gibt dem Held hier zwar nur ein paar Einheiten, aber mit Hochleveln müsste es natürlich genauso funktionieren.

    Bei mir gibts keine Probleme beim Entblocken von Regionen:


    function NewDay()
    if GetDate(DAY) == 2 then
    SetRegionBlocked("region",not nil, PLAYER_1);
    end;
    if GetDate(DAY) == 3 then
    SetRegionBlocked("region",nil, 1);
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "NewDay" );


    Das Script habe ich gerade getestet und wie geplant ist die Region am Tag 2 gesperrt und danch wieder frei. Vermutlich liegt der Fehler bei dir irgendwo in der Auslöserfunktion

    Ich würde einfach eine Region um die xy-Koordinate legen bzw. vor den Eingang der Stadt und das Ganze dann mit den Region-Triggern machen. Ich glaube, eine andere Möglichkeit gibts auch gar nicht. Höchstens wenn der Held die Stadt gerade erobert hat, könntest du auch noch den OBJECT_CAPTURE_TRIGGER verwenden.

    Das folgende Script mit zwei verschiedenen Triggern zur selben Region habe ich gerade ausprobiert und anscheinend führt er die Funktion einfach zweimal aus, jedenfalls bekommt der Held 2 Erzengel. Außerdem bleibt der Held wegen des ersten Triggers natürlich stehen.


    function Held( heroname )
    AddHeroCreatures( heroname, CREATURE_ARCHANGEL, 1 );
    end;


    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "region", "Held" );
    Trigger( REGION_ENTER_WITHOUT_STOP_TRIGGER, "region", "Held" );

    Zitat

    Original von Searphita
    könnte man das skript für "Neuen Helden einfügen" irgendwie so verändern, dass sich die armee dem random-spieler anpasst bzw. wäre es möglich, mehrere helden in die liste zu packen und in das skript ein bedingung einzu bauen, die abhängig vom volk des spielers nur einen der 8 helden aus der Reserve Heroes List auf die karte schickt?


    Das einzige, was mir dazu einfällt, ist ein etwas aufwändigeres Script. Ich vermute, du hast in den Player Properties Generate Hero In Town eingestellt. Dann könntest du eine Variable HeldTyp erstellen sowie eine Region direkt vor dem Stadteingang. Mit einem REGION_ENTER_..._TRIGGER kannst du dann den Namen des Starthelden abfragen, und je nach Name die Variable anders setzen. Also ungefähr so:


    HeldTyp = 0;


    function Typ( heroname )
    if ( heroname == "Orrin" ) or ( heroname == "Nathaniel" ) or ( heroname == "Ving" ) or ( heroname == "Sarge" ) or ( heroname == "Mardigo" ) or ( heroname == "Maeve" ) or ( heroname == "Brem" ) or ( heroname == "Christian" ) then
    HeldTyp = 1;
    end;
    if heroname == []


    Trigger( REGION_ENTER_WITHOUT_STOP_TRIGGER, "rtyp", nil );
    end;
    end;
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rtyp", "Typ" );


    Die obigen Heldennamen sind dabei die Scriptnamen der Ritter, also Dougal, Ellaine usw. Hat der Held den Scriptnamen eines Zauberers, setzt , man z.B. HeldTyp = 2


    Dann kannst du mit Fallunterscheidungen für die verschiedenen Werte von HeldTyp festlegen, welche Armee erscheinen soll.



    Zitat

    wenn ich über map properties ein script gemacht habe, mache ich dann das nächste script einfach darunter weiter?


    Mehrere Scripts kann man ganz normal untereinander schreiben. Es ist auch ganz nützlich sich mal ein paar fertige Scripts aus den Kampagnen anzuschauen. Damit man die mit dem Editor öffnen kann, muss man sie sich aber erst hier als h5m-Datei runterladen.

    Zitat

    Original von Searphita
    z.b. so was wie:
    - event
    - via "entry point" einen helden zu einem festen zeitpunkt die karte betreten lassen (z.b. monat 2 woche 1 tag 1)


    In Heroes 5 geht das auf jeden Fall und steht (inzwischen) in der Scriptliste. Die von Novarius vorgeschlagene Karawane wäre auch möglich mit CreateCaravan. Zu einem Script, das die Rasse des Spielers ermittelt, habe ich aber nichts gefunden.


    Ansonsten könnte das folgende Script vielleicht funktionieren:


    Res = 0;


    function NewDay()
    if GetDate(DAY) == 57 then
    DeployReserveHero( Deleb, 85,80, GROUND);
    if GetPlayerResource(PLAYER_1, GOLD) >=10000 then
    Res = GetPlayerResource( PLAYER_1, GOLD )-10000;
    sleep(2);
    SetPlayerResource( PLAYER_1, GOLD, Res);
    AddHeroCreatures( Deleb, CREATURE_PHOENIX, 2 );
    end;
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, NewDay );


    Der Spieler hat hier aber nicht die Wahl, ob er die Phönixe will oder nicht. Möglich wäre noch, ein Gebäude zu erstellen, in dem der Spieler die Kreaturen abholen kann; wenn er das nicht macht, muss er eben auch nicht zahlen.

    Manuelle Zieleinstellungen


    Bei Szenarios möchte man normalerweise komplexere Ziele erstellen als die Standardeinstellung "Alle Gegner besiegen". Mit Hilfe des Map-Properties-Tree hat man unter Objectives die Auswahl zwischen einer ganzen Menge anderer Ziele, die man auch ohne zusätzliche Scripts verwenden kann. Wie das ganau geht, wird ausführlich im Theorie-Handbuch des Editors beschrieben. (Das befindet sich im Startmenü unter Ubisoft > Tribes of the East > Andere Handbücher > Handbuch zum Karteneditor > Editor-Theorie.) Ein gutes Beispiel dazu mit Graphiken gibt's auch in diesem Thread von Lya.


    Bei der Bearbeitung eines Ziels im Properties-Tree kann man unter "Kind" auch "OBJECTIVE_KIND_MANUAL" wählen. Wir verwenden diese Einstellung, um folgendes Ziel zu erstellen: Der Spieler soll innerhalb von zwei Wochen die Stadt "Minas Morgul" einnehmen, sonst ist das Ziel verfehlt.


    Dafür wählen wir zuerst die gewünschte Stadt an und geben ihr (im Properties-Tree der Stadt) den Namen MinasMorgul. Wir gehen wieder zurück zum Map-Properties-Tree (z.B. über View in der Menüleiste) und geben dem Ziel den Namen Prim1. Für die Punkte "Caption" und "Description" kann man einen passenden Text formulieren.
    Nun bearbeiten wir das Script:


    function Morgul( oldowner, newowner )
    if newowner == PLAYER_1 then
    SetObjectiveState( 'Prim1', OBJECTIVE_COMPLETED );
    end;
    end;


    function NewDay()
    if ( GetDate(DAY) == 15 ) and ( GetObjectiveState( 'Prim1' ) == OBJECTIVE_ACTIVE ) then
    SetObjectiveState( 'Prim1', OBJECTIVE_FAILED );
    end;
    end;


    Trigger( OBJECT_CAPTURE_TRIGGER, "MinasMorgul", "Morgul" );
    Trigger( NEW_DAY_TRIGGER, "NewDay" );



    Erklärung


    Um zu überprüfen, wann die Stadt Minas Morgul erobert wird, benutzt man den
    OBJECT_CAPTURE_TRIGGER. Dieser gibt immer auch den alten und neuen Besitzer aus, so dass man diese Werte als Variablen in der zugehörigen Funktion verwenden kann (so wie z.B. der REGION_ENTER_AND_STOP_TRIGGER immer den Heldennamen ausgibt, der gerade die Region betritt).


    In der zweiten Zeile wird getestet, ob der neue Besitzer der Spieler 1 (also der menschliche Spieler) ist, dann wird mit "SetObjectiveState" das Ziel Prim1 auf "erfüllt" gesetzt. Diesen Teil der Zieleinstellungen hätte man auch ohne Script über den Properties-Tree erreichen können, indem man unter Kind OBJECTIVE_KIND_CAPTURE_OBJECT wählt. Wir fordern allerdings noch die zusätzliche Bedingung, dass der Spieler für diesen Auftrag nur zwei Wochen Zeit hat. Dafür braucht man die zweite Funktion.


    NewDay() untersucht, ob das Ziel Prim1 am Tag 15 noch aktiv, also noch nicht abgeschlossen ist. In disem Fall wertet es das Ziel als verfehlt. In den letzten beiden Zeilen stehen noch die Trigger. Der OBJECT_CAPTURE_TRIGGER ordnet dem "Objekt" MinasMorgul die Funktion Morgul zu.



    Objektbesitzer ändern


    Mit "SetObjectOwner" kann man einem Objekt, z.B.einer Stadt einen neuen Besitzer zuteilen. In diesem Beispiel geben wir der Stadt in ihrem Properties-Tree (siehe oben) den Namen MinasTirith. Bei einem Zeitauslöser sieht das Ganze so aus:


    function NewDay()
    if GetDate(DAY) == 9 then
    SetObjectOwner( 'MinasTirith', 0 );
    SetObjectOwner( 'MinasTirith', 5 );
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "NewDay" );


    Die Stadt wird dann am Tag 9 an Spieler 5 übergeben. In Zeile 3 wird dabei die Stadt zuerst neutral gemacht. Manchmal funktioniert so ein Script auch ohne diese Zeile, manchmal braucht man diesen Zwischenschritt selstamerweise aber auch.


    Statt dem Zeitauslöser kann man den Befehl auch in eine manuelle Zieleinstellung schreiben, so dass sich die Stadt anschließt, nachdem der Spieler dieses Ziel erreicht hat. Das Script aus dem obigen Abschnitt könnte man z.B. erweitern zu


    function Morgul( oldowner, newowner )
    if newowner == PLAYER_1 then
    SetObjectiveState( 'Prim1', OBJECTIVE_COMPLETED );
    SetObjectOwner( 'MinasTirith', 0 );
    SetObjectOwner( 'MinasTirith', 1 );
    end;
    end;


    Trigger( OBJECT_CAPTURE_TRIGGER, "MinasMorgul", "Morgul");




    Neuen Helden einfügen


    Man kann für jeden Spieler einzelne Helden in eine Reserveliste eintragen und die dann zu einem bestimmten Zeitpunkt im Spiel auftauchen lassen. Die Liste findet man in den Map Properties unter Player Properties. Dort wählt man einen Spieler aus und klickt dann bei der Reserve Heroes List auf Add. Auch Armee, Fähigkeiten des Helden usw. können hier eingestellt werden.


    Um den Held im Spiel auftauchen zu lassen, verwendet man die Funktion DeployReserveHero:


    function NewDay()
    if GetDate(DAY) == 2 then
    DeployReserveHero( "Deleb", 85,80, GROUND);
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "NewDay" );


    "DeployReserveHero" hängt von vier Variablen ab: Die erste ist der Scriptname des Helden aus der Reserveliste, der auftauchen soll (hier: Deleb); die beiden folgenden Zahlen stehen für die Eintrittskoordinaten und im letzten Feld wählt man je nach Ebene GROUND oder UNDERGROUND.


    Soll der eingetroffene Held eine bestimmte Stadt angreifen, so sollte man das eigentlich über den Befehl


    SetAIHeroAttractor("MinasTirith", "Deleb", 2)


    steuern können. Bei mir hat das leider nicht funktioniert, was entweder an einem Fehler in meinem Script liegt oder daran, dass diese Priorisierung zu schwach ist. Eine sicherere Möglichkeit, den Helden zu einem Angriff zu veranlassen, ist es den Held einem Spieler zuzuordnen, der genau eine Stadt und keine weiteren Helden hat, wenn das von der Karte her möglich ist. Sobald der neue Held auftaucht, nimmt man ihm mit SetObjectOwner die Stadt weg. Der Held hat dann nur sieben Tage Zeit, eine neue Stadt zu erobern und wird praktisch sofort wie gewünscht die nächstgelegene Stadt angreifen, auch wenn seine Armee eigentlich unterlegen ist.

    Gebäude umfunktionieren


    Beispiel 1: Magischer Schrein für Level 5-Zauber


    Ziel ist es, ein Gebäude zu erstellen, das jedem vorbeikommenden Held einen Level 5-Zauber, genauer den Zauber "Phönix beschwören" lehrt. Wir modifizieren dafür eine "School of Magic", also das Gebäude, in dem die Helden normalerweise entweder Zauberkraft oder Wissen steigern können.
    Wenn man die "School of Magic" anwählt, sieht man auf der linken Seite des Bildschirms eine Liste mit den "Properties" (ich glaube beim ersten Öffnen des Editors wir diese Liste nicht automatisch angezeigt; man muss dann evtl. erst auf den Menüpunkt View > Map Properties Tree gehen). Wir fügen unter Name den Text Magierturm ein; auf die Bezeichnung kann man sich dann im Script beziehen. Letzteres sieht dann so aus:


    function Turm(heroname)
    if GetHeroSkillMastery( heroname, 12) ==3 then
    TeachHeroSpell( heroname, 235);
    MessageBox("Maps/SingleMissions/Test/Phoenix.txt" );
    else
    MessageBox("Maps/SingleMissions/Test/Skill.txt" );
    end;
    end;


    SetObjectEnabled('Magierturm',false);
    Trigger(OBJECT_TOUCH_TRIGGER, 'Magierturm', 'Turm');



    Erklärung


    Zuerst definieren wir die Funktion, die ausgeführt werden soll, wenn ein Held das Gebäude betritt. Dabei wird in der zweiten Zeile überprüft, ob der Held meisteliche Beschwörungsmagie beherrscht: Die 12 ist die ID für beschwörende Magie und 3 steht für meisterliche Stufe. Mit dem Befehl TeachHeroSpell erhält der Held einen Zauber, in diesem Fall "Phönix beschwören" mit der ID 235. Die parallel erscheinende Messagebox enthält die Nachricht, dass der Held den Zauber gelernt hat. Hat der Held keine meisterliche Beschwörungsmagie, dann greift der "else"- Absschnitt mit der Textbox-Information, dass dem Held der erforderliche Skill fehlt.


    Mit "SetObjectEnabled('Magierturm',false);" erreicht man, dass die übliche Funktion einer "School of Magic" - also die Wahl zwischen Zauberkraft und Wissen - abgeschaltet wird, so dass man sie mit Hilfe des nachfolgenden Triggers durch die Funktion "Turm" ersetzen kann.



    Beispiel 2: Dunkelmagie bei einer Hexe lernen


    Wir wollen, dass jeder Held bei einer bestimmten Hexenhütte die Fähigkeit Dunkelmagie lernen kann. Da Hexenhütten auf das Anwählen mit der Leertaste nicht reagieren, muss man dies über ein Script steuern. Der Fall ist allerdings schwieriger als dass obige Beispiel, denn man muss sicherstellen, dass ein Held die Hexe nicht mehrmals besuchen kann und so nacheinender den Skill von einfach auf geübt und dann auf meisterlich steigert.
    Zuerst muss man der Hexe wieder einen Namen geben. In diesem Fall nennen wir das Gebäude einfach Huette. Im Script schreibt man


    visitedHeroes={}


    function Hekate(heroname)
    if not visitedHeroes[heroname]==1 then
    GiveHeroSkill( heroname, 10)
    visitedHeroes[heroname]=1;
    sleep(2);
    if HasHeroSkill( heroname, 10) == true then
    MessageBox("Maps/SingleMissions/Test/HDunkel.txt" );
    else
    MessageBox("Maps/SingleMissions/Test/HSkill.txt" );
    end;
    else
    MessageBox("Maps/SingleMissions/Test/HBesucht.txt" );
    end;
    end;


    SetObjectEnabled('Huette',false);
    Trigger(OBJECT_TOUCH_TRIGGER, 'Huette', 'Hekate');



    Erklärung


    Mit "visitedHeroes" definiert man eine Variable, in die dann die Heldennamen eingetragen werden, die die Hexe Hekate schon besucht haben. Ist das der Fall, wird in Zeile 3 eine 1 ausgegeben, falls nicht, erhält der Held in Zeile 4 über "GiveHeroSkill" die Fähigkeit Dunkelmagie mit der ID 10. Anschließend wird der Held in die visitedHeroes-Liste eingetragen.


    Eine Veränderung tritt natürlich nur dann ein, wenn der Held noch Dunkelmagie lernen kann und nicht schon sechs andere Primärskills besitzt. Deshalb soll mit "HasHeroSkill" geprüft werden, ob das Erlernen auch erfolgreich war. Der sleep(2)-Befehl davor hat den Zweck, dass der Held sozusagen genug Zeit hat den Skill zu lernen, bevor er abgefragt wird. Besitzt der Held nun Dunkelmagie, wird die Erfolgsmeldung "HDunkel.txt" angezeigt, wenn er dagegen schon zu viele andere Fähigkeiten hat, erhält er die negative Meldung "HSkill.txt".


    Der zweite else-Teil bezieht sich schließlich auf den Fall, dass der Held schon zum zweiten Mal bei Hekate auftaucht; er bekommt dann nur die Nachricht "HBesucht.txt".
    (Nicht abgedeckt wird die Situation, das deshalb nichts gelernt werden kann, weil der Held schon den meisterhaften Grad in Dunkelmagie beherrscht. Über GetHeroSkillMastery kann man dazu ggf. noch einen weiteren if-Abschnitt einfügen.)


    Die Grundideen für dieses Script stammen übrigens wieder von makrise, genauer von seinem library-Script.

    Dieser Thread ist für Fragen zur Scriptliste gedacht.



    Also im Prinzip sind das zwei verschiedene Fragen. Der Unterschied zwischen dem REGION_ENTER_AND_STOP_TRIGGER und dem REGION_ENTER_WITHOUT_STOP_TRIGGER besteht glaube ich nur darin, dass der Held im ersten Fall in der Region automatisch stehenbleibt (also stoppt) und im zweiten Fall der Held normal weiterläuft. Allerdings habe ich bisher immer nur den ersten Trigger verwendet.


    Das Löschen des Triggers in der dritten Zeile kann man dann eigentlich in beiden Fällen weglassen, wenn man will, dass die Funktion immer wieder ausgeführt wird. Das STOP dürfte sich nur auf den Helden und nicht auf den Trigger beziehen.

    Ressourceneinstellungen


    Das Einstellen der Startressourcen ist eines der einfachsten Scripts. Es besteht nur aus der Zeile


    SetPlayerStartResources( PLAYER_1, 10, 10, 10, 10, 10, 10, 10000);


    Die erste Variable gibt den Spieler an, der diese Startessourcen erhalten soll. Die folgenden Zahlen beschreiben die Menge von Holz, Stein, Quecksilber, Kristall, Schwefel, Edelsteinen und schließlich Gold. Wichtig ist das Semikolon am Ende des Befehls.
    Etwas schwieriger ist es, die Rohstoffe später um einen bestimmten Betrag zu erhöhen (siehe weiter unten).




    Regionen blockieren


    Oft ist es wichtig, dass ein gegnerischer Held, der in einer Stadt stationiert ist, diese nicht verlassen kann. Dazu erstellt man direkt vor dem Stadteingang eine Region, die hier den Namen "rbarierre" besitzen soll. (Wie man Regionen erstellt, kann man im Editor-Praxis-Handbuch finden, das man hier runterladen kann.) Ist der Gegner Spieler 2, dann verwendet man das Script


    SetRegionBlocked("rbarriere",not nil, PLAYER_2);


    Setzt man


    SetRegionBlocked("rbarriere",not nil, -1);


    so ist die Region für alle Spieler unpassierbar.


    SetRegionBlocked("rbarriere", nil, PLAYER_2);


    sollte die Blockierung wieder aufheben. (Habe ich aber noch nicht ausprobiert.)




    Regionale Auslöser


    Beispiel 1: Wettrennen


    Wir wollen erreichen, dass der erste Held, der die Region "rziel" erreicht, als Belohnung 10 Erzengel erhält. Dazu muss man eine Funktion definieren, die dann durch einen Trigger ausgelöst wird:


    function Ziel(heroname)
    AddHeroCreatures( heroname, CREATURE_ARCHANGEL, 10 );
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rziel", nil);
    end;


    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rziel", "Ziel" );



    Erklärung


    In die erste Zeile schreibt man also "function" und dahinter einen beliebigen Namen (hier: Ziel, der Name sollte aber kein ö, ü oder so enthalten). Die Funkton hängt von der Variable "heroname" ab, in die das Script automatisch den Namen des Helden einsetzt, der die Region gerade betritt. In der zweiten Zeile formuliert man den gewünschten Befehl, der dem Held die Kreaturen gibt. Die IDs wie CREATURE_ARCHANGEL findet man über das Startmenü unter


    Ubisoft > Tribes of the East > Andere Handbücher > Handbuch zum Karteneditor > IDs für Scripte


    Der letzte Parameter (hier: 10) gibt die Anzahl der Kreaturen an. Die dritte Zeile bewirkt, dass die Funktion nur einmal ausgelöst wird, d.h. der Held kann nicht unbegrenzt Erzengel sammeln, indem er immer wieder die Region betritt. Der Befehl in der fünften Zeile bewirkt schließlich, dass beim Betreten der Region "rziel" die Funktion "Ziel" ausgeführt wird.



    Beispiel 2: Festgelegter Held


    Soll nur ein bestimmter Held die Erzengel erhalten können, so ersetzt man obiges Script durch


    function Ziel( heroname )
    if heroname == "Wulfstan" then
    AddHeroCreatures( heroname, CREATURE_ARCHANGEL, 10 );
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rziel", nil );
    end;
    end;


    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rziel", "Ziel" );


    Um die IDs für Helden wie hier Wulfstan, (die nicht immer mit den Heldennamen im Spiel übereinstimmen) zu bekommen, wählt man den Held im Editor mit der Leertaste an; dort findet man den Namen unter "Settings".




    Temporäre Auslöser


    Mit der Funktion "GetDate(DAY)" kann man Ereignisse zu festgelegten Zeitpunkten eintreten lassen.


    function Zeit()
    if GetDate(DAY) == 3 then
    Invasion()
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "Zeit" );


    startet z.B. die (getrennt zu definierende) Funktion "Invasion()" am Tag 3.



    Beispiel: Steuereinnahmen


    Wir wollen erreichen, dass der Spieler 1 nach einem Monat durch Steuereinnahmen zusätzlich 10000 Gold bekommt. Da es keinen Befehl der Form AddResource gibt, muss man eine Variable "Res" einfügen, die die Menge das gerade vorhandenen Goldbestands angibt und zu dieser 10000 hinzufügen:


    Res = 0;


    function Steuer()
    if GetDate(DAY) == 29 then
    Res = GetPlayerResource( PLAYER_1, GOLD )+10000;
    sleep(2);
    SetPlayerResource( PLAYER_1, GOLD, Res);
    Trigger( NEW_DAY_TRIGGER, nil );
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "Steuer" );



    Erklärung


    In der ersten Zeile wird die Variable "Res" definiert und gleich 0 gesetzt. Mit der
    Funktion "GetPlayerResource( PLAYER_1, GOLD )" wird am Tag 29 bestimmt, wie viel Gold Spieler 1 besitzt und "Res" wird um 10000 höher festgesetzt. Der "sleep(2)"- Befehl soll sicherstellen, dass dieser Wert erst berechnet wird, bevor die nächsten Schritte im Script ausgeführt werden. Zeile 6 setzt den Goldbestand dann auf den berechneten Wert. Mit "Trigger( NEW_DAY_TRIGGER, nil );" wird die Möglichkeit von Zeitauslösern abgeschaltet; diese Funktion darf also erst in den "spätesten" Zeitauslöser eingebaut werden.




    Nachrichten-Boxen


    Um in einem Szenario Pläne, Aufträge oder allgemein die Handlung voranzutreiben, braucht man meistens Textboxen, die zu bestimmten Zeiten oder nach bestimmten Ereignissen auftauchen. Dazu verwendet man folgendes Script:


    function Warnung()
    if GetDate(DAY) == 2 then
    MessageBox("Maps/SingleMissions/Gantrithor/Warnung.txt" );
    Trigger( NEW_DAY_TRIGGER, nil );
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, "Warnung" );


    Es wird dann am Tag 2 die Textnachricht, die unter "Warnung.text" im Ordner


    HeroesV\Editor\H5MMods\<Kartenname>\Maps\SingleMissions\<Kartenname>\


    abgespeichert ist, angezeigt. Den Pfad ab "Maps" schreibt man in die Klammer hinter "MessageBox". Die Nachricht muss mit Unicode-Codierung abgespeichert werden, damit das Ganze funktioniert. Eine noch genauere Beschreibung, wie diese Textdateien erstellt werden können, gibt euch makrise.



    So, das reicht für heute. Beim nächsten mal erklär ich euch, wie man Gebäude umfunktionieren kann und Invasionen programmiert. :D

    Bekanntlich ist es mit dem Editor ziemlich schwierig spezielle Missionen zu erstellen, bei denen man z.B. eine Stadt gegen mehrere Invasionsarmeen verteidigen muss, die zu genau festgelegten Zeitpunkten auftauchen sollen. Oder man will ein Szenario erstellen, bei dem sich - zunächst feindliche - Städte erst anschließen, nachdem man bestimmte Aufträge erfüllt hat.


    Gerade für Einsteiger ist es deshalb sicher nützlich, ein paar Beispiele für funktionierende Scripts zu sehen und genau dafür ist dieser Thread gedacht. Wer also schon ein paar Scripts erstellt hat, kann die hier reinstellen


    Bitte keine Fragen hier posten!
    Wenn ihr Fragen habt dann könnt ihr sie hier stellen!

    Vielleicht hilft dir die Anleitung von makrise bei den Message-Boxen. Am wichtigsten ist der richtige Ordner für die Erstellung der Textdatei


    HeroesV\Editor\H5MMods\<Kartenname>\Maps\Singleplayer\<Kartenname>\


    das Abspeichern mit Unicode:


    Zitat

    Original von makrise
    Wir klicken auf eine freie Stelle in dem Ordner und wählen "Neu\Textdokument" aus. Wir benennen die "Neu Textdatei.txt" um, etwa in "hallo_welt.txt". Wir doppelklicken auf die Datei, um sie im Windows-Editor(notepad) zu Ãffnen. Jetzt müssen wir den Text schreiben, der nachher in der Nachricht angezeigt wird. Für den Anfang reicht etwa "Hallo Welt!". Im Datei Menü wählen wir "Speichern unter..." aus.(Wichtig: beim ersten Speichern der neuen Datei darf nicht nur "Speichern" benutzt werden, sonst funktioniert es nicht.) Im Fenster "Datei speichern unter" wählen wir die Textdatei, die wir erstellt haben aus. Jetzt muss in dem Auswahlfeld neben "Codierung:" der Wert "Unicode" eingestellt werden. Nach dem Klick auf Speichern muss nur noch die Frage zum Ãberschreiben der Datei bestätigt werden.


    und, dass der Editor geöffnet ist, während man die Texte erstellt.



    Ich verstehe nur nicht ganz, warum der LevelUpHero-Befehl bei dir nicht funktioniert. Bei mir gabs da überhaupt keine Probleme. ?(

    Es ist fast unvermeidlich, dass man jedes Script mindestens dreimal ausprobieren muss, bis es funktioniert. Ich teste meistens jede Funktion einzeln, weil oft das ganze Script nicht mehr geht, wenn ein Teil falsch ist (, wenn man z.B. einen Namen falsch schreibt.) :-#


    Zu deinem Script: Den LevelUp Teil brauchst du nicht in eine Funktion schreiben, weil er nicht durch einen Trigger ausgelöst wird. Ich hab gerade das folgende Script ausprobiert und bei mir hats funktioniert:


    LevelUpHero("Jazaz");


    Außerdem würde ich hinter jede Zeile einen Strichpunkt setzten, auch innerhalb einer Funktion.
    Für den zweiten Teil gibt es in der praktischen Einführung ein ähnliches Script, das du einfach mal direkt kopieren kannst (mit Copy + Paste, um Rechtschreibfehler zu vermeiden, nur den Region- und Heldennamen ändern)


    function Meeting( heroname )
    if heroname == "Christian" then
    AddHeroCreatures( heroname, CREATURE_ARCHANGEL, 1 );
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "meeting", nil );
    end;
    end;
    Trigger( REGION_ENTER_AND_STOP_TRIGGER, "meeting", "Meeting" );


    In deiner ersten Version könnte das Problem z.B. darin liegen, dass du zwischen heroname und der jeweils ersten Zahl kein Komma eingefügt hast.
    Einfach immer wieder anpassen, umschreiben und ausprobieren. Irgendwann funktionierts dann normalerweise schon :aua:

    Ich hab zwar den Vorschlag von Novarius nicht ausprobiert, aber man kann ein Script für zeitlich ausgelöste Textfenster auch über den MessageBox-Befehl konstruieren. Das folgende Script funktioniert jedenfalls bei mir:



    function Warnung()
    if GetDate(DAY) == 2 then
    MessageBox(Maps/SingleMissions/Gantrithor/warnung.txt );
    Trigger( NEW_DAY_TRIGGER, nil );
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, Warnung );



    Dadurch wird am Tag 2 die Nachricht angezeigt, die ich unter warnung.txt gespeichert habe. Zum Erstellen solcher Nachrichtentexte gibts ja schon ausführliche Beschreibungen (z.B. hier von makrise). Wichtig ist v.a. dass der Editor geöffnet ist, während man die Textdatei erstellt!


    Da das Erstellen von Textboxen sehr fehleranfällig ist, ist es wahrscheinlich sinnvoll, den Zeitauslöser zuerst mit einem einfacheren Befehl zu testen, z.B.



    function Warnung()
    if GetDate(DAY) == 2 then
    SetPlayerResource( PLAYER_1, GOLD, 10000 );
    Trigger( NEW_DAY_TRIGGER, nil );
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, Warnung );



    Für Tag 1 hat der Auslöser bei mir übrigens nicht funktioniert - kann aber sein, dass das an einem anderen Problem lag ?(
    Will man mehrere Nachrichten einbauen, sieht das Ganze so aus:



    function Nachricht()
    if GetDate(DAY) == 2 then
    MessageBox("Maps/SingleMissions/Gantrithor/mission.txt" );
    end;
    if GetDate(DAY) == 3 then
    MessageBox("Maps/SingleMissions/Gantrithor/warnung.txt" );
    Trigger( NEW_DAY_TRIGGER, nil );
    end;
    end;


    Trigger( NEW_DAY_TRIGGER, Nachricht );



    Die Zeile Trigger( NEW_DAY_TRIGGER, nil ); steht also erst im letzten if-Abschnitt.

    Tobius: Ich stimme dir zu, aber ich habe das Gefühl. dass wir diese Ergebnisse schon früher hatten, wenn auch nicht mit dieser Herleitung. ;)


    Als Ordnungsfanatiker muss ich das Ganze mal in eine Struktur zwängen: :besserwisser:
    Wir können einem Spiel aktive und passive Funktionen zuschreiben. Aktive Funktionen sind solche, bei denen der Spieler selbst handeln muss, weil hier der Erfolg motiviert; es geht um die von Tobius beschriebenen nutzbringenden Aktionen. Bei passiven Funktionen motiviert allein das Erleben, auch ohne Aktivität des Spielers. Hier sind v.a. grafische Effekte oder auch die Entwicklung der Charaktere innerhalb der Kampagnenhandlung relevant. Schließlich kann es auch noch Mischformen geben, etwa wenn aktive Handlungen direkt eine grafische Funktion oder die Gestaltung der Geschichte zum Ziel haben.


    Wenn man sich zunächst rein auf die aktive Komponente beschränkt, kann man die Trennung zwischen Einzel- und Mehrspieler in der Tat vernachlässigen für den passiven Anteil halte ich sie dagegen für sehr wichtig. Das hat ja auch grumpy schon angesprochen, indem er zwischen Szenarios und freiem Spiel unterschied.


    Nun zu den konkreten Zielen im reinen aktiven Anteil: Wie Tobius schon beschrieben hat, braucht der Spieler eine große Anzahl von Möglichkeiten/ Freiheiten für nutzbringende Aktionen. Diese haben aber nicht primär den Zweck, Abwechslung zu erzeugen! Die Funktion von Abwechslung kann durch Freiheiten natürlich auch geschaffen werden, aber dies ist viel mehr für den passiven Anteil wichtig, denn da braucht man möglichst gebalancte Vielfalt, um verschiedene gleichwertige Optionen ausprobieren zu können. Im erfolgsorientierten Fall ist dagegen Denkleistung erwünscht, d.h. es gibt innerhalb der Freiheiten bessere und schlechtere Alternativen, die durch Analyse der Situation herausgefunden werden können.


    Der in diesem (reinen aktiven) Bereich zweite wichtige Punkt ergibt sich direkt aus der Situationsabhängigkeit und wurde ja auch schon von Tobius angesprochen:

    Zitat

    da man nicht gegen sich selbst (bzw. das Spiel selbst) spielt, sondern gegen (menschliche oder simulierte) Gegner, stehen (bestimmte) Aktionen notwendigerweise in Beziehung [...] zu Gegenspielern und damit deren Zuggestaltung


    Freiheit erlaubt zwar qualitativ eine komplexe Analyse von Problemen, aber nicht unbedingt quantitativ eine hohe Zahl. Wenn man z.B. 12 Einheiten zur Auswahl hat, von denen eine Kombination eindeutig als das beste bestimmt werden kann, wird es wahrscheinlich eine Zeit dauern bis man diese gefunden hat, aber anschließend sind hier keine Überlegungen mehr erforderlich. Man braucht also variierende Situationen, unter denen jeweils andere Aktionen den meisten Nutzen bringen. Diese Bedingungen können durch den Gegenspieler gegeben sein, aber ebenso auch durch Karteneigenschaften.
    Was die Bedingungen betrifft, die bestimmte Möglichkeiten erst ermöglichen, so lassen sich die ebenfalls in vom Spieler beeinflussbare Faktoren (-> Freiheiten) oder äußere Faktoren (der Karte, des Gegners, der grundsätzlichen Spielregeln) unterteilen.


    Wie gut sich das dann anwenden lässt, könnte man nun in den einzelnen Spielbereichen überprüfen. Z.B. verläuft der Bau von Kreaturenbehausungen, Wirtschaftsgebäuden und Befestigungsanlagen in Heroes mehr oder weniger parallel und meistens nach dem gleichen Schema ab. Es wäre also sicher sinnvoll, hier einen situationsabhängigeren Stadtaufbau zu fördern.