Staredit Network > Forums > Modding Assistance > Topic: GPTP & Assembly line Assistance
GPTP & Assembly line Assistance
Apr 24 2016, 8:46 am
By: KYSXD  

Apr 24 2016, 8:46 am KYSXD Post #1



Hi!

I was working with assembly line and found this lines:

Code
0047B2E0        MOV AX,WORD PTR DS:[EAX+64]
0047B2E4        CMP AX,6A
0047B2E8        JE SHORT StarCraf.0047B32F
0047B2EA        CMP AX,6F
0047B2EE        JE SHORT StarCraf.0047B32F
0047B2F0        CMP AX,71
0047B2F4        JE SHORT StarCraf.0047B32F
0047B2F6        CMP AX,72
0047B2FA        JE SHORT StarCraf.0047B32F
0047B2FC        CMP AX,82
0047B300        JE SHORT StarCraf.0047B32F
0047B302        CMP AX,83
0047B306        JE SHORT StarCraf.0047B32F
0047B308        CMP AX,84
0047B30C        JE SHORT StarCraf.0047B32F
0047B30E        CMP AX,85
0047B312        JE SHORT StarCraf.0047B32F
0047B314        CMP AX,9A
0047B318        JE SHORT StarCraf.0047B32F
0047B31A        CMP AX,0A0
0047B31E        JE SHORT StarCraf.0047B32F
0047B320        CMP AX,0A7
0047B324        JE SHORT StarCraf.0047B32F
0047B326        CMP AX,9B
0047B32A        JE SHORT StarCraf.0047B32F
0047B32C        XOR EAX,EAX
0047B32E        RETN
0047B32F        MOV EAX,1
0047B334        RETN


Are they equivalent to the following?

Code
int function_0047B2E0(CUnit *unit) {
    switch(unit->id) {
        case UnitId::TerranCommandCenter:
        case UnitId::TerranBarracks:
        case UnitId::TerranFactory:
        case UnitId::TerranStarport:
        case UnitId::ZergInfestedCommandCenter:
        case UnitId::ZergHatchery:
        case UnitId::ZergLair:
        case UnitId::ZergHive:
        case UnitId::ProtossNexus:
        case UnitId::ProtossGateway:
        case UnitId::ProtossStargate:
        case UnitId::ProtossRoboticsFacility:
            return 1;
            break;
        default: return 0;
            break;
    }
}


And, how i should add this in GPTP?

I was thinking in:
Code
namespace hooks {
 void injectExperimental_0047B2E0() {
   jmpPatch(function_0047B2E0, 0x0047B2E0, 0);
 }

}


And add "injectExperimental_0047B3E0()" to "initialize.cpp", but that didn't work.

Thanks!
KYSXD

Post has been edited 1 time(s), last time on May 28 2016, 8:33 pm by KYSXD.



None.

Apr 24 2016, 9:58 am Neiv Post #2



Since the function at 0047B3E0 takes the input unit in eax, but you can't represent that in C code, you'll have to write a wrapper for it like so:

Code
void __declspec(naked) func0047B3E0_Wrapper() {
 CUnit *unit;
 int result;

 __asm {
   PUSHAD
   MOV EBP, ESP
   MOV unit, EAX
 }

 result = function_0047B2E0(unit);

 __asm {
   POPAD
   MOV EAX, result
   RETN
 }
}



And then do jmpPatch(func0047B3E0_Wrapper, 0x0047B2E0, 0);



None.

Apr 24 2016, 10:09 pm UndeadStar Post #3



I never use switch, but shouldn't it be "default:" (like the "case" format)?
For the wrapper, it would be:
Code
void __declspec(naked) func0047B2E0_Wrapper() {

CUnit *unit;
Bool32 result;

__asm {
  MOV unit, EAX
  PUSHAD
}

result = function_0047B2E0(unit);

__asm {
  POPAD
  MOV EAX, result
  RETN
}
}

and for the jump patch: "jmpPatch(func0047B2E0_Wrapper, 0x0047B2E0, 3);"
But you can just not add the 3 (the point of filling that is that if somebody memory edit the modded Starcraft, he won't see weird instructions born from half-cut assembly instructions, thanks to "nop" instructions filling the gap).

edit: fixed the fact that sometimes it was written 3E0 and sometimes 2E0 (2E0 being the correct way).
Also, if you just returned a value based on the result of unit->isFactory(), you could choose what's a factory or not with a dat editor.
And finally, in your switch, you wrote Necus instead of Nexus (but I guess VS would help you fix this kind of mistake)

Post has been edited 1 time(s), last time on Apr 25 2016, 11:18 am by UndeadStar.



None.

Apr 25 2016, 4:08 am O)FaRTy1billion[MM] Post #4

👻 👾 👽 💪

Quote from Neiv
Since the function at 0047B3E0 takes the input unit in eax, but you can't represent that in C code, you'll have to write a wrapper for it like so:
You can use __fastcall, or is that ECX?



TinyMap2 - Latest in map compression! ( 7/09/14 - New build! )
EUD Action Enabler - Lightweight EUD/EPD support! (ChaosLauncher/MPQDraft support!)
EUDDB - topic - Help out by adding your EUDs! Or Submit reference files in the References tab!
MapSketch - New image->map generator!
EUDTrig - topic - Quickly and easily convert offsets to EUDs! (extended players supported)
SC2 Map Texture Mask Importer/Exporter - Edit texture placement in an image editor!
\:farty\: This page has been viewed [img]http://farty1billion.dyndns.org/Clicky.php?img.gif[/img] times!

Apr 26 2016, 5:06 pm KYSXD Post #5



Thanks, Neiv, it worked fine. I'll have to remember that for future works.

UndeadStar, I corrected all those problems, thanks. The main reason i started that was to practice assembly line convertion, i found those lines and thought them could be easy to start.



None.

May 28 2016, 9:09 pm KYSXD Post #6



Working with some functions i almost achieve a full 640x480 game layer render, but i got some troubles with some functions.

Without modifications or patch, starcraft's behaviour looks like this:



After patch:



I didn't convert all the assembler to C++ functions, just changed some values that 'make sense' to me.

The only problems i got are with these functions (Names from heinermann's Broodwar mapping):

(Patch on these causes to 'repeat' the terrain from the top of the screen, in the place where the black section is)
0x0040C200 - BlitToBitmap
0x0040C253 - blitTileCache
0x0040C2BD - BlitTerrainCacheToGameBitmap

(Patch on this causes crash when any sprite tries to load mirror directions)
0x004D57B0 - CImage__updateGraphicData

(Patch on this causes the gradient on the bottom of the screen)
0x004808E0 - updateAllFog

I'd like to understand what those functions are doing in order to know what changes i should make, but my conversion skills aren't good (I tried a few times, but i get lost eventually)

Could anyone translate these functions to C code?



None.

May 29 2016, 7:11 am Heinermann Post #7

SDE, BWAPI owner, hacker.

Not entirely accurate, but draws the game tiles correctly (in a separate SDL window): https://github.com/bwapi/bwapi/blob/SDL-Experiment/bwapi/BWAPI/GameRender.cpp

EDIT: That code doesn't use a cache like Starcraft does because it's not 1998 anymore.

Post has been edited 1 time(s), last time on May 29 2016, 8:34 am by Heinermann.




May 29 2016, 7:14 pm KYSXD Post #8



Quote from Heinermann
Not entirely accurate, but draws the game tiles correctly (in a separate SDL window): https://github.com/bwapi/bwapi/blob/SDL-Experiment/bwapi/BWAPI/GameRender.cpp

EDIT: That code doesn't use a cache like Starcraft does because it's not 1998 anymore.

Wow! I'll take a look on it. Thanks!



None.

Oct 20 2016, 10:32 am UndeadStar Post #9



I have a piece of code I'm currently keeping in assembly because I don't get what it does exactly.
Maybe it's an optimization of an easy manipulation, so I will share it here in case somebody get what it's doing and can explain:

Code
        __asm {
            PUSHAD
            MOV CL, pathingFlags
            MOV AL, elevationLevel
            CMP AL, 0x0C
            SETB AL
            XOR AL, CL
            AND AL, 0x01
            XOR CL, AL
            MOV pathingFlags, CL
            POPAD
        }

        unitToLoad->pathingFlags = pathingFlags;


edit: I'm especially confused with the XOR.The objective of course is to get a C code doing the same thing in a more readable way.
edit2: thank you for your help

Post has been edited 1 time(s), last time on Oct 25 2016, 7:04 am by UndeadStar.



None.

Oct 20 2016, 2:53 pm O)FaRTy1billion[MM] Post #10

👻 👾 👽 💪

It's ternary operator optimized to have no jump instructions, which is usually the case when you see things like SETB (which sets the specified register to 1 if the condition is true, otherwise sets it to 0)

It seems to be doing unitToLoad->pathingFlags = (elevationLevel < 0xC) ? pathingFlags | 1 : pathingFlags & ~1;
Basically setting flag 0x1 if elevationLevel < 12 an clearing it otherwise.

Post has been edited 1 time(s), last time on Oct 20 2016, 3:00 pm by FaRTy1billion.



TinyMap2 - Latest in map compression! ( 7/09/14 - New build! )
EUD Action Enabler - Lightweight EUD/EPD support! (ChaosLauncher/MPQDraft support!)
EUDDB - topic - Help out by adding your EUDs! Or Submit reference files in the References tab!
MapSketch - New image->map generator!
EUDTrig - topic - Quickly and easily convert offsets to EUDs! (extended players supported)
SC2 Map Texture Mask Importer/Exporter - Edit texture placement in an image editor!
\:farty\: This page has been viewed [img]http://farty1billion.dyndns.org/Clicky.php?img.gif[/img] times!

Options
  Back to forum
Please log in to reply to this topic or to report it.
Members in this topic: None.
[06:25 pm]
m.0.n.3.y -- Here's another question. I'm using switch randomization for powerups. There are 9 powerups, and I only want any of the powerups to appear only about 30% of the time. So I was just going to use 5 switches for a total of 32 options and have the other 23 results restart the randomization process. Is there a better way to do this?
[06:04 pm]
m.0.n.3.y -- NudeRaider
NudeRaider shouted: m.0.n.3.y Pro and Demon already gave correct answers, but let me add a pretty elegant way: Have the detection trigger owned by whoever is convenient for you. A single computer player, a force, all players - it doesn't matter. Now detect for the arbiter in conditions - also doesn't really matter how. In actions just set a dc to 1 for all players or the force that should have the text displayed. It will set the dc for each player to 1 individually. Because of this you can make a 2nd trigger that checks for the dc for current player and remove the dc for current player afterwards.
Ok that makes perfect sense NudeRaider
NudeRaider shouted: This method also has a bonus use: If you detect the arbiter in conditions for current player (set trigger owned accordingly!) then you can do the following: Add 1 to dc for current player AND add 1 to dc for all players. And in your 2nd trigger you can distinguish between players that just are informed and the player that actually had it, because their dc will be 2 instead of 1. So you can give them an additional reward or something dynamically.
Wow that's awesome! I'll definitely be doing this. Thanks for the tip, that's really cool
[05:29 pm]
NudeRaider -- This method also has a bonus use: If you detect the arbiter in conditions for current player (set trigger owned accordingly!) then you can do the following: Add 1 to dc for current player AND add 1 to dc for all players. And in your 2nd trigger you can distinguish between players that just are informed and the player that actually had it, because their dc will be 2 instead of 1. So you can give them an additional reward or something dynamically.
[05:27 pm]
NudeRaider -- m.0.n.3.y
m.0.n.3.y shouted: NEW QUESTION: How is it possible to show text to all players when something occurs? EX: Player 1 builds an Arbiter. Trigger says, When player 1 builds an Arbiter, do something, then remove the Arbiter. Now, I'd like text to show for all other players when P1 builds an Arbiter that says "P1 built an arbiter!". But how is this possible when the the original trigger that detects if P1 built an Arbiter then removes the Arbiter in it's actions? Like, the Arbiter is detected as built, then Action occurs for P1, then Arbiter is removed. So how can you detect if the Arbiter is built to show text to the other plays saying "P1 built an Arbiter" if the other trigger quickly removes the Arbiter? Does that make sense?
Pro and Demon already gave correct answers, but let me add a pretty elegant way: Have the detection trigger owned by whoever is convenient for you. A single computer player, a force, all players - it doesn't matter. Now detect for the arbiter in conditions - also doesn't really matter how. In actions just set a dc to 1 for all players or the force that should have the text displayed. It will set the dc for each player to 1 individually. Because of this you can make a 2nd trigger that checks for the dc for current player and remove the dc for current player afterwards.
[05:22 pm]
NudeRaider -- that's why the All Players thing is neat: When one player runs a wait, their copy of hypers will actually be blocked. But the hyper effect will not be disrupted because the hypers of all the other players are still running.
[05:21 pm]
NudeRaider -- *running at the same time for the same player.
[05:20 pm]
NudeRaider -- m.0.n.3.y
m.0.n.3.y shouted: Mini Moose 2707 Shit. Ok what are the exact circumstances where using wait triggers causes wait blocks and messes things up? EX: If player 8 is a computer and has hyper triggers at the bottom of his list, can I use a few of triggers on each human player 1-6 with a few waits each lasting 50 - 1000ms? I've read the articles in SEN Wiki but still not super clear on it :/
simple: 2 waits running at the same time. Hyper triggers constantly block each other, but they have no other purpose than to force another trigger loop, and stay in that "blocking each other" state as long as possible (=NEO)
[05:17 pm]
NudeRaider -- Dem0n
Dem0n shouted: It's recommended to never use waits if you have hyper triggers.
yes and no. If you have to ask: yes. If you know what you're doing, you can use them in a non-disruptive manner.
[05:15 pm]
NudeRaider -- m.0.n.3.y
m.0.n.3.y shouted: ALSO: @NudeRaider for your "other setup" you mean give the hypers to the "All Players" player checkbox, not to each player individually, right?
That's equivalent. At the start of a game sc parses triggers and creates copies of triggers owned by player groups (forces and all players) to each player that is part of that group. During runtime there's only individual trigger owners.
[04:04 pm]
m.0.n.3.y -- Dem0n
Dem0n shouted: That won't work. And it's one extra trigger with 2 actions. Hardly extra work.
You're right. Thank you!
Please log in to shout.


Members Online: Roy, m.0.n.3.y, Wing Zero