Dieses Forum nutzt Cookies
Dieses Forum nutzt Cookies um Anmeldeinformationen (keine Passwörter) zu speichern. Dabei werden diese Informationen als kleine Textdateien auf deinem Endgerät abgelegt. Sie können nur durch dieses Forum ausgelesen werden und stellen kein Sicherheitsrisiko dar. Neben deinem letzten Login wird auch abgespeichert, welche Themen du bereits gelesen hast.

Zudem wird ein Cookie angelegt, in dem abgespeichert wird, ob du diesen Hinweis gelesen hast. Damit wird er nicht jedes mal angezeigt.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
Verfasser Nachricht
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #1
M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
M4nfo

A macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
Eine Makrosammlung zur Generierung von nfo code für TTDPatch und OpenTTD newgrfs

Michael Blunck
Oktober 2009



Einleitung

Programmieren in "Bytecode", zB die Erstellung von nfo-Code für Transport Tycoon (TTDPatch und OTTD) newgrf Sets ist bekanntermassen nicht jedermanns Sache. Auch die Pflege von vielen tausend Zeilen Bytecode in den grösseren Sets ist für geübte Programmierer nicht einfach. Die Idee, eine "höhere Sprache" für diesen Zweck zu entwickeln ist deshalb genauso alt wie die Entwicklung des nfo-Bytecodes durch Josef Drexler. Aber trotz vieler Versuche und intensiver Diskussionen ist diesbezüglich bisher nichts Brauchbares entstanden.

Ein Grund liegt natürlich darin dass die Entwicklung einer neuen "Sprache" und die Entwicklung eines Übersetzers (Compiler, Interpreter) dafür nicht unbedingt zu den Vorhaben gehört die man schnell an einem Wochenende erledigen kann.

Zum zweiten ist die Umsetzung von nfo-Bytecode in eine höhere Sprache kein leichtes Unterfangen, da nfo-Bytecode diverse Fallstricke gegenüber einer einfachen Umsetzung bereit hält. Zum einen kann der Code selbstverändernd geschrieben werden ("action6"), zum anderen ist die Behandlung der verschiedenen newgrf Objekte (Fahrzeuge, Gebäude, Industrien, ...) nicht uniform, sondern kann bei gleicher (oder ähnlicher) Behandlung verschiedener Objekte mehr oder weniger variieren.

Darüber hinaus ist die Syntax abseits der am meisten verwendeten "actions" (action0, action1, action2, varaction2, action3, action4) aufgrund ihrer extrem maschinennahen Implementierung, relativ komplex (s. zB action7/9, actionD, advancedaction2, die Benutzung von Registern, "subroutines" oder (externen) Parametern, usw.).

Trotzdem hat wohl jeder nfo-"Coder" der lange genug dabei ist, sich einige Hilfsmittel geschaffen, die die Code-Erstellung einfacher und weniger mühselig machen. Auch ich gehöre zu diesem Kreis. Cool

Nachdem ich am letzten Wochenende eine kleinere Erleuchtung diesbezüglich hatte, habe ich mich mal zwei Abende hingesetzt, und alles was ich zu früheren Zeiten schon mal ausprobiert hatte zusammengefasst und überarbeitet. Nicht ohne einen gewissen Erfolg.

Trotzdem: mein Ansatz ist höchst pragmatisch, und das Ergebnis ist nicht die schon lange erwartete Hochsprache die es (fast) jedem ermöglicht ein beliebiges Vorhaben in einfacher Weise in eine lauffähige newgrf umzusetzen. Abgesehen von dem doch eher kleinen Sprachumfang, der zZt lediglich die Programmierung von Schienenfahrzeugen ermöglicht, ist auch hier die Kenntnis des Aufbaus einer newgrf und der grundlegenden Struktur des nfo Konzepts zwingende Voraussetzung für einen Einstieg.

Statt einer Universallösung inklusive dem dazugehörigem Compiler bietet sie (im Moment) wie gesagt lediglich eine Lösung für den Bereich Schienenfahrzeuge. Eine Erweiterung auf den Bereich Strassenfahrzeuge, Flugzeuge und Schiffe ist aber leicht möglich. Anders sieht dies für den Bereich Gebäude oder Industrien aus, hier würde man noch einmal ganz von Neuem entwickeln müssen, obwohl man sicher manche Funktionen der aktuellen Entwicklung nutzen und ausbauen können wird.

Der derzeitige Implementierungsstand erlaubte jedenfalls bereits die Neuimplementierung meiner derzeitigen Arbeitsversion des DB Sets v0.9*. Das ist mMn nicht schlecht, denn der Set hat trotz einer komprimierten Programmierweise 10000 Sprites (Codezeilen) und ist wesentlich komplexer als die aktuelle Version 0.82.

[*] einige wenige exotische Konstrukte sind dabei noch in nfo, das wird sich aber noch ändern.


Zum Technischen.

--------- Ende Teil 1 -------------------------------------


Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
20.10.2009 23:11
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #2
RE: M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
--------- Fortsetzung -----------------------

Das Ganze ist im Prinzip lediglich eine Makro-Sammlung, die unter dem Makroprozessor "M4" lauffähig ist. Die Nutzung eines Makroprozessors mit naturgemäss eingeschränktem Funktionsumfang für einen solchen Zweck gilt gemeinhin als eine weniger elegante und zuverlässige Lösung als zB die Entwicklung einer dem Problem bestmöglich angepassten Speziallösung, am besten in einer weitverbreiteten und leistungsfähigen Hochsprache (zB C/C++), aber die technisch simplere Lösung erzwingt auch die Konzentration auf das Wesentliche. Ein Fakt der häufig übersehen wird.

Ein zentrales Problem bei einer Compilerlösung war zB immer die Umsetzung der nfo-Spritenummern in eine vom Compiler verwaltete Befehlskette. In meinem Ansatz habe ich davon ganz abgesehen (weil technisch nicht machbar) und die Definition und Referenzierung der .nfo Sprite-Nummern einfach manuell belassen. Dies hat durchaus Vorteile, denn der neue Code ist dadurch wesentlich lesbarer als wenn man zB eine Lisp-artige Schachtelung der Befehlsketten implementieren würde. Zudem ist die eigenständige Verwaltung (Neuvergabe, Wiederbenutzung) von Sprite-Nummern durch einen Compiler auch nicht gerade einfach zu implementieren und ohne explizite Sprite-Nummern würde man ein zusätzliches Debugging-Tool benötigen, etc ..., und eine Makro-Bibliothek ist leicht erweiterbar und veränderbar, im Gegensatz zu einem Compiler.


Die Definition von Sprite-Nummern (c-IDs) und ihre Referenzierung habe ich sinnvollerweise in zwei verschiedene Funktionen getrennt:

def(<n>) definiert eine Sprite-Nummer,
ref(<n>) referenziert eine Sprite-Nummer.

Die in nfo vorhandenen "properties" können nun ganz einfach durch einen Katalog von Funktionen abgebildet werden. Abgesehen von einer besseren Lesbarkeit des Codes kann man zusätzlich eine gewisse "Automatisierung" durch die Art und Weise ihrer Implementierung erreichen.

ZB sind in einem grossen Fahrzeugset Ketten aus "varaction2" mit schätzungsweise 90% der Codezeilen, bzw Spritenummern beteiligt. Kern einer varaction2 ist (in nfo Syntax) ein Konstrukt dass in etwa einem "C" switch/case Block entspricht.

Dies habe ich auch entsprechend so implementiert, nur dass eben das zentrale Konstrukt eines solchen Blocks, das neue "if" Statement, sehr flexibel implementiert ist und dadurch, wie oben beschrieben, dem Programmierer überflüssige Arbeit ersparen hilft.

Sehen wir uns dies einmal genauer an.

1. Syntax für varaction2

1.1 Das "if" Statement

if(<Ganzzahl Konstante> | <Bereich> | <Liste>)

Das "if" Statement vereinfacht den nfo "switch/case" Block.

ZB kann der nfo-Block

Code:
-1 * 0   00 02 00 81 40 00 03 03
    03 00 03 03
    02 00 02 02
    01 00 01 01
    00 00

nun einfach als

Code:
def(0)  vehpos(MOD4,
    ref(3) if(3)
    ref(2) if(2)
    ref(1) if(1)
    ref(0) else
)

geschrieben werden. Hier zeigt sich deutlich die Trennung zwischen der Referenz einer c-ID und der Auswertung der "property" auf dem die erfolgende Referenz beruht.

Die Idee lässt sich verbessern:

Aus

Code:
-1 * 0   00 02 00 81 10 00 FF 01
    62 80 01 03
    FF 80

wird

Code:
def(0) articulated(
    addveh(0x62) if(1 .. 3)
    ENDLIST else
)

Das "if" Statement kennt als Parameter auch einen Bereich, genauso wie nfo das auch implementiert. Hier sieht man ausserdem, dass sich recht einfach Konstanten per Textersatz lesbarer gestalten lassen, wie zB das "FF 80" am Ende einer Liste von artikulierten Teilfahrzeugen oder am Ende einer Liste von "text suffixes".

Das "if" ist aber noch nicht am Ende, es kennt auch Listen als Parameter:

Aus dem nfo-Block

Code:
-1 * 0   00 02 00 81 B9 00 FF 03
    FE 80 00 00
    FE 80 02 02
    FE 80 0A 0A
    20 80

wird

Code:
def(0) cargo(
    ATT_OK if(PASS, MAIL, VALU)
    ATT_VAN else
)

D.h. wenn verschiedenen Ergebniswerten ein und dieselbe Referenz zugeordnet werden soll, müssen diese Werte nicht einzeln aufgeführt werden wie zB hier:

Code:
def(0) cargo(
    ATT_OK if(PASS)
    ATT_OK if(MAIL)
    ATT_OK if(VALU)
    ATT_VAN else
)

sondern das "if" Statement ermöglicht eine kompaktere Notation als die einer 1:1 Abbildung auf die nfo. Auch hier sind die "ATT_*" übrigens wieder (frei vereinbare) Konstanten, die zB Referenzen oder Callback-Resultate sein können. Hier sind es Resultate für den callback 1D ("wagon attach"), die angeben ob ein bestimmtes Fahrzeug angehängt werden kann ("ATT_OK") oder nicht ("ATT_VAN": "Güterwagen kann nicht angehängt werden").

--------- Ende Teil 2 -----------------------

Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
22.10.2009 22:11
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #3
RE: M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
1.2. Das "ifyear" Statement als Variation des "if" Statement

ifyear(<Jahr> | <Jahrbereich> | <Jahrliste>)

Eine vielfach benötigte Anwendung eines varaction2 Blocks bzw eines entsprechenden "if" Konstrukts ist die Evaluierung eines Datums, insbesondere des Jahres, zB zum Bestimmen bestimmter Farbgebungen, oder bei Veränderungen der technischen Parameter des Fahrzeuges durch einen callback. Hierfür ist das "ifyear" Statement von Nutzen:

Aus

Code:
-1 * 0   00 02 02 81 C4 00 FF 01
    00 00 00 36  // -1974 rot
    01 00        // 1975- blau/beige

wird damit

Code:
def(2) yearbuilt(
         ref(0) ifyear(1920 .. 1974) // -1974 rot
         ref(1) else                 // 1975- blau/beige
)

d.h. das Konstrukt erlaubt die Eingabe realer Jahreszahlen ohne irgendwelche Umrechnungen.


2. Syntax für action0

Eine Implementierung der nfo "action0" ist einfach, da hier im Prinzip lediglich dezimal vorliegende Werte in Hex-Zahlen umgewandelt werden müssen.

train(<veh-ID>,<name>,{<property>})

Die aktuelle Implementierung bietet aber auch hier durch "implizite" Auswertungen und Berechnungen diverse Vereinfachungen. ZB werden bestimmte "properties" zusammengefasst und gemeinsam evaluiert. Dies geschieht zB bei der Datumsangabe, der Gewichtsangabe oder der Bestimmung der property für die Zugkraft. Diese Werte (und andere) können also komfortabel angegeben werden wie hier zu sehen ist:

Code:
train(10, {"BR 220 (ex V 200)"},
    intro(1954) // Einführungsjahr
    reliability(11) // Abnahme der Fz-Verlässlichkeit
    vehlife(30) // Lebensdauer des Fz (in Jahren)
    modlife(30) // Verfügbarkeit des Modells (in Jahren)
    enginetype(DIESEL) // Traktionsart und Kostentabelle
    speed(140 km/h) // Höchstgeschwindigkeit
    power(2700 PS) // Dauerleistung
    runningcost(120) // Wartungskosten
    dualhead(NO) // einfache Lok
    capacity(0) // keine Frachtkapazität
    weight(80 t) // Dienstgewicht
    price(75) // Kaufpreis
    aiusage(10) // AI Rang
    effort(235 kN) // Zugkraft
    shorter(0) // normale Fahrzeuglänge
    retire(2) // frühzeitige Entfernung aus Kaufliste
)

Die "train" Funktion übernimmt hier quasi nebenbei auch die Funktion der "action4", also der Namensgebung. Alle Werte werden dezimal angegeben, es sind keinerlei Umrechnungen erforderlich, auch keine eigene Errechnung der "property" für die Zugkraft aus dem Gewicht der Lok. Auch die Angabe der Nutzung von "callbacks" oder die Festlegung der Frachtmasken erfolgen in komfortabler Weise:

callbacks(CB_POWR, CB_ARTI, CB_RCOL) bzw.
cargomask(PASS, MAIL, TOUR) // Passagiere, Post, Touristen

und sind gleich den ausserhalb der nfo action0 anzugebenden Werten.

Zudem können bestimmte Werte mit Einheiten angegeben werden, sodass eine eventuelle notwendige Umrechnung entfällt. Dies sind

- für Geschwindigkeit: km/h, mph
- für Leistung: kW, PS, hp (SAE hp bzw bhp)
- für Zugkraft: kN, kp, lbf
- für Gewicht: t (metrische Tonne), tnsh (short ton, US), tnl (long ton, UK).


------------ Ende Teil 3 ----------------

Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
04.11.2009 17:50
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #4
RE: M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
3. Syntax für action1 und action2

Auch diese Implementierung ist simpel. In Spriteblöcken für Fahrzeuge treten normalerweise zwar lediglich 4- und 8-Richtung-Sprites auf, dennoch schien es hier sinnvoll dieses statement flexibler auszuführen, besonders im Hinblick auf eine spätere Erweiterung auf andere Objekte.

spriteblock({<set>}) - definiert einen sprite-Block
set({<sprite>}) - definiert einen sprite Set
sprite(<realsprite>) - definiert ein einzelnes "real sprite"

in Verbindung mit einer Implementierung für die zugehörige "action2", namens

spriteset(move(<movingstates>), load(<loadingstates>))

sieht die praktische Anwendung dann zB so aus:

Code:
//---------------------------------------
// V200
//---------------------------------------

spriteblock(
  // rot
  set(
    sprite(db_v200.pcx 66 8 01 20 8 -3 -12)
    sprite(db_v200.pcx 82 8 09 17 23 -14 -9)
    sprite(db_v200.pcx 114 8 01 12 30 -14 -8)
    sprite(db_v200.pcx 146 8 09 17 23 -5 -8)
    sprite(db_v200.pcx 178 8 01 20 8 -3 -12)
    sprite(db_v200.pcx 194 8 09 17 23 -16 -8)
    sprite(db_v200.pcx 226 8 01 12 30 -15 -8)
    sprite(db_v200.pcx 258 8 09 17 23 -7 -9)
  )
  // blau/beige
  set(
    sprite(db_v200.pcx 66 30 01 20 8 -3 -12)
    sprite(db_v200.pcx 82 30 09 17 23 -14 -9)
    sprite(db_v200.pcx 114 30 01 12 30 -14 -8)
    sprite(db_v200.pcx 146 30 09 17 23 -5 -8)
    sprite(db_v200.pcx 178 30 01 20 8 -3 -12)
    sprite(db_v200.pcx 194 30 09 17 23 -16 -8)
    sprite(db_v200.pcx 226 30 01 12 30 -15 -8)
    sprite(db_v200.pcx 258 30 09 17 23 -7 -9)
  )
)

Hierdurch werden also 2 Sets zu jeweils 8 Richtungssprites definiert.

Code:
def(0) spriteset(move(0), load(0)) // rot
def(1) spriteset(move(1), load(1)) // blau/beige

Die Funktionen "move" und "load" geben die per "spriteblock" definierten und zu verwendenden Sprite-Sets an. Im obigen Beispiel wird lediglich ein Sprite-Set pro Farbgebung verwendet, aber bei einem Güterwagen könnte dies zB so aussehen:

Code:
def(5) spriteset(move(0, 13), load(0, 9, 10, 11, 12, 13))

für 2 Fahrzustände (offen, geschlossen) und 6 Beladungszustände.


4. Syntax für action3

Auch diese Implementierung ist relativ simpel aber effektiv:

makevehicle(<veh-ID>,{c-ID/cargo type pair},<default c-ID>[{,<override>}])

Die Paare von c-IDs und zugehöriger Fracht ("cargo type") werden durch die Funktion "link" realisiert:

link(<c-ID>,{<cargotype>}), sodass eine praktische Anwendung zB so aussehen würde:

Eine Lok:

Code:
makevehicle(0x01,
    link(ref(3), MENU) // Kaufmenü
    default(ref(1)) // Lok
)

Ein Güterwagen:

Code:
makevehicle(0x43,
    link(ref(7), MENU) // Kaufmenü
    link(ref(2), LVST) // Vieh
    link(ref(6), FOOD, FISH) // Lebensmittel und Fisch
    default(ref(1)) // alles andere
)

Ein eventuell notwendiger "livery override" wird durch die Funktion "override" erzeugt:

override(<veh-ID>,<c-ID>), s. Beispiel im nächsten Abschnitt.

-------- Ende Teil 4 -------------------------

Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
09.11.2009 21:51
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #5
RE: M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
4.1 Beispiel V200

Nun wollen wir in einem einfachen Beispiel mal zusammenfassen, was wir bis jetzt haben. Wie gesagt, habe ich bereits die Version 0.9 des DB Set in die neue Syntax übertragen, so dass auch die üblicherweise vorkommenden komplizierteren Konstruktionen (zB Callbacks oder "recolourings") bereits von der aktuellen Implementierung dieser Makrosammlung abgedeckt werden.

Hier also erst mal die einfache V200:

Code:
//------------------------------------------------------------------
//      BR 220                  V 200
//------------------------------------------------------------------

train(10, {"BR 220 (ex V 200)"},
    intro(1954) // Einführungsjahr
    reliability(11) // Abnahme der Fz-Verlässlichkeit
    vehlife(30) // Lebensdauer des Fz (in Jahren)
    modlife(30) // Verfügbarkeit des Modells (in Jahren)
    enginetype(DIESEL) // Traktionsart und Kostentabelle
    speed(140 km/h) // Höchstgeschwindigkeit
    power(2700 PS) // Dauerleistung
    runningcost(120) // Wartungskosten
    dualhead(NO) // einfache Lok
    capacity(0) // keine Frachtkapazität
    weight(80 t) // Dienstgewicht
    price(75) // Kaufpreis
    aiusage(10) // AI Rang
    effort(235 kN) // Zugkraft
    shorter(0) // normale Fahrzeuglänge
    retire(2) // frühzeitige Entfernung aus Kaufliste
)

spriteblock(
  set(
    sprite(db_v200.pcx 66 8 01 20 8 -3 -12)
    sprite(db_v200.pcx 82 8 09 17 23 -14 -9)
    sprite(db_v200.pcx 114 8 01 12 30 -14 -8)
    sprite(db_v200.pcx 146 8 09 17 23 -5 -8)
    sprite(db_v200.pcx 178 8 01 20 8 -3 -12)
    sprite(db_v200.pcx 194 8 09 17 23 -16 -8)
    sprite(db_v200.pcx 226 8 01 12 30 -15 -8)
    sprite(db_v200.pcx 258 8 09 17 23 -7 -9)
  )
  set(
    sprite(db_v200.pcx 66 30 01 20 8 -3 -12)
    sprite(db_v200.pcx 82 30 09 17 23 -14 -9)
    sprite(db_v200.pcx 114 30 01 12 30 -14 -8)
    sprite(db_v200.pcx 146 30 09 17 23 -5 -8)
    sprite(db_v200.pcx 178 30 01 20 8 -3 -12)
    sprite(db_v200.pcx 194 30 09 17 23 -16 -8)
    sprite(db_v200.pcx 226 30 01 12 30 -15 -8)
    sprite(db_v200.pcx 258 30 09 17 23 -7 -9)
  )
)

def(0) spriteset(move(0), load(0)) // rot
def(1) spriteset(move(1), load(1)) // blau/beige

def(2) yearbuilt(
         ref(0) ifyear(1920 .. 1974) // rot
         ref(1) else                    // blau/beige
)

//------------------------------------------------------------------
// Anzeige
//------------------------------------------------------------------

spriteblock(
  set(
    sprite(db_v200.pcx 226 50 01 12 30 -14 -8) // rot
  )
  set(
    sprite(db_v200.pcx 226 70 01 12 30 -14 -8) // blau/beige
  )
)

def(0) spriteset(move(0), load(0)) // rot
def(1) spriteset(move(1), load(1)) // blau/beige

def(3) year(
         ref(0) ifyear(1920 .. 1973) // rot
         ref(1) else                    // blau/beige
)

// callbacks Anzeige
def(4) callback(
         TLH_V200 if(CB_TEXT) // Hilfstext für Lok
         ref(3) else          // Grafik für Anzeige
)

//------------------------------------------------------------------
// Wagen für V200: Passagiere (fern + extra)
//------------------------------------------------------------------

def(0) yearbuilt(
         ref(XSPW_WRUM) ifyear(1920 .. 1960) // 1950 - 1960 switch Wrüm | Aüm
         ref(X_TEEHUMP) ifyear(1969 .. 1973) // switch TEE Buckel | generic
         ref(F_BB74) ifyear(1974 .. 1986)    // DB74
         ref(X_IRIC) ifyear(1987 .. 1996)    // switch IR87 | IC87
         ref(LF_) else                       // 1997- generic (k. SPW!)
)

//------------------------------------------------------------------
// Wagen für V200: Post (fern + extra)
//------------------------------------------------------------------

def(1) yearbuilt(
         ref(XP_TEE) ifyear(1969 .. 1973)  // switch TEE | generic
         ref(FP_BB74) ifyear(1974 .. 1986) // DB74
         ref(XP_IRIC) ifyear(1987 .. 1996) // switch IR87 | IC87
         ref(LFP_) else                    // 1997- generic
)

makevehicle(0x0A,
    link(ref(4),MENU) // Kaufmenü
    default(ref(2)) // Lok
    override(0x4D,ref(0)) // Passagiere
    override(0x4E,ref(1)) // Post
)

Wie man sieht, sind hier die einzelnen Wagenklassen aus Gründen der Übersichtlichkeit über "label" defineirt bzw referenziert, und nicht über c-ID Nummern. Dies ist entsprechend natürlich auch für die veh-IDs möglich.

------------ Ende Teil 5 -----------------------------

Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
(Dieser Beitrag wurde zuletzt bearbeitet: 11.11.2009 22:58 von mb.)
11.11.2009 22:58
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #6
RE: M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
5. Syntax für random action2

Ähnlich wie bei der varaction2 "vehpos" gibt es auch hier die Unterscheidung zwischen der auf den aktuellen Wagen oder der auf die Lok bezogenen Entscheidung.

randomrel(<trigger>,<randbit>,<randomstates>) bezieht sich auf den aktuellen Wagen, und
randomabs(<trigger>,<randbit>,<randomstates>) auf die Lok.

ZB randomisiert

Code:
randomrel(CONSTRUCT, 1, ref(0), ref(1), ref(2), ref(3))

beim Bau eines Wagens 4 verschiedene Zustände, während

Code:
randomrel(LOAD, 1, ref(1), ref(2))

beim Neubeladen eines Wagens zwischen zwei Zuständen auswählt,

und

Code:
randomabs(UNLOAD, 1, ref(8), ref(9), ref(10), ref(11))

aus 4 Zuständen auswählt.


6. Syntax für actionE

Mittels

deactivateset(<Liste der grf-IDs>)

werden die angegebenen newgrfs deaktiviert.


7. Syntax für action10

Um Sprungmarken zB für die action7 (oder action9) zu setzen ist eine Verwaltung dieser Marken nötig.

Mit

deflabel(<Marke>)

wird eine Marke definiert, die mittels

placelabel(<Marke>)

am entsprechenden Platz verankert wird.

In Sprungbefehlen (s.u.) kann dann mittels

reflabel(<label>)

auf die jeweilige Marke Bezug genommen werden.

-------------- Ende Teil 6 -------------------

Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
18.11.2009 11:40
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
mb
Tycoon
*****

Beiträge: 5.054
Registriert seit: Mar 2005
Beitrag #7
RE: M4nfo - a macro library for generating nfo code for TTDPatch and OpenTTD newgrfs
8. Syntax für action7

Hier galt es erstmals eine komplizierte Struktur so zu vereinfachen dass sie in einer Mehrzahl der Fälle relativ unkompliziert genutzt werden kann. Die volle Leistungsfähigkeit der nfo action07 bzw action9 ist daher (bisher) nicht implementiert worden.

Das statement

skip(<number>)

überspringt immer die angegebene Anzahl von sprites, wobei

skip(EXIT)

die aktuelle newgrf beendet.

Der bedingte Sprungbefehl

skipif(<number>,<var>, <conditiontype>,<value>)

ermöglicht Sprünge abhängig von verschiedenen Variablenarten.


8.1. Sprung abhängig von TTDPatch-Variablen

Als TTDPatch-Variablen können hier 4 verschiedene Typen auftreten:

- Zahlenwert (Klima, Versionsnummer, ...)
- Bitwert (TTDPatch flags)
- grf-ID
- cargo label

Entsprechend unterschiedlich gestaltet sich die Syntax des Befehls:

Code:
skipif(6,CLIMATE,==,TEMP)

führt zum Sprung wenn das Klima das temperierte Klima ist. Es stehen ausserdem die Operatoren !=, < und > zur Verfügung.

Code:
skipif(1,FLAGS,BITSET,NEWTRAINS)

führt zum Sprung wenn das bit für das TTDPatch feature "newtrains" gesetzt ist. BITCLR wird verwendet um zu prüfen ob ein bit nicht gesetzt ist.

Code:
skipif(2,GRFACTIVE,+,ALPINESET)

führt zum Sprung wenn die newgrf "alpineclimate" aktiv ist, und

Code:
skipif(1,GRFACTIVE,-+,ALPINESET)

wenn diese newgrf (noch) nicht aktiviert ist, später aber noch aktiviert werden wird:

D.h.

"+" steht für "ist aktiviert",
"-" für "ist nicht aktiviert",
"-+" für "ist nicht aktiviert, wird aber noch aktiviert werden",
"++" für "ist aktiviert, und wird noch aktiviert werden",
"--" für "ist weder aktiviert noch wird später aktiviert werden".

Code:
skipif(reflabel(NOCERE), CARGO, -, {CERE})

führt zum Sprung an die Marke "NOCERE" wenn die Güterart "CERE" nicht zur Verfügung steht.

In diesem Fall muss übrigens der Parameter CERE in bestimmter Weise gekennzeichnet werden ("quoted") weil er sonst nicht als Text ("CERE") sondern als die entsprechende Güterart (CERE) selber behandelt werden würde. Nur durch die Verwendung von Text kann hier nämlich auch auf das Vorhandensein unbekannter Güterarten abgeprüft werden.

Genauso muss übrigens auch bei der Definition einer "cargo translation table" "gequoted" werden, dies als Folge des Vorteils dass wir, anders als in nfo, nicht zwischen den verschiedenen Bezeichnern für Frachtarten in den action0, action2 und action3, etc unterscheiden brauchen:

Code:
cargotranslationtable(32)
                 {"PASS" "COAL" "MAIL"
                 "OIL_" "LVST" "GOOD"
                 "CERE" "WOOD" "IORE"
                 "STEL" "VALU" "PAPR"  
                 "FOOD" "FRUT" "FISH"
                 "WOOL" "POTA" "SAND"
                 "GLAS" "WDPR" "DYES"
                 "FERT" "OLSD" "RFPR"
                 "VEHI" "PETR" "BRCK"
                 "SULP" "CMNT" "FICR"  
                 "LIME" "TOUR"}


8.2. Sprung abhängig von über Parameter vereinbarten Variablen

Dies sind Variablen die üblicherweise über die nfo actionD vereinbart werden. Durch diesen Mechanismus kann auch auf die Werte von TTDPatch flags zugegriffen werden.

Statt zB

Code:
-1 * 9        0D 01 00 06 FE FF FF 00 00  // lade "multihead" Wert in Parameter 1
-1 * 6        07 01 01 02 00 01 // Sprung abhängig vom Wert des Parameters 1

lässt sich nun mit

Code:
skipif(1, patchvar(MULTIHEAD), ==, 0)

derselbe Effekt erzielen. Hierbei ermittelt die Funktion "patchvar" den Wert der entsprechenden TTDPatch-Variablen.

-------------- Ende Teil 7 -------------------

Gruß
Michael

Zitat:EU-Wirtschaft- und Währungskommissar Joaquin Almunia hat alle Besorgnisse über den Schuldnerstatus Griechenlands als unbegründet zurückgewiesen.
12.12.2009 10:22
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
Hilfe Diverse Fragen zu OpenTTD, TTD und TTDPatch Steinborg 7 5.222 22.07.2013 18:26
Letzter Beitrag: Steinborg

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste