Banner left   Banner center   Banner right

Germanenglish Home · News · Diary · Screenshots · Documentation (Wiki) · Downloads · Guestbook · Forum

Home · Benutzer registrieren · Suchen · Statistik · FAQ · Benutzerliste

Zur Zeit online: keiner ausser dir

 X-Force - Fight For Destiny - Forum —› X-Skript / Developer-Pack —› TGameFigure

Autor Mitteilung
verfasst am: 29.11.2011, 02:33 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
Vielleicht kann mir hier jemand bei helfen?

Ich will einen Wert von einem Script in ein anderes schleusen. Über eine SpielGlobale Variable zu jonglieren, will ich erstmal vermeiden, da unsauber und ich mich dann auch noch mit einem Array dort rumschlagen muss, wo ich nebenbei dann auch noch die entsprechende Referenzen auf die eigentlichen Tfigures mit verwalten müsste.

Evtl. könnte ich einen der Writeable-Werte in TGameFigure missbrauchen?

procedure SetAIScript(ScriptName: String);
Script verdrehen, kommt nicht in Frage. Damit verliere ich den Mechanismus von Scriptglobalen Variablen.

procedure UserCall;
was kann man damit eigentlich machen, keine Parameterübergabe, wozu soll die dann gut sein?

property VisionRange: LongInt; read / write;
Hier evtl.? Ich könnte die Range auf irgendwelche extremen Werte setzen, um damit den anderen Script eine Botschaft zu schicken, das andere Script müsste dann natürlich den Wert wieder auf Original biegen.

property HP: LongInt; read / write;
property MaxHP: LongInt; read / write;
property ReservedTimeUnits: LongInt; read / write;
property TimeUnits: LongInt; read / write;
property MaxTimeUnits: LongInt; read / write;
Die 5 Werte würde ich dafür eher ungerne anfassen.

property Name: String; read / write;
property Name: String; read / write;
zweimal Property Name ?
Vielleicht noch besser, wie den VisionRange? Hier könnte ich sogar saubere Commando-Strings rüberschleussen?

property FigureStatus: TFigureStatus; read / write;
property AIGroup: TAIGroup; read / write;
sind eher ungeeignet.

Wie schwer ist es, in die TGameFigureKlasse eine freie Variable zu integrieren, die die Scripter dann nach belieben verwenden dürfen? z.B.
property ScriptTransfer: String; read / write;

Das ganze brauche ich für PSI-Angriffe.

Ich habe das theoretische Model in einer ersten einfachen Form dafür fertig.

PsiAttacken können erstmal nur von Aliens ausgeführt werden.
Angreifer und Ziel sind dem Script bekannt.
Damit müsste ich auch problemlos an die Werte Psiattacke und Psiverteidigung kommen. Darauf basierend und auf vorhandene TimeUnits+Zufall ermittel ich die Art der Psiattacke(Stun/Panic/Control). Im Script kann ich jetzt sogar noch einfache Manipulationen auf den Gegner auslösen. (z.B. Timeunits vom Gegner auf 0 oder ihn diese Runde noch laufen, schiessen lassen) Aber ich will eine Manipulation, die rundenübergreifend ist. Das Gegnerscript soll dann in der nächsten Runde reagieren und z.B. Panic abarbeiten.

Kann ich einen der

property Name: String; read / write;

dafür missbrauchen? Würde den tatsächlichen Inhalt dann in einer Scriptglobalen buffern und sowie ich ein Kommando registriere, ziehe ich mir das Kommando da raus und setze den String wieder auf den gepufferten Wert.
verfasst am: 29.11.2011, 08:17
Admin, Spielsatz GalWar

Registrierdatum: 31.08.2005, 21:51

 Beiträge: 5595
Ich würde das ganz anders machen (und habe das auch im GalWar anders gemacht): Externe Funktionsaufrufe mit Parameterübergabe.

Du brauchst dafür das TMission des Zielskriptes und musst dann vom externen Skript aus das CallProcedure verwenden, um im Zielskript eine gewählte Funktion aufzurufen.

Beispiel 1: Galwar/CON002action
Hier siehst Du, wie man das Mission-Objekt eines externen Skriptes ermittelt und eine Funtkion in diesem aufruft, allerdings hat die Funktion in diesem Beispiel keine Parameter (suche nach dem Kommentar "Aktion aufrufen", beginnt ab Zeile 64 oder so).

Beispiel 2: GalWar/ACC91drone (noch nicht fertig)
Hier gibt es einige Laufzeitprobleme, deshalb wird dieses Skript in den letzten Versionen vom GalWar nicht verwendet. Allerdings liegen die Fehler nicht in der Parameterübergabe, deshalb kannst Du diese Zeilen verwenden.
Alternativ kannst Du auch alle internen UFO-AI-Skripte anschauen, die haben alle ähnliche Zugriffsoptionen um externe Zielangaben zu erhalten. Nur liegen diese in der skripts.pak und Du müsstest die die Originale über SVN aus dem Quellcode holen.
Irgendwo im Forum gibt es aber auch einen Link auf ein Zip mit diesen Skripten, ich weiß den Link nur nicht auswendig.

Zitat: Kamor
procedure UserCall;
was kann man damit eigentlich machen, keine Parameterübergabe, wozu soll die dann gut sein?

Das löst ein vorher auf die Gamefigure registriertes User-Event aus, siehe User-Events für die genauere Beschreibung
verfasst am: 29.11.2011, 08:31 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
Zitat: DirkF
Irgendwo im Forum gibt es aber auch einen Link auf ein Zip mit diesen Skripten, ich weiß den Link nur nicht auswendig.


https://xforceffd.svn.sourceforge.net/svnroot/xforceffd/branches/V915t urbo2006/game/bin/settings/Scripts/

Gute schaue ich mir mal an dort, bzw. in deinem Galwar.
verfasst am: 29.11.2011, 08:43
Admin, Spielsatz GalWar

Registrierdatum: 31.08.2005, 21:51

 Beiträge: 5595
Hatte den Link zwischenzeitlich auch gefunden, aber die "Beispiele" in den UFO-AI-Skripten sind leider nicht so gut dokumentiert wie im unfertigen drone-Skript aus dem Galwar, weil die nur für externe Aufrufe vorbereitet waren, aber keine eigenen externen Aufrufe starten.
verfasst am: 29.11.2011, 21:48 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
Die Komunikation zwischen zwei Scripts kann man über deine vorgeschlagene Methode sehr gut lösen.

Mein Alien kann schon eine Psiattacke auf einen Gegner übertragen.

z.B.

mit mission.CallProcedure('ScriptCommand',['stun']);

Das Gegnerscript wertet das dann weiter aus

procedure ScriptCommand(command:string);
begin
  if (command='human') then human:=true;
  
  if (command='stun') then
  begin
    game_api_MessageBox(command);
    stun:=true;
    thisUnit.timeunits:=0;
    thisUnit.EndRound;
  end;
  if (command='panic') then
  begin
    game_api_MessageBox(command);
    panic:=true;
    thisUnit.MoveToRandomPosition(0);
  end;
  if (command='control') then
  begin
    game_api_MessageBox(command);
    control:=true;
    thisUnit.timeunits:=0;
    thisUnit.EndRound; // TODO: Einheiten auf Freunde schiessen lassen
  end;
end;



Leider treten doch nicht wenig neue Probleme auf. Die Kommunikationen zwischen den Objekten(Skripten) ist doch sehr träge.

Der Readwert von timeunits hängt konsequent hinterher, so das man ihn kaum für vergleiche heranziehen kann, ausser vielleicht noch am anfang der KI-Logic. Beim beschreiben, habe ich auch das Gefühl, das er sich manchmal streubt.

thisunit.endround; ohne vorher thisunit.timeunits:=0; gesetzt zu haben ist voll die Niete, da macht die Einheit noch fröhlich weiter dann. Mit dem Befehl thisunit.timeunits:=0; bekomme ich es zumeist hin, das die angesprochene Unit dann Null Move hat. Leider wie schon gesagt, wird das manchmal auch noch ignoriert?

Bei Panic ist es das gleiche, bzw. fuscht da noch der Status rein, das Einheiten vom Spieler gesteuert werden. Der schnelle Spieler kann konsequent in Panic geratene Soldaten abfangen. Manchmal wird Panic auch gar nicht ausgelöst. Der Pfad wird gesetzt, aber ein Walkbefehl wird nicht gestartet. Ich glaube das passiert, wenn man eine Einheit im Cursor hat, die scheint dann zum Teil immun gegen Moveanweisungen ausm Skript zu sein.

Ansonsten habe ich noch ein weiteres Problem. Ich will jetzt an die Werte PsiAttack und PsiVerteidigung ran.

Hatte schon gedacht über die
property UnitModelID: LongWord; read; ?

Aber da kommen glaube bei den Spieler TGameFigures nur nullen. Evtl. das ich die Aliens darüber lokalisiere und die Spieler dann über ihre Namen raussuchen und mit den Soldatennamen in der Base dann vergleiche?
verfasst am: 30.11.2011, 10:21
Admin, Spielsatz GalWar

Registrierdatum: 31.08.2005, 21:51

 Beiträge: 5595
PSI-Werte sind deaktiviert, weil die Funktionen dazu noch nie umgesetzt waren.

Irgendwann in (leider ferner) Zukunft ist auch geplant, die Einheitenwerte komplett zu überarbeiten, deshalb wird da momentan nicht viel passieren.

Vorschlag: Ergänze eigene Werte per Skript - habe ich zwar auch noch nicht versucht, aber theoretisch bräuchtest Du dazu nur ein permanent im Hintergrund laufendes Skript, das jedem Soldaten einen Array mit Zusatzwerten zuordnet und dann aus dem Bodeneinsatz jeweils mit CallProzedure die Abfrage startet. Übergebe als Parameter unter anderem das Mission-Objekt des startenden Skriptes und die externe Prozedur schickt die Daten umgehend zurück an das gerade arbeitende Skript.
verfasst am: 30.11.2011, 13:53
Programmierer, allgemeines

Registrierdatum: 06.06.2004, 17:19

 Beiträge: 3186
Allgemein zur KI. Ein Teil des Problems liegt wohl auch an dem ehemaligen Echtzeit-Bodeneinsatz. Dafür wurde nämlich die Engine ausgelegt, und erst später auf Rundenbasiert umgestellt. Prinzipiell läuft es so ab, dass alle Einheiten einer Partei (derzeit Spieler oder Alien) bei ihrem Zug in eine Liste gepackt werden, die dann immer wieder durchlaufen wird. Eine Runde ist erst dann beendet, wenn alle Einheiten aus der Liste entfernt wurden. Soweit ich mich erinnere, macht TGamefigure.endround genau das. Es werden aber keine laufenden Befehle abgebrochen (bestes Beispiel - wenn der Spieler allen Soldaten Wegbefehle gegeben hat, ohne diese auszuführen, und dann seinen Zug beendet, werden alle Soldaten aus der Liste genommen - und führen noch die letzte Bewegungsanweisung aus). Der richtige Ansatz ist also, die TUs auf 0 zu setzen. Allerdings - wenn der Gegner am Zug ist, und du setzt bei einem Treffer die TUs auf null, dann werden die ja in der neuen Runde wieder aufgefrischt. Hier müsstest du also im NewRound oder ähnlichem den Stun-Status umsetzen.

Ist aber schon länger her, dass ich an der KI gebastelt hab - deshalb alle angaben ohne Gewähr.

PS: Ich würde außerdem empfehlen, eine Art Logfile für jede Einheit zu erstellen. Das hilft ungemein bei der Fehlersuche.
verfasst am: 30.11.2011, 15:58 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
Zitat: Natter
Hier müsstest du also im NewRound oder ähnlichem den Stun-Status umsetzen.


Jo das mache ich auch, dafür habe ich die Scriptglobalen Flags dann. Funktioniert meist auch, gibt aber Situationen, wo das dann irgendwie noch ignoriert wird? Habe die Ursache dafür noch nicht gefunden und ist halt schwer, wenn die Objekte eigentlich in Echtzeit agieren und nicht die Bohne aufeinander warten wollen. ;-) Evtl. greift hier auch noch das Benutzerinterface zwischen und beisst sich mit meinen Scriptanweisungen auf eigentlich nur durch den Spieler zu bewegene Einheiten? Kann man evtl. Spielereinheiten noch irgendwie anders ausklammern, so das der Spieler diese temporär gar nicht steuern kann?

Dieses "ignorieren wir mal Stun oder Panic in der nächsten Spielerrunde" Phänomen muss ich erstmal in Griff bekommen, sonst hat weitere Psi-Programmlogik erstmal kein Sinn.

Deshalb ermittle ich auch erstmal nur den Psiattackwert und ignoriere Psiverteidigung. Auch wird das ganze nur auf den Psiattackwert eines Aliens reduziert. So komme ich erstmal relativ einfach an diesen Wert.

// psiattackewert ermitteln, psiverteidigung erstmal ignorieren
    ModelID:=thisUnit.UnitModelID;
    
    if (ModelID<>0) then
    begin
      game_api_MessageBox(inttostr(ModelID));
    
      thisUnitModel:=alien_api_GetAlienByID(ModelID);
      // if (isobject(TObject(thisUnitModel))) then
      // if (thisUnitModel<>NIL) then
      // if (thisUnitModel<>Null) then
      if (true) then
      begin
        game_api_MessageBox(inttostr(thisUnitModel.PSIAtt));
      end;
    end;



Der Code ist erstmal funktionell, habe aber leider noch nicht geschafft, abzufangen wenn alien_api_GetAlienByID(ModelID); kein TUnit objekt ermitteln kann.

isobject weigert sich mit TUnit zu arbeiten, ein Typencast darauf zum TObjekt will auch nicht?

thisUnitModel<>Null macht mir ein Typemismatchlaufzeitfehler?
thisUnitModel<>NIL geht auch nicht?

Wie kann ich das abfangen, um das Skript da sauber zu bekommen?
verfasst am: 01.12.2011, 02:07 · Edited by: Natter
Programmierer, allgemeines

Registrierdatum: 06.06.2004, 17:19

 Beiträge: 3186
Zitat: Kamor

isobject weigert sich mit TUnit zu arbeiten, ein Typencast darauf zum TObjekt will auch nicht?

Ohne jetzt nachzuschauen - TUnit ist doch ein record, oder?

Nur um das klarzustellen - Model steht in X-Force normalerweise für einen Datensatz (mit den Daten aus dem Spielsatz), der einen Einheitentyp beschreibt (momentan fallen mir da UFOs und Aliens ein). Dabei handelt es sich um einen record.

Die eigentlichen Einheiten im Spiel (also ein konkretes UFO auf dem Globus oder eine einzelne Einheit im Bodeneinsatz) sind dann Objekte. Neben den Spielsatzdaten aus dem Model werden in dem Objekt auch laufzeitspeziefische Sachen gespeichert (aktuelle Position, aktuelle HP etc.). Im Bodeneinsatz ist das TGamefigure. Das sollte sich auch auf nil bzw. isobject prüfen lassen. Wobei eine Objektvariable allerdings nicht automatisch nil wird - diesen Wert müsstest du an anderer Stelle im Skript schon selbst zuweisen. Auch bei IsObject bin ich mir nicht sicher, wenn das false liefert. Soweit ich mich erinnere werden auch die Objekte von getötete Einheiten erst am Ende des Bodeneinsatzes endgültig freigegeben (Angaben ohne Gewähr ^^).

Ansonsten - zur Fehlersuche hilft imho wirklich am besten ein Logfile. Dazu in jedem KI-Skript einen globalen String anlegen, und dann in jeder Prozedur/Funktion eine entsprechende Zeile an den String anhängen (gegebenenfalls auch weitere Informationen in den Funktionen, z.B. wenn Schuss abgefeuert wurde etc.). Beim beenden des Skriptes den String in eine Textdatei ausgeben.
verfasst am: 01.12.2011, 13:17 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
Zitat: Natter
Ansonsten - zur Fehlersuche hilft imho wirklich am besten ein Logfile


Habe ich bisher noch nicht für nötig gehalten, bzw. wäre der Aufwand für mich zu hoch und der Nutzen noch zu klein gewesen.

Die Logik mit der ich derzeit spiele ist eher noch überschaulich und simpel. Vielleicht später? Die Sache mit dem Logfile hat aber noch andere Nachteile, da geht der Echtzeittrace unter und da bei mir mehrere Scripte für eine Gesamtlogik kommunizieren, muss ich das dann auch noch zusammenpuzzeln. Ist mir wie gesagt, derzeit viel zu viel Aufwand, bei zu geringen Nutzen. Da setze ich lieber kurze lokale Debugausgaben, um Fehler zu finden.

Später wenn es vieleicht mal an eine komplexe Gruppenlogik geht, um reine Logikfehler zu finden, wäre so ein System evtl. interessant? Weiss aber nicht, ob ich so weit hier gehe. Im Moment steht erstmal ne vernünftige Individualki auf dem Plan und ich habe jetzt schon im Script jede Menge TODO Notizen um die Individualki noch effektiver zu gestalten.

Trotzdem danke für den Tip mit dem Logfilesystem. Das ganze erst im String zu puffern und dann am Ende ins File, merke ich mir.

Passend zum Thema, bin ich in einem anderen Ki-Projekt weg von einem Logfile gegangen und habe mir da 4 große Outputboxen gebastelt+Trace, so das ich da jederzeit beobachten kann, was die KI-Logik dort fabriziert.

Das meinte ich anderer Stelle hier im Forum, das man später, wenn man komplexere Logiken für die KI integriert eine Art Vereinfachung(Simulation) der Situation programmiert, wobei es dann hier einzig und allein um Logikfehlerfindung und Logikoptimierung in der KI geht. Ist aber alles eher utopisch und ich muss mich erstmal auf das Fundament konzentrieren.

Und das ist derzeit erstmal die Struktur der Komunikation zweier Skripte und das Handling der Einheiten. Noch ne Ebene tiefer, habe ich auch noch das Problem, das mir euer X-Script-Syntax noch etwas schwer von der Hand geht.

Ich hänge teilweise an Problemen, die eigentlich keine sein sollten.

Wie kann ich festellen, ob

thisUnitModel:=alien_api_GetAlienByID(ModelID);



mir keinen gültigen Pointer auf eine TUnit Struktur zurückgibt?
verfasst am: 01.12.2011, 15:03
Programmierer, allgemeines

Registrierdatum: 06.06.2004, 17:19

 Beiträge: 3186
alien_api_GetAlienByID wird nur die Daten kopieren - es wird keine Speicheradresse übergeben. Ich vermute mal, wenn es das Model nicht gibt, werden keine Daten in thisUnitModel geändert (und so könnte man das wohl auch prüfen - einfach vorher irgendwo einen Wert setzen und hinterher abfragen). Kann aber auch sein, dass in dem Fall eine exception im Spiel ausgelöst würde.
verfasst am: 01.12.2011, 16:02 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
Zitat: Natter
Kann aber auch sein, dass in dem Fall eine exception im Spiel ausgelöst würde.


Jo und genau diese exception möchte ich gerade verhindern. OK, wenn es keine bessere Lösung gibt, versuche ich das mal mit deinem Vorschlag, auch wenn sich gerade alle meine Nackenhaare streuben.
verfasst am: 01.12.2011, 19:37
Programmierer, allgemeines

Registrierdatum: 06.06.2004, 17:19

 Beiträge: 3186
Zitat: Kamor
OK, wenn es keine bessere Lösung gibt, versuche ich das mal mit deinem Vorschlag, auch wenn sich gerade alle meine Nackenhaare streuben.

Wann kommt denn die Exception? Was ich meinte, wäre eine Exception in X-Force beim Aufruf von alien_api_GetAlienByID mit einer ungültigen ID. Das ließe sich dann aber im Skript erstmal garnicht abfangen. Oder kommt der Fehler bei game_api_MessageBox?
verfasst am: 01.12.2011, 20:04 · Edited by: Kamor
Registrierdatum: 20.07.2005, 00:01

 Beiträge: 203
bisher kommt noch keine Exception ... habe auch noch ne Abfrage vorher drin, die 0 ´er IDs ausschließt. (0=Soldaten???)

Die messagebox ist nur zur demonstration da, im echten script läuft dann dort der ganze psi-angriffsalgoryhtmus

Hm, wenn die alien_api_GetAlienByID bei ungültiger ID schon den Exception auslöst, bringt mir das im nachhinein auch nichts, da auf NIL, NULL oder keinobject zu prüfen. Wie finde ich dann heraus, ob eine ID überhaupt gültig ist, so das mir die Benutzung dieser Routine nicht doch irgendwann unerwartet ein Exception reindrükt? Ich teste jetzt erstmal alien_api_GetAlienByID(0); ob der ne exception auslöst.



Du musst dich registrieren um auf dieses Thema zu antworten.
Login :: » Name » Passwort

Ladezeit (sec.): 0.015 · Powered by miniBB 1.6 with parts of 1.7 © 2001-2003