Jump to content

[SA] Memory access via stat opcodes


Recommended Posts

Update (1 Oct 2006) -- The first post was drastically reorganized to provide a summary of the current situation and remove some outdated information. The genesis of this idea was discussions between PLPynton and myself during a brief hijacking of Dem's TFB development topic.

 

Note that all memory locations given in this post are for the US version 1.0 exe; for other regions and versions, the absolute locations are probably different but the method of accessing them should be the same.

 

The SA stat opcodes do not do boundary checking on the stat ID numbers they are passed, so they provide limited memory access to locations near the stat pools. The chunk of memory you can get to isn't super large, but there are some interesting things you can play around with. The stat pools themselves, based on op9080's memory investigations are an array of 223 ints (stats 120-342) starting at location 0xB79000 and an array of 82 floats (stats 0-81) starting at location 0xB79380.

 

But, you can use stat IDs 82-119 to get to the memory just before this range and IDs 343-65535 to get to memory above this range. Essentially, what happens is that for a given X (where X is from 82 to 65535 inclusive) stat X gives you access to memory location 0xB78F68 + 4*(X-82). Because these values are handled by the opcodes as if you are reading from the integer stat pool, they will be read and written as 4-byte integers, meaning you will generally have to translate them if the underlying data is really another size and/or type.

 

Note that because the float stat pool (stats 0-81) is also inside this range, you get an overlap where stats 344-425 also access stats 0-81, however they interpret them as INTs and so you're generally better off accessing these stats in the normal manner. Below is a table showing the memory layout and how it corresponds to the stat ID numbers:

 

 

Offset-H  Offset-D  Stat ID========  ========  ========0xB78F68  12029800  stat 82  (always read as 4b INT)  ...       ...       thru0xB78FFC  12029948  stat 119 (always read as 4b INT)0xB79000  12029952  stat 120 (properly-handled INTs)  ...       ...       thru0xB79378  12030840  stat 342 (properly-handled INTs)0xB7937C  12030844  stat 343 (always read as 4b INT)0xB79380  12030848  stat 344 (always read as 4b INT) or 0  (properly-handled floats)  ...       ...       thru0xB794C4  12031172  stat 425 (always read as 4b INT) or 81 (properly-handled floats)0xB794C8  12031176  stat 426 (always read as 4b INT)  ...       ...       thru0xBB8E1C  12291612  stat 65535 (always read as 4b INT)

 

 

Other stat ID numbers work as well, but they overflow into the 0-65535 range. For example, stat -1 is the same as stat 65535 and stat 65536 is the same as stat 0. To restate the summary, the full useful range of stat id numbers appears to be 0-65535 with stats 82-65535 spanning the entire memory range of 0xB78F68 - 0xBB8E1F in 4-byte integer chunks and stats 0-81 overlapping a small part of that range but providing true float access to that part.

 

The first main caveat to this memory access is that the stat opcodes will always interpret the value in memory as a signed 4-byte integer even if it is something else. Therefore, you always want to use 0652 for reading so that the stat opcodes don't wrongly transform the value. For example, if you are reading a value you know is a float, you still use 0652 to read it, and then just treat it as a float afterwards.

 

The second main caveat is that the stat-changing opcodes are limited in how much they can change those stats. They will only assign (or increment) in the range of -32768 to 32767. So if you need to assign a much higher value, as when working with a float, you have to use multiple small increments until you reach your goal.

 

Here's an example using stat 85. The set of stat IDs 82-119 access the memory just before the two stat pools and IDs 82-118 correspond to definitions 22-58 in ar_stats.dat. For the example, I want to change stat 85 from 10.0 to 20.0. Because these are outside the "legitimate" stat pools, they are treated as integers and so 10.0 is read as 1092616192 and 20.0 would be 1101004800. Thus, I need to add 8388608 to the current value, but have to do it in chunks no larger than 32767. See the examples section at the end for code which does this.

 

Here are a couple of other examples of stat-based memory access chosen because they were known locations which would have easily verifiable results. I chose the player's money which is stored as 32-bit ints at locations 0xB7CE50 (actual value) and 0xB7CE54 (displayed value), (and elsewhere) and the color of the text of the money display on the HUD at xBAB230 (1 byte each for RGBA). Taking the offsets of those locations from the start of the stat pool and plugging into the previously listed formula, that gives "stat" values of 4108, 4109 and 51460 respectively.

 

After setting my money via one of the normal opcodes:

 

0109: player $PLAYER_CHAR money += 53891

 

the 4108/4109 stats updated to the same value, as seen in the below screenshot (you'll have to trust me on the output tounge2.gif) user posted image

 

Similarly, the following command in the script set the money back to 30000:

 

0629: change_stat 4108 to 30000

 

 

As for the HUD, somewhat randomly changing the value of stat 51460 resulted in the expected on-screen results:

user posted image

 

The rest of the topic concerns interesting memory locations we can reach and what to do with them as well as general discussions on the methods.

 

=====================================================

 

Code examples (Sanny Builder format)

 

Making adjustments

No matter what the underlying data type is, to change them you have to treat them as integers and make the changes in several small increments. Note that this can take a quite long time if the values are vastly different. Suggestions for more efficient methods are greatly appreciated.

 

Here's a generic updating subroutine for the stats outside the legitimate ranges. I've updated it to handle both "absolute" updates (similar to the 0629: change_stat opcode) as well as "relative" updates similar to 0623: increase_stat and 0625: decrease_stat opcodes. If you gosub to @StatUpdateAbsolute, it makes the necessary adjustments to 22@ and falls through to the relative code; note that the result is that 22@ is modified from what was sent to it. In either case, it assumes 21@ is the stat ID and 22@ is the new value or increase/decrease. Note that the absolute call also uses 23@ for temporary storage.

 

:StatUpdateAbsolute// Changes stat 21@ to be exactly 22@0652: 23@ = stat 21@0062: 22@ -= 23@:StatUpdateRelative// Changes stat 21@ by adding 22@ to it// A positive 22@ results in an increase, and a negative 22@ is a decrease.if 0 > 22@jf @StatUpdateIncreaseLoop22@ *= -1 // make it positive:StatUpdateDecreaseLoopif 22@ >= 32767jf @StatUpdateMakeLastDecreasewait 00625: decrease_stat 21@ by 3276722@ -= 32767jump @StatUpdateDecreaseLoop:StatUpdateMakeLastDecrease0625: decrease_stat 21@ by 22@jump @StatUpdateEnd:StatUpdateIncreaseLoopif 22@ >= 32767jf @StatUpdateMakeLastIncreasewait 00623: increase_stat 21@ by 3276722@ -= 32767jump @StatUpdateIncreaseLoop:StatUpdateMakeLastIncrease0623: increase_stat 21@ by 22@:StatUpdateEndreturn

 

 

And here's an alternative version from Seemann and slightly modified by me which takes advantage of Sanny Builder's ability to have a more high-level syntax. The advantages are readability and not having to worry about internal label names; but SAMB users would have to work a little harder to translate it wink.gif

 

:StatUpdateAbsolute// Changes stat 21@ to be exactly 22@0652: 23@ = stat 21@0062: 22@ -= 23@:StatUpdateRelative// Changes stat 21@ by adding 22@ to it// A positive 22@ results in an increase, and a negative 22@ is a decrease.if 22@ > 0then  while 22@ >= 32767    wait 0    0623: increase_stat 21@ by 32767    22@ -= 32767  end  0623: increase_stat 21@ by 22@else  22@ *= -1 // make it positive  while 22@ >= 32767    wait 0    0625: decrease_stat 21@ by 32767    22@ -= 32767  end  0625: decrease_stat 21@ by 22@endreturn

 

 

 

Type Conversions

 

32-bit floats - you want to read them as integer with 0652, then treat them as floats for processing, then switch back and treat them as integers for changing the stat value.

 

Reading:

 

0652: 10@ = stat 85 // read as int10@ += 1.0  // use float assignment and math afterwards0087: 11@ = 10@ // use float assignment and math afterwards

 

 

Changing to a specific hardcoded target value:

 

0652: 10@ = stat 85 // read as int (e.g. 1092616192)11@ = 20.0 // hardcoded target value21@ = 85 // stat ID num0085: 22@ = 11@  // int assign0062: 22@ -= 10@ // int difference for stat value change (e.g. 8388608)gosub @StatUpdateRelative // See above subroutine

 

 

Changing to a calculated target value (in this case 1/2 of original):

 

0652: 10@ = stat 86 // read as int0087: 11@ = 10@ // treat as float to process11@ *= 0.5 // calculated target value21@ = 86 // stat ID num0085: 22@ = 11@  // int assign0062: 22@ -= 10@ // int difference for stat value changegosub @StatUpdateRelative // See above subroutine

 

 

RGBA color definitions:

Reading:

0652: 10@ = stat 51460 // as integer0085: 13@ = 10@13@ /= 16777216 // 13@ will be Alpha byte0085: 15@ = 13@if 0 > 10@jf @SkipNegativeA// The INT value is negative, so we have to adjust15@ -= 113@ = 256005A: 13@ += 15@:SkipNegativeA15@ *= 167772160062: 10@ -= 15@0085: 12@ = 10@12@ /= 65536 // 12@ will be Blue byte0085: 15@ = 12@15@ *= 655360062: 10@ -= 15@0085: 11@ = 10@11@ /= 256 // 11@ will be Green byte0085: 15@ = 11@15@ *= 2560062: 10@ -= 15@ // 10@ will be Red byte0302: text_4numbers 'HJSTATF' 10@ 11@ 12@ 13@ 10000 ms 1 // debugging output to easily check numbers

 

 

Writing: (Note this can take freaking forever with large changes to the alpha because of the inefficient looping assignment methods). Note also that I use the absolute version of the stat update subroutine here.

 

10@ = 255 // Red11@ = 128 // Green12@ = 128 // Blue13@ = 255 // Alpha0085: 14@ = 10@0085: 15@ = 11@15@ *= 256005A: 14@ += 15@0085: 15@ = 12@15@ *= 65536005A: 14@ += 15@// Deal with potential signed valuesif 13@ > 127jf @SkipNegative  13@ -= 256:SkipNegative0085: 15@ = 13@15@ *= 16777216005A: 14@ += 15@ // 14@ is now the INT for the RGBA quad21@ = 514600085: 22@ = 14@gosub @StatUpdateAbsolute // See above subroutine

 

Edited by pdescobar
Link to comment
https://gtaforums.com/topic/257379-sa-memory-access-via-stat-opcodes/
Share on other sites

mate thank you for opening this, i was also hesitating to trash over another topic.

 

i found think about more safe method to write them with check (Stat 46689 MENU-ACTIVE OR PLAYING) then just bump it. some of memory adress can not be changed while plying because of crash. and another is that negative values work too bu not the same adressing applies.

 

mem adress for stat

stat = 0x00b78E20h + 4 * stat number

 

ok, here are my examples for you all. examples of useless stuff and heavy ressistible stuff as well.

Stat 04108 ---Money Posessed

Stat 04109 ---Money Displayed

Stat 50560 ---Wanted Level (RO)

Stat 46683 MENU-SUBTITLES

Stat 46681 MENU-BRIGHTNESS (0-384)

Stat 46675 MENU-RADAR MODE

Stat 46674 MENU-HUD MODE

Stat 46724 MENU-STORE GALLERY PHOTOS

Stat 46682 MENU-DRAW DISTANCE

Stat 46717 MENU-ANTI ALIASING (1 = off, 2 = 1x, 3 = 2x, 4 = 3x)

Stat 46720 MENU-RESOLUTION

Stat 46715 MENU-MIP MAPPING

Stat 46718 MENU-CONTROLLER (0 = mouse+keys, 1 = joypad)

Stat 46689 MENU-ACTIVE OR PLAYING

Stat 51447 HUD-WEAPON TEXTURE

Stat 51450 HUD-RADAR TEXTURE

Stat 51459 HUD-HEALTH BAR (RGBA)

Stat 51460 HUD-CASH & ENTER VEHICLE (RGBA)

Stat 51461 HUD-P2 (RGBA)

Stat 51462 HUD-BREATH METER BAR & STATUS TEXT (RGBA)

Stat 51463 HUD-CLOCK & ARMOUR BAR (RGBA)

Stat 51464 HUD-STYLED TEXT (RGBA)

Stat 51465 HUD-WANTED METER (RGBA)

Stat 51467 HUD-RADIOSTATION TEXT (RGBA)

here is heavy sh*t:

Stat 49154 MENU-MAP-PLAYER TARGET X

Stat 49155 MENU-MAP-PLAYER TARGET Y

Stat 49164 MENU-MAP-PLAYER TARGET X

Stat 49165 MENU-MAP-PLAYER TARGET Y

Stat 49144 MENU-MAP-PLAYER TARGET X

Stat 49145 MENU-MAP-PLAYER TARGET Y

here is a way of setting custom text on screen without gxt twists

Stat 50784 ---TEXT BOX 4Letters-01

thru

Stat 50880 ---TEXT BOX 4Letters-97

Stat 51176 ---TEXT STYLED 4Letters-01

thru

Stat 51224 ---TEXT STYLED 4Letters-48

Edited by PLPynton
Looks like I need to start boning up on SA mem-hacking. SCM-based mem-hacking is so damn sexy. As is a purple cash readout wink.gif I can't wait to abuse this. Anything I can do to help in terms of development? Though it sounds like the two of you have it well under control...
Looks like I need to start boning up on SA mem-hacking. SCM-based mem-hacking is so damn sexy. As is a purple cash readout wink.gif I can't wait to abuse this. Anything I can do to help in terms of development? Though it sounds like the two of you have it well under control...

your help will be needed.

we need:

 

1. coded method to update stats to any given value also negative ones, pseudo floats and casual text strings (some of completed in first post)

2. lots of testings for hazardous memory chunks (you update 4 bits at once in loop and sometimes one stat applies to 4 bits with few functions).

3. new adresses: get some art money or whatever, trace something then check if its offset is above B78E20h or else it is going to be hard to get to it thru script. you can check memory adresses topic but you will not find much over there because they were always chasing functions that we do have in coding.

 

yesterday i have finished my teleporter code thanks to mem access, now i can place marker on map and press the button to teleport player right to this spot (adresses in second post).

 

i am looking since ages for airplane velocity 75.0 m/s limit someone?

 

i suspect radio counters are located around 0096907Bh and i have not found favourite radio stat nowhere till now.

 

yesterday i have finished my teleporter code thanks to mem access, now i can place marker on map and press the button to teleport player right to this spot (adresses in second post).

Oooh. nice!

 

 

i am looking since ages for airplane velocity 75.0 m/s limit someone?

Well the Hydra speed limit might be an unsigned byte at 0x6DADE8; quite a bit lower in memory than we can currently get to easily. That assumes that I am reading the source code to op9080's SCM Hook correctly. Plane and Jetpack height limits are near that as well.

 

 

i suspect radio counters are located around 0096907Bh and i have not found favourite radio stat nowhere till now.

Hmmm. Interesting. monocle.gif I need to learn better memory-hacking skills.

 

 

Some more addresses:

The section of stats 430-443 seem to be stat and skill timers related to ar_stats.dat; I haven't investigated them fully yet but here are some preliminary guesses:

  • stat 430: increases when sprinting; possibly timer for sprint stamina increase
  • stat 431: increases when sprinting on bike; possibly timer for cycle stamina increase
  • stat 432: increases when on bike and moving over a certain minimum speed; possibly timer for cycle skill increase
  • stat 433: increases when swimming; possibly timer for swim stamina increase
  • stat 435: increases when in car and moving over a certain minimum speed; possibly timer for driving skill increase
  • stat 436: increases when in plane or heli and moving over a certain minimum speed; possibly timer for flying skill increase
  • stat 438: increases when on motorbike and moving over a certain minimum speed; possibly timer for bike skill increase
  • stats 439 and 443: increase when jogging, sprinting, swimming, cycling; possibly timers for fat decrease, muscle increase, or max health increase.

-1(INTEGER) Total mission points

-343() UNUSED BY EXE. you can store anything here

-345(FLOAT) Total mission points

-347(FLOAT) Distance traveled on foot

-348(FLOAT) Distance traveled by car

-349(FLOAT) Distance traveled by motorbike

-350(FLOAT) Distance traveled by boat

-351(FLOAT) Distance traveled by golf cart

-352(FLOAT) Distance traveled by helicopter

-353(FLOAT) Distance traveled by plane

-372(FLOAT) Distance traveled on exercise bike

-452(INTEGER) Hazardous- do not change it

-492(INTEGER) Hazardous- do not change it

 

i have a question:

there are few kind of 4b adress types:

 

1. truncated whatever integer or float like all the normal ingame stats

2. normal (you can change them to 65535 for example in one step (stat 81 or 82 i do not recall)

3. however you read them you have to get them to int then to flaot ant this again to float (stat 365 for example)

 

how we will indicate them in description? A B C D ...?

 

 

-1(INTEGER) Total mission points

-343() UNUSED BY EXE. you can store anything here

-345(FLOAT) Total mission points

-347(FLOAT) Distance traveled on foot

-348(FLOAT) Distance traveled by car

-349(FLOAT) Distance traveled by motorbike

-350(FLOAT) Distance traveled by boat

-351(FLOAT) Distance traveled by golf cart

-352(FLOAT) Distance traveled by helicopter

-353(FLOAT) Distance traveled by plane

-372(FLOAT) Distance traveled on exercise bike

Any stat X from 344 to 425 (inclusive) should be just a less useful way of accessing stat (X-344) so we really don't need to list them explicitly. I say "Less useful" because they are read as INTs instead of their true floats.

 

 

-452(INTEGER) Hazardous- do not change it

-492(INTEGER) Hazardous- do not change it

If I calculated the offset correctly, 452 is a pointer to the last controlled car since that's what Jernej posted for memory offset 0xB79530 in the memory topic. No clue on 492.

 

 

i have a question:

there are few kind of 4b adress types:

 

1. truncated whatever integer or float like all the normal ingame stats

2. normal (you can change them to 65535 for example in one step (stat 81 or 82 i do not recall)

3. however you read them you have to get them to int then to flaot ant this again to float (stat 365 for example)

 

how we will indicate them in description? A B C D ...?

Stats 0-81 are all internally floats and the stat opcodes are smart enough to make the proper translations on the fly. So both "0629: change_stat 0 to 5" or "062A: change_stat 0 to 5.0" should work fine and result in the actual data becoming 5.0

 

Stats 120-342 are all internally 16-bit integers sign-extended to 32-bits and once again the stat opcodes translate when necessary.

 

Any other stat value will be the type 3 in your quote where they are treated as 32-bit integers and assignment involves the kind of looping shown in the first post. Since what you have to do to translate those to and from useful values is dependant upon what the underlying data types and sizes actually are, I'd say the simplest thing is just indicate the underlying data type in its descriptions like you did here.

Bloody hell, this is awesome, I didn't realize anyone had found a way to do this yet. Or even that it was possible. I am very interested in finding how this all works out, it will change scm modding once again, I can see it now icon14.gif

 

Keep up the great work guys, I'll do some research and see if I can get in on the action too tounge.gif.

pure way to change most of or even bring some (whenever needed) text messages, boxes ect.

 

user posted image

 

first thread is a simple button press engine to see effects:

 

 

:TESTER03A4: name_thread 'TESTER' 0004: $CTEXT(@0,70i)  =  0;; integer values:TESTER040001: wait  250 ms00D6: if  0 0256:   is_player_playing $PLAYER004D: jump_if_false ££TESTER0400D6: if  080E1:   NOT   key_pressed  0  18004D: jump_if_false ££TESTER7000D6: if  080E1:   NOT   key_pressed  0  19004D: jump_if_false ££TESTER800002: jump ££TESTER04:TESTER7000D6: if  00038:   $DISPLAY ==  0;; integer values004D: jump_if_false ££TESTER040004: $CTMESSAGE  =  0;; integer values0417: start_mission  135; Custom text database0001: wait  50 ms004F: create_thread ££CTEXT 0002: jump ££TESTER04:TESTER8000D6: if  00038:   $DISPLAY ==  0;; integer values004D: jump_if_false ££TESTER040004: $CTMESSAGE  =  1;; integer values0417: start_mission  135; Custom text database0001: wait  50 ms004F: create_thread ££CTEXT 0002: jump ££TESTER04004E: end_thread

 

 

second part is main part where the adresses are written into memory:

 

 

:CTEXT03A4: name_thread 'CTEXT' 0004: $DISPLAY  =  1;; integer values03E6: remove_text_box03EB: clear_small_messages_only 00BE: print_now_clear_all0006: @0 = 0;; integer values0006: @1 = 0;; integer values008B: @2 = $STAT;; integer values and handles00D6: if  250018:   $TIME >  10000;; integer values0018:   $CTMAX >  95;; integer values8018:   NOT   $CTMAX >  0;; integer values8018:   NOT   $STAT >  0;; integer values8018:   NOT   $COUNT >  0;; integer values001C:   $COUNT > $CTMAX;; integer values004D: jump_if_false ££CTEXT_10004: $STAT  =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1095909712;; integer values0004: $CTEXT(1)  =  1163150669;; integer values0004: $CTEXT(2)  =  1461736274;; integer values0004: $CTEXT(3)  =  1196314450;; integer values0004: $COUNT  =  4;; integer values008B: @2 = $STAT;; integer values and handles:CTEXT_1;0629: change_stat @2 to 0;; integer values 00D6: if  0 803C:   NOT   $CTMAX == @1;; integer values 004D: jump_if_false ££CTEXT_2000A: @1 +=  1;; integer values000A: @2 +=  1;; integer values0002: jump ££CTEXT_1:CTEXT_20652: get_stat  $STAT store_to @3; integer0064: @3 -= $CTEXT(@0,95i);; integer values 00D6: if  0001B:    0 > @3;; integer values004D: jump_if_false ££CTEXT_50012: @3 *=  -1;; integer values :CTEXT_300D6: if  0 0029:   @3 >=  32767;; integer values004D: jump_if_false ££CTEXT_40623: increase_stat  $STAT by  32767;; integer values000E: @3 -=  32767;; integer values0002: jump ££CTEXT_3:CTEXT_40623: increase_stat  $STAT by  @3;; integer values0002: jump ££CTEXT_8:CTEXT_500D6: if  0 0029:   @3 >=  32767;; integer values004D: jump_if_false ££CTEXT_60625: decrease_stat  $STAT by  32767;; integer values 000E: @3 -=  32767;; integer values0002: jump ££CTEXT_5:CTEXT_60625: decrease_stat  $STAT by  @3;; integer values :CTEXT_80008: $STAT +=  1;; integer values000A: @0 +=  1;; integer values00D6: if  0 803C:   NOT   $COUNT == @0;; integer values 004D: jump_if_false ££CTEXT_100001: wait  0 ms0002: jump ££CTEXT_2:CTEXT_100001: wait  $TIME ms03E6: remove_text_box03EB: clear_small_messages_only 00BE: print_now_clear_all0004: $DISPLAY  =  0;; integer values004E: end_thread

 

 

and this is an example how to not to lose so much memory in main section and handle containment of messages via mission script.

 

 

;-------------Mission 135---------------; Custom text database:CTDATA_103A4: name_thread 'CTDATA':CTDATA_20871: init_jump_table $CTMESSAGE total_jumps  6  0 £CTDATA_M00 jumps  1 £CTDATA_M01  2 £CTDATA_M02  3 £CTDATA_M03  4 £CTDATA_M04  5 £CTDATA_M05  6 £CTDATA_M06  -1 £CTDATA_M07 :CTDATA_M000004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1919903827;; integer values0004: $CTEXT(1)  =  1702109300;; integer values0004: $CTEXT(2)  =  1663071352;; integer values0004: $CTEXT(3)  =  1646292577;; integer values0004: $CTEXT(4)  =  1869357157;; integer values0004: $CTEXT(5)  =  1684366433;; integer values0004: $CTEXT(6)  =  1935762720;; integer values0004: $CTEXT(7)  =  1851859065;; integer values0004: $CTEXT(8)  =  1634082916;; integer values0004: $CTEXT(9)  =  1998615667;; integer values0004: $CTEXT(10)  =  1701603688;; integer values0004: $CTEXT(11)  =  1852795936;; integer values0004: $CTEXT(12)  =  1852776551;; integer values0004: $CTEXT(13)  =  1635000421;; integer values0004: $CTEXT(14)  =  544433515;; integer values0004: $CTEXT(15)  =  1701998445;; integer values0004: $CTEXT(16)  =  1835627552;; integer values0004: $CTEXT(17)  =  1869881445;; integer values0004: $CTEXT(18)  =  1634692128;; integer values0004: $CTEXT(19)  =  11876;; integer values0004: $COUNT  =  20;; integer values0002: jump £CTDATA_M07:CTDATA_M010004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1801680198;; integer values0004: $CTEXT(1)  =  779381024;; integer values0004: $COUNT  =  2;; integer values0002: jump £CTDATA_M07:CTDATA_M020004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1919903827;; integer values0004: $CTEXT(1)  =  1702109300;; integer values0004: $CTEXT(2)  =  1663071352;; integer values0004: $CTEXT(3)  =  1646292577;; integer values0004: $CTEXT(4)  =  1869357157;; integer values0004: $CTEXT(5)  =  1684366433;; integer values0004: $CTEXT(6)  =  1935762720;; integer values0004: $CTEXT(7)  =  1851859065;; integer values0004: $CTEXT(8)  =  1634082916;; integer values0004: $CTEXT(9)  =  1998615667;; integer values0004: $CTEXT(10)  =  1701603688;; integer values0004: $CTEXT(11)  =  1852795936;; integer values0004: $CTEXT(12)  =  1852776551;; integer values0004: $CTEXT(13)  =  1635000421;; integer values0004: $CTEXT(14)  =  544433515;; integer values0004: $CTEXT(15)  =  1701998445;; integer values0004: $CTEXT(16)  =  1835627552;; integer values0004: $CTEXT(17)  =  1869881445;; integer values0004: $CTEXT(18)  =  1634692128;; integer values0004: $CTEXT(19)  =  11876;; integer values0004: $COUNT  =  20;; integer values0002: jump £CTDATA_M07:CTDATA_M030004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1919903827;; integer values0004: $CTEXT(1)  =  1702109300;; integer values0004: $CTEXT(2)  =  1663071352;; integer values0004: $CTEXT(3)  =  1646292577;; integer values0004: $CTEXT(4)  =  1869357157;; integer values0004: $CTEXT(5)  =  1684366433;; integer values0004: $CTEXT(6)  =  1935762720;; integer values0004: $CTEXT(7)  =  1851859065;; integer values0004: $CTEXT(8)  =  1634082916;; integer values0004: $CTEXT(9)  =  1998615667;; integer values0004: $CTEXT(10)  =  1701603688;; integer values0004: $CTEXT(11)  =  1852795936;; integer values0004: $CTEXT(12)  =  1852776551;; integer values0004: $CTEXT(13)  =  1635000421;; integer values0004: $CTEXT(14)  =  544433515;; integer values0004: $CTEXT(15)  =  1701998445;; integer values0004: $CTEXT(16)  =  1835627552;; integer values0004: $CTEXT(17)  =  1869881445;; integer values0004: $CTEXT(18)  =  1634692128;; integer values0004: $CTEXT(19)  =  11876;; integer values0004: $COUNT  =  20;; integer values0002: jump £CTDATA_M07:CTDATA_M040004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1919903827;; integer values0004: $CTEXT(1)  =  1702109300;; integer values0004: $CTEXT(2)  =  1663071352;; integer values0004: $CTEXT(3)  =  1646292577;; integer values0004: $CTEXT(4)  =  1869357157;; integer values0004: $CTEXT(5)  =  1684366433;; integer values0004: $CTEXT(6)  =  1935762720;; integer values0004: $CTEXT(7)  =  1851859065;; integer values0004: $CTEXT(8)  =  1634082916;; integer values0004: $CTEXT(9)  =  1998615667;; integer values0004: $CTEXT(10)  =  1701603688;; integer values0004: $CTEXT(11)  =  1852795936;; integer values0004: $CTEXT(12)  =  1852776551;; integer values0004: $CTEXT(13)  =  1635000421;; integer values0004: $CTEXT(14)  =  544433515;; integer values0004: $CTEXT(15)  =  1701998445;; integer values0004: $CTEXT(16)  =  1835627552;; integer values0004: $CTEXT(17)  =  1869881445;; integer values0004: $CTEXT(18)  =  1634692128;; integer values0004: $CTEXT(19)  =  11876;; integer values0004: $COUNT  =  20;; integer values0002: jump £CTDATA_M07:CTDATA_M050004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1919903827;; integer values0004: $CTEXT(1)  =  1702109300;; integer values0004: $CTEXT(2)  =  1663071352;; integer values0004: $CTEXT(3)  =  1646292577;; integer values0004: $CTEXT(4)  =  1869357157;; integer values0004: $CTEXT(5)  =  1684366433;; integer values0004: $CTEXT(6)  =  1935762720;; integer values0004: $CTEXT(7)  =  1851859065;; integer values0004: $CTEXT(8)  =  1634082916;; integer values0004: $CTEXT(9)  =  1998615667;; integer values0004: $CTEXT(10)  =  1701603688;; integer values0004: $CTEXT(11)  =  1852795936;; integer values0004: $CTEXT(12)  =  1852776551;; integer values0004: $CTEXT(13)  =  1635000421;; integer values0004: $CTEXT(14)  =  544433515;; integer values0004: $CTEXT(15)  =  1701998445;; integer values0004: $CTEXT(16)  =  1835627552;; integer values0004: $CTEXT(17)  =  1869881445;; integer values0004: $CTEXT(18)  =  1634692128;; integer values0004: $CTEXT(19)  =  11876;; integer values0004: $COUNT  =  20;; integer values0002: jump £CTDATA_M07:CTDATA_M060004: $STAT =  50784;; integer values0004: $TIME  =  5000;; integer values0004: $CTMAX  =  75;; integer values0004: $CTEXT  =  1919903827;; integer values0004: $CTEXT(1)  =  1702109300;; integer values0004: $CTEXT(2)  =  1663071352;; integer values0004: $CTEXT(3)  =  1646292577;; integer values0004: $CTEXT(4)  =  1869357157;; integer values0004: $CTEXT(5)  =  1684366433;; integer values0004: $CTEXT(6)  =  1935762720;; integer values0004: $CTEXT(7)  =  1851859065;; integer values0004: $CTEXT(8)  =  1634082916;; integer values0004: $CTEXT(9)  =  1998615667;; integer values0004: $CTEXT(10)  =  1701603688;; integer values0004: $CTEXT(11)  =  1852795936;; integer values0004: $CTEXT(12)  =  1852776551;; integer values0004: $CTEXT(13)  =  1635000421;; integer values0004: $CTEXT(14)  =  544433515;; integer values0004: $CTEXT(15)  =  1701998445;; integer values0004: $CTEXT(16)  =  1835627552;; integer values0004: $CTEXT(17)  =  1869881445;; integer values0004: $CTEXT(18)  =  1634692128;; integer values0004: $CTEXT(19)  =  11876;; integer values0004: $COUNT  =  20;; integer values:CTDATA_M07004E: end_thread

 

 

i hope the code is clear enough to get the idea.

 

@pdescobar: mate thanks for that address, i will check it thru. it might be it if i can get into this memory range!

edit: yes that was it, changed few bits in it and works but unfortunatelly i cannot get anywhere else except <0x00B78E20 thru 0x00BB8E1C> have you find any mathod to get outside it?

what a shame we can not access memory range to put piece of code in it.

EDIT: there was a mistake in your nick name man, sorry for that.

Edited by PLPynton

@PLPynton: PLEASE don't take offense at this. Just as you stated, minimal footprint is key and the following is intended to be maximum compression. It ONLY adds 80 bytes to MAIN (not including the create_thread)

 

 

:TESTER0004: $CTMESSAGE  =  18:TESTER20001: wait  127 ms00D6: if  100E1:   key_pressed  0 $CTMESSAGE0038:   $DISPLAY ==  0004D: jump_if_false ££TESTER30417: start_mission  135:TESTER30008: $CTMESSAGE +=  100D6: if  000E1:   $CTMESSAGE >  19004D: jump_if_false ££TESTER20004: $CTMESSAGE  =  180002: jump ££TESTER2

 

 

...with the following as the mission

 

 

;-------------Mission 135---------------; Custom text database:CTDATA_103A4: name_thread 'CTDATA'0004: $DISPLAY  =  10006: @4 =  507840006: @5  =  7500D6: if  00038:   $CTMESSAGE ==  18004D: jump_if_false £CTDATA_M010006: @34  =  19199038270006: @35  =  17021093000006: @36  =  16630713520006: @37  =  16462925770006: @38  =  18693571570006: @39  =  16843664330006: @40  =  19357627200006: @41  =  18518590650006: @42  =  16340829160006: @43  =  19986156670006: @44  =  17016036880006: @45  =  18527959360006: @46  =  18527765510006: @47  =  16350004210006: @48  =  5444335150006: @49  =  17019984450006: @50  =  18356275520006: @51  =  18698814450006: @52  =  16346921280006: @53  =  118760006: @6  =  200002: jump £CTDATA_M07:CTDATA_M010006: @34  =  18016801980006: @35  =  7793810240006: @6  =  2:CTDATA_M070050: gosub £CTEXTCLEARALL0085: @2 = @4:CTEXT_100D6: if  0803B:   NOT   @5 == @1004D: jump_if_false £CTEXT_2000A: @1 +=  1000A: @2 +=  10002: jump £CTEXT_1:CTEXT_20001: wait  0 ms0652: get_stat @4 store_to @30062: @3 -= @34(@0,95i)00D6: if  0001B:    0 > @3004D: jump_if_false £CTEXT_50012: @3 *=  -1:CTEXT_30623: increase_stat @4 by  3276700D6: if  00019:   @3 >  32767004D: jump_if_false £CTEXT_8000E: @3 -=  327670002: jump £CTEXT_3:CTEXT_50625: decrease_stat @4 by  @300D6: if  00019:   @3 >  32767004D: jump_if_false £CTEXT_8000E: @3 -=  327670002: jump £CTEXT_5:CTEXT_8000A: @4 +=  1000A: @0 +=  100D6: if  0003B:    @6 == @0004D: jump_if_false £CTEXT_20001: wait  5000 ms0050: gosub £CTEXTCLEARALL0004: $DISPLAY  =  0004E: end_thread:CTEXTCLEARALL03E6: remove_text_box03EB: clear_small_messages_only00BE: print_now_clear_all0051: return

 

 

No offense intended. I just really enjoy compressing existing code. The above only requires 2 globals as well. One key fix is that you checked if var >= 32767 when I'm almost certain you want if var > 32767. VERY awesome development!

no offence taken, i have had no time to write footprint while i have had it ready for something else.

nice, well compressed.

but my idea was to create thread that runs all mechanics so you can access it from any part of script.

 

but i like it, not perfect solution but i will never ever use gxt files again. as i can create text directly for each displayed and print it onscreen at any time.

 

i wonder if there is more pearls like that inside this chunk, 256kb i pretty nothing but...

Edited by PLPynton

Sorry. With the advancements I've made with savegame compatibility, DMA, reduced globals, etc are always a goal of mine even when I don't mean to. I'm sure the MAIN thread there could be expanded upon easily enough.

 

Hey, can you give us a step by step as to how this works exactly? How you arrived at the numbers you chose, how to spark it showing up in game, etc. I must confess I'm a little curious and can't readily tell by looking at it. blush.gif

perticular memory address leads to corner text box. whenever change detected the hame starts to display a text box for some period of time dependent of lenghtof the text.

i will fly over my code birefly:

$MESSAGE specify a variation of text used to display

$TIME custom time in ms after which text box will dissapear

$STAT number for stat where the perticular memory adress is located

$CTMAX (max lenght of memory chunk for perticular text) overload protection. absolutely necessary in my opinion because it forces you to give it in order to not to go above memory range (what causes game crash)

$COUNT since an array is used not in its full capacity you have to specify how many blocks are used to be filled with text

$CTEXT(@0,50i) here the text data is stored as 4 bytes long per each

 

idea was to store hundreds of coded messages in mission. then whenever you have necesity to put custom text instead of displayed by default or you like to bring your own message:

set message number, launch and forget about it the text appears. or you set message, launch mission THEN run opcode with default text and after few ms lunch thread to exchange original message data.

 

text is normal code! 4 bytes (signs) you have to count into 4bytes integer. its value you put into this array.

 

i understand you shortened my code and removed all of the protections but you can see that after that it is bearly capable of 33% original capabilities. but you are right the code of mine was far away of being optimized or whatsoever.

 

 

The only way I limited the code was rendering the mission capable of 2 different messages. Since the code I was working with also only made provisions for 2 codes, it works the same. Even your offered code could not accomodate more than 2 since you only sniffed for 2 keypresses. Anybody capable of understanding this stuff will also know how to set ONE global var as per their own triggers and then launch the mission. As for overrun protection: necessary? Yes. Necessary in the code itself? No. If you publish "Hey guys, don't use messages longer than X in this code" then you've satisfied your requirement to let us know while allowing the code to be that much smaller.

 

I'm still not entirely clear how you arrived at the values though. As you know from my works with SCM-based mem-hacking and such, I'm familiar with converting 4 bytes to hex and using their int representation, etc... But I'm still not clear on what values you'd use for A, B, C, and so forth. Is it standard ASCII where 65 (I believe) is A and it counts up from there or what?

here is an example for codes coresponding to some letters

 

user posted image

 

word "FINE" as 4b int has a value of 1162758470

 

be aware of fact that:

-SA print function does not display some cases like 2 spaces one after another... (i believe unter space works fine for that)

-you have to clear containment of old memory cells is order to display different message properly

 

Very good. I assumed it was that sort of ASCII map thing (though I had the value wrong).

Actually, you had the value spot on. On that screen cap, A is 0x41 which is 65 in decimal. wink.gif

 

I was playing with PLPynton's text routines a little bit and you can sorta type the text directly using the "long string variable" type. There are two problems with that, though. The first is that everything gets shifted to upper case; the second is that you seem to be forced to use underscores instead of spaces (at least Sanny complains about spaces), and underscores apparently don't word wrap. So this seems to be mainly useful only for short messages. Examples:

 

Short text, works pretty good aside from capitalization.

 

:CTDATA_M010004: $STAT =  50784// integer values0004: $TIME  =  5000// integer values0004: $CTMAX  =  75// integer values// Long strings are 16 bytes, so size goes from 75 to 18 (with 3 leftover bytes)// Count is ( (total characters +1) / 4 )0@ = 006D1: $CTEXT(0@,18v) = "Hello_World." 0004: $COUNT  =  4// integer values0002: jump @CTDATA_M07

 

user posted image

 

Long text; Houston, we have a problem

 

:CTDATA_M000004: $STAT =  50784// integer values0004: $TIME  =  5000// integer values0004: $CTMAX  =  75// integer values0@ = 006D1: $CTEXT(0@,18v)  =  "This_is_a_test_o"0@ = 106D1: $CTEXT(0@,18v)  =  "f_the_emergency_"0@ = 206D1: $CTEXT(0@,18v)  =  "broadcast_system"0@ = 306D1: $CTEXT(0@,18v)  =  "._This_is_only_a"0@ = 406D1: $CTEXT(0@,18v)  =  "_test."0004: $COUNT  =  18// (total characters + 1) / 40002: jump @CTDATA_M07

 

user posted image

 

======================

 

@pedescobar: mate thanks for that address, i will check it thru. it might be it if i can get into this memory range!

edit: yes that was it, changed few bits in it and works but unfortunatelly i cannot get anywhere else except <0x00B78E20 thru 0x00BB8E1C> have you find any mathod to get outside it?

what a shame we can not access memory range to put piece of code in it.

The range of useful addresses I've found is similar to yours, although I still don't understand where negative stat IDs point. I don't think we'll be getting outside of that range via the stat opcodes, but Xieon's patch looks like the Holy Grail of SCM memory-hacking anyhow wink.gif

 

These are the memory locations I've been able to get to through the stats:

 

Offset-H  Offset-D  Stat ID========  ========  ========0xB78F68  12029800  stat 82  (always read as 4b INT)  ...       ...       thru0xB78FFC  12029948  stat 119 (always read as 4b INT)0xB79000  12029952  stat 120 (properly-handled INTs)   ...       ...       thru0xB79378  12030840  stat 342 (properly-handled INTs) 0xB7937C  12030844  stat 343 (always read as 4b INT) 0xB79380  12030848  stat 344 (always read as 4b INT) or 0  (properly-handled floats)  ...       ...       thru0xB794C4  12031172  stat 425 (always read as 4b INT) or 81 (properly-handled floats)0xB794C8  12031176  stat 426 (always read as 4b INT)  ...       ...       thru0xBB8E1C  12291612  stat 65535 (always read as 4b INT)

 

 

EDIT: I'm now confident that negative stat IDs don't point anywhere new.

stat -1 is the same as stat 65535,

stat -2 is the same as stat 65534,

and it continues on from there with stat -X being equivalent to stat 65536-X

 

So, the full useful range of stat id numbers appears to be 0-65535 with stats 82-65535 spanning the entire memory range of 0xB78F68 - 0xBB8E1F and stats 0-81 overlapping a small part of that range but providing true float access to that part.

Edited by pdescobar
Xieon's patch looks like the Holy Grail of SCM memory-hacking anyhow wink.gif

I respectfully and humbly disagree. His work is AMAZING and the type selector is tits and then some.

 

However, I feel (and Y_Less agrees) that a purely SCM-based solution is prefered. This thread here opens up X% of it. Y_Less has published a tentative method, etc. Not everybody's going to be willing to patch their EXE.

 

Awesome advancement though, sir. Is there any known limit to verlenstr's? I know that when stored in vars, they're limited to 16, but original code has shown me at least one example of 17 chars. Also, have you tested spaces in SAMB?

 

Xieon's patch looks like the Holy Grail of SCM memory-hacking anyhow wink.gif

I respectfully and humbly disagree. His work is AMAZING and the type selector is tits and then some.

 

However, I feel (and Y_Less agrees) that a purely SCM-based solution is prefered. This thread here opens up X% of it. Y_Less has published a tentative method, etc. Not everybody's going to be willing to patch their EXE.

Okay, so you caught me in some hyperbole. A purely SCM-based solution is obviously preferable, but those aren't too far advanced currently. Xieon's patch isn't really the Holy Grail since it does require modifying the exe, but for now it is the most simple and flexible method for SCM-based memory-hacking in SA and it reaches pretty well everywhere with its support for virtualprotect. So please pardon my overenthusiasm. wink.gif

 

 

Awesome advancement though, sir. Is there any known limit to verlenstr's? I know that when stored in vars, they're limited to 16, but original code has shown me at least one example of 17 chars. Also, have you tested spaces in SAMB?

Haven't tested in SAMB since I got sidetracked with my radio project. Regarding length, I really don't know, but I do find it interesting that you can assign the a full 16-byte string to a variable rather than having to limit to 15 with a null-terminator. (assuming they're stored as c-style strings)

Well until we (read: me; I'm all wet when it comes to most forms of mem-hacking) get a list of supported EXE's, I'm not sure you can count on my vote in the simplicity column. If that one patch works on all common EXE's, okay.

 

I'm not sure how it works exactly. I know that in all my efforts (compacting of MAIN threads for TTSA), nothing crashed the game. Storing a 17 byte varlenstr and then reading it, only provided the 16 bytes. Then when I did in fact store the full 16 (and therefore not the terminator), it read all 16 and was able to manipulate them accordingly. Maybe it's because I was using vars. Try it raw (by plucking the terminator with a hex editor) and I'm sure you'd see problems. The ONLY reason that bothers me is because unless you're using a varlenstr array, there's no need to have a finite cap of 16 bytes. And the part that REALLY mystifies me is that if the engine is going to assume 16 bytes on retrieval, then why did they bother naming animations and such with 17+ bytes? *scratches head*

 

What would REALLY be keen is if we could figure out a way to tie the debug functions into this. Every time I think varlenstr's, I drool over the degub commands that SEEM to be built in free texters.

I did some more testing on using long string variables. SAMB also refuses to compile with spaces in the string, but if I hex-edit the compiled SCM and turn the underscores into spaces, it works properly in-game and line-wraps inside the box. And the reason the text displays as uppercase is because the compilers (both of them) make that adjustment.

 

I did some more testing on using long string variables. SAMB also refuses to compile with spaces in the string, but if I hex-edit the compiled SCM and turn the underscores into spaces, it works properly in-game and line-wraps inside the box. And the reason the text displays as uppercase is because the compilers (both of them) make that adjustment.

I can remove both of the limits (capitalization and spaces inaccessibility).

 

So, please, test if the game is able to support some special bytes within long strings, like #9 (TAB), #13#10 (carriage return), and some else. If they are supported, I can make the compiler compile the line with such chars (with c-like method: using \n instead of #13#10 as carriage return, for example).

 

So, it will allow to use the strings like

"Line 1 text \n Line 2 text"

which will be displayed as two-lined message.

 

Not sure if the game is able to parse them, but if so I think it would be very useful.

Edited by Seemann

 

I did some more testing on using long string variables. SAMB also refuses to compile with spaces in the string, but if I hex-edit the compiled SCM and turn the underscores into spaces, it works properly in-game and line-wraps inside the box. And the reason the text displays as uppercase is because the compilers (both of them) make that adjustment.

I can remove both of the limits (capitalization and spaces inaccessibility).

That would be excellent. icon14.gif

 

 

So, please, test if the game is able to support some special bytes within long strings, like #9 (TAB), #13#10 (carriage return), and some else. If they are supported, I can make the compiler compile the line with such chars (with c-like method: using \n instead of #13#10 as carriage return, for example).

 

So, it will allow to use the strings like

"Line 1 text \n Line 2 text"

which will be displayed as two-lined message.

 

Not sure if the game is able to parse them, but if so I think it would be very useful.

All of those special characters (TAB, CR, and LF) are basically interpreted the same as underscores -- they wind up being single non-breaking spaces. However, the game already has a provision for embedding newlines via "~n~". Off-hand, the only special character I think you'd need to support is a way to escape single and double quotes. For example, making it so that

 

"Test\"Test\'Test"

 

gets compiled as a single long string containing

 

Test"Test'Test

 

Embedded quotes like that do display properly if hex-edited in, although I didn't test that one until after I took the below screenshot of the other tests.

 

user posted image

 

====================

 

Also, I'm now pretty sure that negative stat IDs don't point anywhere new; I edited a note into my previous post which discussed the memory range and will probably update the first post to more accurately reflect our new knowledge later on.

 

Off-hand, the only special character I think you'd need to support is a way to escape single and double quotes.

Now, SB 2.98 supports the single quotes within "", and the double quotes within ''

(for example: "'single'", '"double"')

 

but OK, I'll try to implement an escape char. (EDIT: Done.)

 

 

Edit:

 

A litte question too.

 

Does the game support both of the variants ~n~ and ~N~, or ~n~ only?

I just want to implement \n constant, which will be replaced with ~n~ (I think \n is more understable to use).

 

So, the line "line 1 \n line 2" will be compiled as "line 1 ~n~ line 2".

 

Also, I've implemented \s constant which is extra space within the string.

So, the line "Sanny \s\s\s\ Builder" have to be displayed as

"Sanny     Builder"  // 5 spaces

in-game.

 

Single space between the words is also supported.

Edited by Seemann

stat 48694-50453 is a table (known as well as pool) for all possible radar makers.

174 markers as game maximum, 10 "stat numbers" per one marker.

marker 1 breakdown (i will not attempt to breake it down completely)

Stat 48694 MAPMARKER001-COORD X [float]

Stat 48695 MAPMARKER001-COORD Y [float]

Stat 48696 MAPMARKER001-COORD Z [float]

Stat 48697 MAPMARKER001-COUNTER

Stat 48698 MAPMARKER001-RADIUS (POI cylinder) [float]

Stat 48699 MAPMARKER001-unknown

Stat 48700 MAPMARKER001-unknown

Stat 48701 MAPMARKER001-texture,radar,visibility,unused= corresponds bytes 0-3

Stat 48702 MAPMARKER001-unknown 1b bitmask

Stat 48703 MAPMARKER001-unknown 2b bitmask

 

actually it does not add nothing special into mission coding except that you can read/write all the parameters. for someone with good imagination it can be really useful

 

EDIT: i have found something much more useful for mission coding. objects parameters definitions table!

it is located in range 61212 through 64351. 156 object entries, 20 "stat numbers" per each.

example object [bouy] breakdown (complette)

Stat 62032 OBJECT -BOUY MASS

Stat 62033 OBJECT -BOUY TURNMASS

Stat 62034 OBJECT -BOUY AIR RESISTANCE

Stat 62035 OBJECT -BOUY ELASTICITY

Stat 62036 OBJECT -BOUY PERCENTAGE SUBMERGED

Stat 62037 OBJECT -BOUY UPROOT LIMIT

Stat 62038 OBJECT -BOUY CDMULTIPLIER

Stat 62039 OBJECT -BOUY CDEFFECT,SPCDRESPONSEC,CAMAVOID,CEXPLOSION

Stat 62040 OBJECT -BOUY FX_TYPE,Unused,Unused,Unused

Stat 62041 OBJECT -BOUY FX_OFFSET X

Stat 62042 OBJECT -BOUY FX_OFFSET Y

Stat 62043 OBJECT -BOUY FX_OFFSET Z

Stat 62044 OBJECT -BOUY FX_NAME (internal identifier)

Stat 62045 OBJECT -BOUY SMASH MULTIPLIER

Stat 62046 OBJECT -BOUY BREAK VELOCITY X

Stat 62047 OBJECT -BOUY BREAK VELOCITY Y

Stat 62048 OBJECT -BOUY BREAK VELOCITY Z

Stat 62049 OBJECT -BOUY BREAK VELOCITY RANDOMNESS

Stat 62050 OBJECT -BOUY GUN BREAK

Stat 62051 OBJECT -BOUY PRODUCE SPARKS

 

i believe that i do not have to comment how deamn great is to have access to object parameters alright.

 

i someone will bother to mess with vehicle table (as i wanted to do for Tomworld and Picolini) you have to chose Xien's memory patch for exe with DMA opcodes 'cause the table is located at memory cell C2B9E0h (56x4b per entry).

Edited by PLPynton
  • 2 weeks later...

as ordered:

 

Stat 04080 HUD-BREATHMETER- current value

 

by the maens of original script conditions it is 4byte float with max valueof 1150.0 so you have to get it increased to prevent breathmeter to drop dramatically. max value is stored at some offset much higher than stats can get but is protected after all because is computed.

To get an approximation of the current breath meter maximum, you can take the base 1150.0 and add 1.5 * stat_225 (lung capacity). So, with a lung capacity of 200, the breath meter maxes at approx 1450.0 and with a lung capacity of 1000, the breath meter maxes at approx 2650.0. There's some roundoff error though so that value is around +/- 5.0 from the true maximum.

 

EDIT: Some sample code; quick & dirty just to illustrate accessing the values.

 

:BreathMeter0652: 1@ = stat 4080 // Current Breath Meter Value (FLOAT even though INT opcode used)0653: 2@ = stat 225 // Lung Capacity  (FLOAT)2@ *= 1.52@ += 1150.0  // Now 2@ is approximate Breath Meter max// Simple Text Display:0092: 1@ = float_to_integer 1@0092: 2@ = float_to_integer 2@02FD: text_2numbers_lowpriority 'TIME' 1@ 2@ 100 ms 1  // ~1~:~1~wait 100jump @BreathMeter 

 

Edited by pdescobar

stat 00082 STAT_INC_SNIPERRIFLE_SKILL (ar_stats.dat)

stat 00083 STAT_DEC_FAT (ar_stats.dat)

stat 00084 STAT_DEC_BODY_MUSCLE (ar_stats.dat)

stat 00085 STAT_DEC_MAX_HEALTH (ar_stats.dat)

stat 00086 STAT_EXERCISE_RATE_CYCLE (ar_stats.dat)

stat 00087 STAT_EXERCISE_RATE_CYCLE_SPRINT (ar_stats.dat)

stat 00088 STAT_EXERCISE_RATE_SWIM (ar_stats.dat)

stat 00089 STAT_EXERCISE_RATE_SWIM_SPRINT (ar_stats.dat)

stat 00090 STAT_EXERCISE_RATE_SPRINT (ar_stats.dat)

stat 00091 STAT_EXERCISE_RATE_RUN (ar_stats.dat)

stat 00092 STAT_EXERCISE_RATE_FIGHT (ar_stats.dat)

stat 00093 STAT_TIMELIMIT_CYCLE_STAMINA (ar_stats.dat)

stat 00094 STAT_TIMELIMIT_SWIM_STAMINA (ar_stats.dat)

stat 00095 STAT_TIMELIMIT_SPRINT_STAMINA (ar_stats.dat)

stat 00096 STAT_TIMELIMIT_RUNNING (ar_stats.dat)

stat 00097 STAT_TIMELIMIT_DRIVING_SKILL (ar_stats.dat)

stat 00098 STAT_TIMELIMIT_FLYING_SKILL (ar_stats.dat)

stat 00099 STAT_TIMELIMIT_CYCLE_SKILL (ar_stats.dat)

stat 00100 STAT_TIMELIMIT_MOTORBIKE_SKILL (ar_stats.dat)

stat 00101 STAT_TIMELIMIT_BOAT_SKILL (ar_stats.dat)

stat 00102 STAT_TIMELIMIT_FAT_ADJUST (ar_stats.dat)

stat 00103 STAT_TIMELIMIT_FAT_ADJUST_STRENUOUS (ar_stats.dat)

stat 00104 STAT_TIMELIMIT_BREATH_UNDERWATER (ar_stats.dat)

stat 00105 STAT_TIMELIMIT_MAX_HEALTH (ar_stats.dat)

stat 00106 STAT_TIMELIMIT_PISTOL_SKILL (ar_stats.dat)

stat 00107 STAT_TIMELIMIT_PISTOL_SILENCED_SKILL (ar_stats.dat)

stat 00108 STAT_TIMELIMIT_DESERT_EAGLE_SKILL (ar_stats.dat)

stat 00109 STAT_TIMELIMIT_SHOTGUN_SKILL (ar_stats.dat)

stat 00110 STAT_TIMELIMIT_SAWNOFF_SHOTGUN_SKILL (ar_stats.dat)

stat 00111 STAT_TIMELIMIT_SPAS12_SHOTGUN_SKILL (ar_stats.dat)

stat 00112 STAT_TIMELIMIT_MICRO_UZI_SKILL (ar_stats.dat)

stat 00113 STAT_TIMELIMIT_MP5_SKILL (ar_stats.dat)

stat 00114 STAT_TIMELIMIT_AK47_SKILL (ar_stats.dat)

stat 00115 STAT_TIMELIMIT_M4_SKILL (ar_stats.dat)

stat 00116 STAT_TIMELIMIT_SNIPERRIFLE_SKILL (ar_stats.dat)

stat 00117 STAT_TIMELIMIT_DEATH_HEALTH (ar_stats.dat)

stat 00118 STAT_TIMELIMIT_ADD_TO_HEALTH (ar_stats.dat)

 

it could have been posted before, in this case that will be supreme confirmation.

Edited by PLPynton

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 0 User Currently Viewing
    0 members, 0 Anonymous, 0 Guests

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.