Jump to content

[SA|CLEO] Eigen trein types spawnen


Recommended Posts

Geplaatst: (bewerkt)

Eigen trein types spawnen



post-140414-0-13725000-1469099082.jpg

In deze tutorial ga ik uitleggen hoe je aangepaste trein types kan spawnen. Ben je die 16 voorgedefiniëerde types beu? Zin in verandering? Wil je eindelijk een keer een Freight box in werking zien? Dan is dit de tut voor jou!

Benodigdheden

CLEO3 of hoger

Sannybuilder

GTA:SA v1 of v1.01

We maken gebruik van geheugenadressen, waardoor dit hoogstwaarschijnlijk niet zal kloppen voor andere versies

SCM-kennis

Basiskennis is een vereiste (Basis SCM-scripten: tutorial door @Dutchy3010 & @PatrickW)

We zullen ook werken met het geheugen (Werken met geheugen (adressen) in CLEO: tutorial door @Crypteq)

Inhoud

Voorwoord

Inhoud

Werking

Methode 1

Methode 2

Nog langere types

Finito

 

Werking

Zoals je (misschien) weet zijn er 16 verschillende trein types in SA (je kan ze zien in sannybuilder help: druk F12 en ga naar SCM documentation > GTA SA > Train types)

De samenstellingen van de types zitten in het geheugen van het spel (baseadres 0x8D44F8).

post-140414-0-51474900-1469111254.jpg

Vanaf dit adres zijn er 16 blokken die elk 16 nummers (4 bytes) bevatten (dus elk blok is 64 bytes groot (40h), totaal 1024 bytes). Als het spel een trein spawnt, zal hij kijken vanaf adres 0x8D44F8 + type * 40h. Daar staat het modelid van de eerste wagon. Dan zoekt het spel 4 bytes verder voor de volgende wagon, totdat het volgende nummer een 0 is, dan is de volledige trein gespawnt.

Tijdens de testen heb ik gemerkt dat het spel tot 19 wagons kan spawnen, als ik probeer om 20 wagons in één type te steken, crasht het spel als zo een trein spawnt.

Merk op dat 19 wagons meer is dan de 16 nummers per blok. Dit betekent dat de laatste 3 wagons eigenlijk al in het volgende treintype zit.

Ook interessant om te weten: treinen die willekeurig voorbijkomen hebben geen probleem met aangepaste types, deze laden de modellen zelf. Maar in missies worden enkel de modellen geladen die in de standaard types zitten. Als je hier andere modellen toevoegt, zal je game crashen als die missie een trein probeert te spawnen! Meerdere dezelfde wagentjes toevoegen is echter geen probleem.

Opgelet: het is aangeraden om iedere keer terug de waardes op default te zetten nadat je je trein gespawnt hebt. Als de speler namelijk een ander script start (bv andere MPACK) zitten de vorige waarden er nog in en zal de game waarschijnlijk crashen als er een trein spawnt. Het is ook waarschijnlijk niet zo handig voor de speler als er opeens rare treinen spawnen als hij een nieuw spel start. Bij methode 2 zal de game zeker crashen als er een ander script wordt geladen en er een trein spawnt.

Methode 1

Nu kunnen we de nummers veranderen in die blokken om zo de types aan te passen.

Als je een enkele trein wilt spawnen is het handig om type 15 aan te passen en die te spawnen.

Ik raad types 9,14,15 aan omdat die types slechts één wagon hebben. Als je de standaardwaarde dan terug moet zetten, hoef je enkel die ene wagon terug te zetten én de volgende op 0 zetten.

Om dit te doen, moeten we dus de nieuwe model ids schrijven naar de correcte geheugenplaatsen.

De offset van het basis adres naar type 15 is dus 15 * 64 bytes = 960 (3C0h)

0x8D44F8 + 0x3C0 = 0x8D48B8

0247: load_model #FREIGHT
0247: load_model #FREIFLAT
0247: load_model #FREIBOX
0247: load_model #TRAM
038B: load_requested_models 

:LOAD
0001: wait 0
00D6: if and 
0248:   model #FREIGHT available
0248:   model #FREIFLAT available
0248:   model #FREIBOX available
0248:   model #TRAM available
004D: jump_if_false @LOAD

0006: 0@ = 0x8D48B8 // base adres type 15
0A8C: write_memory 0@ size 4 value #FREIGHT vp 0 //car1         
000A: 0@ += 4 // 4 bytes verder, volgende wagon
0A8C: write_memory 0@ size 4 value #FREIFLAT vp 0 //car2
000A: 0@ += 4 // 4 bytes verder, volgende wagon
0A8C: write_memory 0@ size 4 value #FREIBOX vp 0 //car3
000A: 0@ += 4 // 4 bytes verder, volgende wagon
0A8C: write_memory 0@ size 4 value #TRAM vp 0 //car4
000A: 0@ += 4 // 4 bytes verder, volgende wagon
0A8C: write_memory 0@ size 4 value 0 vp 0 //car5

// spawn onze trein
06D8: 0@ = create_train_at 2785.3813 1821.3121 10.8203 type 15 direction 1 // type 15!
036A: put_actor $PLAYER_ACTOR in_car 0@

// waardes terugzetten
0006: 0@ = 0x8D48B8 // base adres type 15
0A8C: write_memory 0@ size 4 value #STREAK vp 0 //car1         
000A: 0@ += 4 // 4 bytes verder, volgende wagon
0A8C: write_memory 0@ size 4 value 0 vp 0 //car2

0249: release_model #FREIGHT
0249: release_model #FREIFLAT
0249: release_model #FREIBOX
0249: release_model #TRAM
 

post-140414-0-02946200-1469099102.jpg

Merk op dat we enorm handig gewoon de modellen kunnen schrijven met #FREIGHT enz. Sannybuilder verandert dit automatisch naar het juiste nummer bij compilatie (hier: 537).

Methode 2

In plaats van de nummers te veranderen, kunnen we er ook gewoon voor zorgen dat het spel op een andere plaats gaat zoeken naar de types!

Met een disassembler kan je in de code van de exe kijken en zoeken waar de waardes die op locatie 0x8D44F8 liggen ingelezen worden. Als we dan zeggen 'kijk niet naar 0x8D44F8, maar zoek op het adres dat wij jou geven', kunnen we op een simpelere manier de waardes veranderen en terugzetten.

0247: load_model #FREIGHT
0247: load_model #FREIFLAT
0247: load_model #FREIBOX
0247: load_model #TRAM
038B: load_requested_models 

:LOAD
0001: wait 0
00D6: if and 
0248:   model #FREIGHT available
0248:   model #FREIFLAT available
0248:   model #FREIBOX available
0248:   model #TRAM available
004D: jump_if_false @LOAD

jump @OVER
:CARRIAGES
hex
   #FREIGHT  00 00
   #FREIFLAT 00 00
   #FREIBOX  00 00
   #TRAM     00 00
   00 00     00 00
end

:OVER
0AC6: 0@ = label @CARRIAGES offset 
0A8C: write_memory 0x6F75D6 size 4 value 0@ vp 0   //006F75D6  add     eax, offset unk_8D44F8
0A8C: write_memory 0x6F7B17 size 4 value 0@ vp 0   //006F7B16  add     esi, offset unk_8D44F8
0A8C: write_memory 0x6F7D2E size 4 value 0@ vp 0   //006F7D2C  add     ecx, offset unk_8D44F8

// spawn onze trein
06D8: 0@ = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1 // type 0!
036A: put_actor $PLAYER_ACTOR in_car 0@

// waardes terugzetten
0A8C: write_memory 0x6F75D6 size 4 value 0x8D44F8 vp 0   //006F75D6  add     eax, offset unk_8D44F8
0A8C: write_memory 0x6F7B17 size 4 value 0x8D44F8 vp 0   //006F7B16  add     esi, offset unk_8D44F8
0A8C: write_memory 0x6F7D2E size 4 value 0x8D44F8 vp 0   //006F7D2C  add     ecx, offset unk_8D44F8

0249: release_model #FREIGHT
0249: release_model #FREIFLAT
0249: release_model #FREIBOX
0249: release_model #TRAM
 

Met opcode 0AC6 krijgen we het adres van de locatie waar label :CARRIAGES staat. Na die label kom er een hex blok, waardoor die waarden letterlijk in het script komen te staan. Natuurlijk worden eerst de #FREIGHT enzo omgezet in hun nummers. Sannybuilder zet ze om naar een number die 2 bytes neemt. Elke wagon moet 4 bytes zijn dus staan er nog 00 00 achter. Dit is dan de locatie waar wij willen dat het spel kijkt om de wagonnen te spawnen. Dan kunnen we die locatie schrijven op de plaatsen die normaal naar de gewone plaats zou kijken (0x8D44F8). Hierdoor zal het spel dus de modellen van de wagonnen halen uit de bytes die in ons script zit, op de locatie van :CARRIAGES.

Hex blok met de standaard waarden:

hex   
   19 02 00 00 39 02 00 00  39 02 00 00 39 02 00 00  39 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type0
   1A 02 00 00 3A 02 00 00  3A 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type1
   1A 02 00 00 3A 02 00 00  3A 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type2
   19 02 00 00 39 02 00 00  39 02 00 00 39 02 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type3
   1A 02 00 00 3A 02 00 00  3A 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type4
   1A 02 00 00 3A 02 00 00  3A 02 00 00 3A 02 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type5
   19 02 00 00 39 02 00 00  39 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type6
   1A 02 00 00 3A 02 00 00  3A 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type7
   C1 01 00 00 C1 01 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type8
   C1 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type9
   19 02 00 00 39 02 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type10
   1A 02 00 00 3A 02 00 00  3A 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type11
   19 02 00 00 39 02 00 00  39 02 00 00 39 02 00 00  19 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type12
   19 02 00 00 39 02 00 00  39 02 00 00 39 02 00 00  39 02 00 00 39 02 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type13
   C1 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type14
   1A 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 // type15
end
 

Merk op dat het eerste getal bv 19 02 00 00 is. Dit is omdat het nummer in little-endiannotatie staat.

19 02 00 00 = 0x00000219 = 537 = #FREIGHT

Nog langere types

Heb je nog niet genoeg met 19 wagonnen? Moet het begin van de trein tegen het einde zitten? Dat kan! (Neen Robin, dat kan niet. Het spel zal crashen omdat je teveel voertuigen zal spawnen)

Op het forum van sannybuilder heb ik code gevonden om 2 treinen aan elkaar te koppelen: https://sannybuilder.com/forums/viewtopic.php?id=18 (post #13).

Maar: hoe langer je het maakt, hoe trager de trein zal versnellen/vertragen!

06D8: $DEM_TRAIN = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1      
06D8: $DEM_TRAIN2 = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1  
gosub @ATTACH2
06D8: $DEM_TRAIN2 = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1  
gosub @ATTACH2
06D8: $DEM_TRAIN2 = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1  
gosub @ATTACH2
// nu heb je 4 treinen aan elkaar!

:ATTACH2
// https://sannybuilder.com/forums/viewtopic.php?id=18 #13

// https://github.com/multitheftauto/mtasa-blue/blob/9b1fbaf639657a446790469aa6711e11be0d3eee/MTA10/game_sa/CVehicleSA.h#L472
// https://github.com/multitheftauto/mtasa-blue/blob/9b1fbaf639657a446790469aa6711e11be0d3eee/MTA10/game_sa/CVehicleSA.h#L456   
// https://github.com/multitheftauto/mtasa-blue/blob/9b1fbaf639657a446790469aa6711e11be0d3eee/MTA10/game_sa/CVehicleSA.h#L306

06DE: 1@ = get_train $DEM_TRAIN last_carriage_handle
0A97: 1@ = car 1@ struct // pointer van laatste wagon van eerste trein

078A: 3@ = get_train $DEM_TRAIN2 carriage 0 handle 
0A97: 3@ = car 3@ struct // pointer van eerste wagon van tweede trein

// Fix afstand tussen wagons. Omdat de eerste wagon van de tweede train geen voorganger heeft, is de afstand tot de voorganger 0.
// Hierdoor zal de eerste wagon van de tweede trein IN de laatste wagon van de eerste trein zitten
// dus zullen we die waarde instellen op de afstand van de tweede wagon tot de eerste wagon.
//   (dit is een incorrecte waarde, als de eerste wagon niet even groot is als de tweede, maar een betere manier dan dit heb ik nog niet gevonden)
078A: 10@ = get_train $DEM_TRAIN2 carriage 1 handle
0A97: 10@ = car 10@ struct // pointer naar tweede wagon van tweede trein
000A: 10@ += 0x5AC // float m_fDistanceToNextCarriage;
0A8D: 10@ = read_memory 10@ size 4 vp 0 // 10@ is nu de afstand van de tweede wagon naar de eerste
0085: 4@ = 3@ // (int) // pointer naar eerste wagon van tweede trein
000A: 4@ += 0x5AC // float m_fDistanceToNextCarriage;
0A8C: write_memory 4@ size 4 value 10@ vp 0 // de afstand van de eerste wagon is nu hetzelfde als de afstand tussen de tweede en de eerste (10@)

// De eerste wagon van de tweede trein is de engine.
// Als je instapt in een wagon dat geen engine is, kan je de trein niet besturen
// Een engine wagon kan geen voorganger hebben dus kan niet aan de laatste wagon van de eerste trein gekoppeld worden.
// In de post op het sannybuilder forum wordt dit opgelost door de eerste wagon van de tweede trein te verwijderen en de tweede wagon van de tweede trein aan de laatste wagon van de eerste trein te koppelen.
// Maar het kan dus ook opgelost worden door gewoon de flag die zegt dat het een engine is uit te zetten 
0085: 4@ = 3@ // (int) // pointer naar eerste wagon van tweede trein
000A: 4@ += 0x5B8 // CTrainFlags trainFlags; 
0A8D: 5@ = read_memory 4@ size 1 vp 0
08C0: clear 5@ bit 3 // unsigned char bIsTheChainEngine : 1; // Only the first created train on the chain gets this set to true, others get it set to false.
0A8C: write_memory 4@ size 1 value 5@ vp 0

// Nu kunnen we ze samenkoppelen
0085: 2@ = 1@ // (int) // pointer naar laatste wagon van eerste trein
000A: 2@ += 0x5D4 // CVehicleSAInterface* m_nextCarriage;
0085: 4@ = 3@ // (int) // pointer naar eerste wagon van tweede trein
000A: 4@ += 0x5D0 // CVehicleSAInterface* m_prevCarriage;
0A8C: write_memory 2@ size 4 value 3@ vp 0
0A8C: write_memory 4@ size 4 value 1@ vp 0
return
 

Finito

En voila, eigen trein types :D

He, psst! Al eens gedacht wat er zou gebeuren als je een gewone auto in een trein steekt? Probeer het eens ;)

 

 

:cya:

Bewerkt: door robin_be
  • 3 maanden later...
Geplaatst:

Schandalig van mij dat ik hier helemaal overheen gekeken heb. bloos.giffp.gifboink.gif

Mijn grote complimenten voor deze tutorial.

Mooi om te zien hoe de onderliggende laag werkt, en hoe je de limieten van het spel kan omzeilen.puh2.gif

Geweldig die video! schater.gifworshippy.gif

De tutorial heb ik natuurlijk in de Master Tutorial List gezet.

KUTGW thumbsup2.gif

Een reactie plaatsen

Je kan nu een reactie plaatsen en pas achteraf registreren. Als je al lid bent, log eerst in om met je eigen account een reactie te plaatsen.

Gast
Op dit onderwerp reageren...

×   Je hebt text geplaatst met opmaak.   Opmaak verwijderen

  Only 75 emoji are allowed.

×   Je link is automatisch ingevoegd.   In plaats daarvan weergeven als link

×   Je vorige bewerkingen zijn hersteld.   Alles verwijderen

×   You cannot paste images directly. Upload or insert images from URL.

  • Recent actief   0 leden

    • Er zijn hier geen geregistreerde gebruikers aanwezig.
×
×
  • Create New...