This is pure theory. You can just skip it if you're not interested in.
TL;DR- SetMemory(0x6509B0, SetTo, EPD(address to pointer))
: Copy pointer value to 0x6509B0, but divide it by 4 while copying. (You should know how if you're reading this)
- SetDeaths(CurrentPlayer, Anything, YouWant, 0)
=====
In C, we call variable having address to other values as value '
pointer'.
ex) In SC, 4byte at 0x5993D4 has address to STR section as a value, so we say
- 0x5993D4 is a pointer to STR section.
Here we create simple example that does:
- Create 1 Protoss Zealot
- Set that zealot's shield to 30.
- Repeat these steps for every trigger loop.
-------
SC manages unit by
Doubly Linked List.
WikiIn short, every unit has 'previous unit' and 'next unit'. You can access any unit by following those links.
These links are also pointers, but we won't use them here.
Here's SC's inner workings on making a unit:
1. Pop an element from 'Empty unit list'.
2. Push that to 'Used unit list'.
3. Initialize unit structure.
Here we will hook step 1. Before SC pops unit from empty list, we will get. what unit SC will pop.
We can get those using address 0x628438. 0x628438 is a pointer to the first 'empty' unit. It will be popped.
So we read value there and store it somewhere. Here's simple pseudocode for doing it.
if Memory(0x628438, AtLeast, 2^31) then SetMemory(0x628438, Subtract, 2^31); SetDeaths(P1, Add, 2^31, "Marine"); SetDeaths(P1, Add, 2^31, "Firebat"); end
// Everyone knows how to copy death values. We'll skip the details here
-------
Create zealot. Fine.
Next we'll update that zealot's shield.
This is what
CUnit.h says.
/*0x060*/ u32 shieldPoints; // BW shows this value/256, possibly not u32?
So we need to modify value at (addressToZealot + 0x60) to (30*256)
But addressToZealot is not fixed: They are not constant. We can't just make trigger out of it.
So we use CP trick.
Our goal is to simulate the action:
SetDeaths(EPD(addressToZealot + 0x60), SetTo, 30*256);
->
SetDeaths(EPD(addressToZealot) + (0x60 / 4), SetTo, 30*256);
EPD(addressToZealot) is variable, so we can't just put them right into trigger editor.
We indirectly put them to action using Current Player.
// SetCurrentPlayer(EPD(addressToZealot) + (0x60 / 4))
SetMemory(0x6509B0, SetTo, EPD(addressToZealot));
SetMemory(0x6509B0, Add, 24);
SetDeaths(CurrentPlayer, SetTo, 30*256);
The only non-constant part here is
SetMemory(0x6509B0, SetTo, EPD(addressToZealot));-------
We implement them by copying addressToZealot to 0x6509B0. Like this
if Always() then
SetMemory(0x6509B0, SetTo, (-0x58A364 // 4));
end
if Deaths(P1, AtLeast, 2^31, "Marine") then
SetMemory(0x6509B0, Add, 2^29);
SetDeaths(P1, Subtract, 2^31, "Marine");
end
// Skip details here
Note that we
- divide P1's marine deaths value by 4 while copying.
- doesn't repair P1's marine deaths value since it's just a temporary value.
So now we have EPD(addressToZealot) in CurrentPlayer. Just add two triggers.
if Always() then
SetMemory(0x6509B0, Add, 24);
SetDeaths(CurrentPlayer, SetTo, 30*256);
SetMemory(0x6509B0, SetTo, 0); // Revert current player to P1
end
Ok. quite simple, isn't it?
-------
Now we'll implement above trigger using TrigEditPlus.
TrigEditPlus uses lua internally, so it supports basic looping.
[collapse]
[code]
-- This text is generated by TrigEditPlus
-- Copy 0x628438 -> Terran Marine
for i = 30, 0, -1 do
Trigger {
players = {P1},
conditions = {
Memory(0x628438, AtLeast, 2^i);
},
actions = {
SetMemory(0x628438, Subtract, 2^i);
SetDeaths(P1, Add, 2^i, "Terran Marine");
SetDeaths(P1, Add, 2^i, "Terran Firebat");
PreserveTrigger();
}
}
end
for i = 30, 0, -1 do
Trigger {
players = {P1},
conditions = {
Deaths(P1, AtLeast, 2^i, "Terran Firebat");
},
actions = {
SetMemory(0x628438, Add, 2^i);
SetDeaths(P1, Subtract, 2^i, "Terran Firebat");
PreserveTrigger();
}
}
end
-- Create zealot
Trigger {
players={P1},
actions={
CreateUnit(1, "Protoss Zealot", "Anywhere", P1);
PreserveTrigger();
}
}
-- Set 0x6509B0 to EPD(0)
Trigger {
players={P1},
actions={
SetMemory(0x6509B0, SetTo, EPD(0));
PreserveTrigger();
}
}
for i = 30, 2, -1 do
Trigger {
players = {P1},
conditions = {
Deaths(P1, AtLeast, 2^i, "Terran Marine");
},
actions = {
SetMemory(0x6509B0, Add, 2^(i-2));
SetDeaths(P1, Subtract, 2^i, "Terran Marine");
PreserveTrigger();
}
}
end
Trigger {
players={P1},
actions={
SetMemory(0x6509B0, Add, 24);
SetDeaths(CurrentPlayer, SetTo, 30*256, 0);
SetMemory(0x6509B0, SetTo, 0);
PreserveTrigger();
}
}