Staredit Network > Forums > Modding Assistance > Topic: Adding new spells through useweapon(iscript) and weapon_fire.cpp
Adding new spells through useweapon(iscript) and weapon_fire.cpp
Dec 1 2015, 11:50 am
By: Eisetley  

Dec 1 2015, 11:50 am Eisetley Post #1



I wonder if someone tried to create a new spell this way. What I have in mind is basically a piece of code executed when a unit uses a weapon with certain id to produce a different effect. I think this would prevent consuming existing spells. My knowledge of C++ is almost non-existent, but I hope someone with more experience would carry on idea.
And there is my experiment. I tried to add blink spell, the one that Stalkers in SC2 have.
1)Added ensnare button to dragoon's button set.
2)Put useweapon 117 instead of castspell opcode in dragoon's icript inside the DragoonCastSpell section.
3)Set unused weapon's no 117 targeting to terrain in weapons.dat.
4)Added this abomination into weapon_fire.cpp
Quote
//Blink
if (unit->id == UnitId::dragoon)
{
//if (unit->unusedTimer = 0)
//{
//if (weapons_dat::Weapon[weaponId] == 117);
{
CUnit *target = unit->orderTarget.unit;
unit->unusedTimer = 40;
u32 TeleportX = unit->orderTarget.pt.x - 20;
u32 TeleportY = unit->orderTarget.pt.y;
unit->position.x = TeleportX;
unit->position.y = TeleportY;

}
When I used the ensnare button nothing besides creating an arclite shock cannon hit effect on the ground happened. So I just made dragoon attack normally and that's when the weird shit started to happen.
https://www.youtube.com/watch?v=9XoRKs1T1Oc&feature=youtu.be
If anyone could help me with making dragoons blink I'd be grateful. The perfect way for me would be blink using 0 energy but having a few seconds delay (probably using unusedTimer would make this possible).

Attachments:
weapon_fire.cpp
Hits: 2 Size: 2.61kb



None.

Dec 1 2015, 1:39 pm Neiv Post #2



I assume you also edited ensnare's tech use requirements in Firegraft, as using the blink button actually does something?

Quote from Eisetley
2)Put useweapon 117 instead of castspell opcode in dragoon's icript inside the DragoonCastSpell section.
As the code you posted says:
Code
   //This hook affects the following iscript opcodes: attackwith, attack, castspell
   //This also affects CUnit::fireWeapon().

Useweapon just spawns the bullet at the target position, skipping the code entirely. You would have to either hook the useweapon function or give the dragoon weapon 117 as second weapon and use attackwith instead.

Quote from Eisetley
3)Set unused weapon's no 117 targeting to terrain in weapons.dat.
I don't think this does anything (without additional code editing). Bw just thinks the dragoon is casting ensnare, and uses its targeting flags/energy/order/etc.

Code
unit->position.x = TeleportX;
unit->position.y = TeleportY;

Moving units properly is far more complicated than that. There are several variables which contain unit's coordinates and they all have to be set. Also unit's pathing state has to be resetted and so on.
You can add the following function, which calls the bw's unit moving code. It should work, but it moves the unit whether or not it actually has space there.. (Disclaimer: I didn't actually test anything; 1.16.1 only)
Code
    const u32 Helper_MoveUnit = 0x004EBAE0;
    void moveUnit(CUnit *unit, s32 x, s32 y) {
        __asm {
            PUSHAD
            MOV edx, unit
            MOV eax, x
            MOV ecx, y
            CALL Helper_MoveUnit
            POPAD
        }
    }


Quote from Eisetley
The perfect way for me would be blink using 0 energy but having a few seconds delay (probably using unusedTimer would make this possible).
I'm not sure where the code that reduces energy is, but you'd have to find it and modify it. Or a messier solution could just set dragoons to have max energy always and figure out a way to make them immune to feedback?



None.

Dec 1 2015, 3:36 pm Eisetley Post #3



Quote
Or a messier solution could just set dragoons to have max energy always and figure out a way to make them immune to feedback?
That's not really a messier solution. All units have energy, making them spellcasters in units.dat just makes the energy amount visible under unit's wireframe. I believe feedback just checks if target is a spellcaster to determine if it can be used on it or not. All I'd have to do would be refilling dragoon's energy after it's created and after every use of blink.



None.

Dec 2 2015, 12:07 pm UndeadStar Post #4



For teleportation, this should work:
scbw::moveUnit(unit, unit->orderTarget.pt.x - 20, unit->orderTarget.pt.y);

//if (unit->unusedTimer = 0) should be //if (unit->unusedTimer == 0)

//if (weapons_dat::Weapon[weaponId] == 117); should be //if (weaponId == 117);

Did you also put some code somewhere else to decrease the unusedTimer over time?




Dec 2 2015, 11:06 pm Eisetley Post #5



Quote
Did you also put some code somewhere else to decrease the unusedTimer over time?
Nope, but I'll probably abandon the idea and do something like if unit->mainOrderId is ensnare order then teleport unit to orderTarget. I'm kinda busy right now, so I can't work on my mod for a little while, but I'll post when I'll progress with it or have problems. Maybe I'll just steal the code from here http://www.modcrafters.com/forum/viewtopic.php?f=17&t=211.
@edit
I think I'm almost there.
Quote
//Blink
if ((unit->id == UnitId::dragoon) && (weaponId == 58))
{

{
CUnit *target = unit->orderTarget.unit;
unit->unusedTimer = 40;
u32 TeleportX = unit->orderTarget.pt.x - 20;
u32 TeleportY = unit->orderTarget.pt.y;
scbw::moveUnit(unit, TeleportX, TeleportY);
unit->energy == 100;
}

}

}
}
https://www.youtube.com/watch?v=kbtvU6_Xf3A&feature=youtu.be
I put back the castspell opcode into dragoon's iscript. The cool thing is that it's blocked by fog of war now, exactly how I wanted. Now I need to add timer to it and make SC return "Cooldown is active" if it =/= 0, maybe even change dragoon's buttonset during cooldown to show blink as disabled or something. And of course remove the ensnare bullet and effect.

Post has been edited 2 time(s), last time on Dec 2 2015, 11:37 pm by Eisetley.



None.

Dec 4 2015, 11:35 am Eisetley Post #6



I decided to sacrifice ensnare but it was totally worth it.

The only issue would be the timer (unusedTimer), because it's u8 so I can't make it any higher than 255, and I can't make a loop that would decrease the timer slower than 1 per frame. Maybe someone will help me. The only idea I had was to double the time this way: decrease unusedTimer if elapsedFrames/2 is integer.

weaponfire.cpp
Quote
//Blink

if ((unit->id == UnitId::dragoon)
&& (unit->mainOrderId == OrderId::Ensnare)
&& (unit->unusedTimer != 0))

{
scbw::showErrorMessageWithSfx(unit->playerId, 1558, 1114);
unit->playIscriptAnim(IscriptAnimation::WalkingToIdle);
}





if ((unit->id == UnitId::dragoon)
&& (unit->mainOrderId == OrderId::Ensnare)
&& unit->unusedTimer == 0)


{
u32 EffectPositionX = unit->position.x;
u32 EffectPositionY = unit->position.y;
CUnit *target = unit->orderTarget.unit;
u32 TeleportX = unit->orderTarget.pt.x;
u32 TeleportY = unit->orderTarget.pt.y;
unit->sprite->createOverlay(932, 0, 0, 0);
createThingy(507, EffectPositionX, EffectPositionY, unit->playerId);
scbw::moveUnit(unit, TeleportX, TeleportY);
unit->playIscriptAnim(IscriptAnimation::SpecialState2);
unit->unusedTimer = 255;

}


game_hooks.cpp inside bool nextFrame()
Quote
//UnusedTimer
CUnit *unusedTimerUnit;
for (int unusedTimerLoop = 0; unusedTimerLoop < 1700; unusedTimerLoop++)
{
unusedTimerUnit = &unitTable[unusedTimerLoop];

if (unusedTimerUnit->unusedTimer > 0)
{
unusedTimerUnit->unusedTimer = unusedTimerUnit->unusedTimer - 1;
}

}




None.

Dec 4 2015, 2:12 pm UndeadStar Post #7



For weaponfire.cpp, I would see it more like this:

Code
//Blink

if ((unit->id == UnitId::dragoon)
&& (unit->mainOrderId == OrderId::Ensnare)

{

if (unit->unusedTimer != 0))

{
scbw::showErrorMessageWithSfx(unit->playerId, 1558, 1114);
unit->orderToIdle();
}

else //(unit->unusedTimer == 0

{
u32 EffectPositionX = unit->position.x;
u32 EffectPositionY = unit->position.y;
u32 TeleportX = unit->orderTarget.pt.x;
u32 TeleportY = unit->orderTarget.pt.y;
unit->sprite->createOverlay(932, 0, 0, 0);
createThingy(507, EffectPositionX, EffectPositionY, unit->playerId);
scbw::moveUnit(unit, TeleportX, TeleportY);
unit->playIscriptAnim(IscriptAnimation::SpecialState2);
unit->unusedTimer = 255;
}


What I did:
-removed the repetition of tests by putting unit->unusedTimer test as a if/else inside the common test
-put a more proper "return to idle" action (for it to be more compatible with multiplayer/replay)
-removed the line that saved an unit target (since it's unused)

I wonder if the current code would allow an exploit where you make the dragoon fire, and while it's firing, you can use the blink ability with unlimited range.




Dec 4 2015, 2:17 pm Eisetley Post #8



I don't think so, it always uses ensnare targeting I think. I'll test your code today, thank you.



None.

Options
  Back to forum
Please log in to reply to this topic or to report it.
Members in this topic: None.
[09:24 pm]
Moose -- denis
[05:00 pm]
lil-Inferno -- benis
[10:41 am]
v9bettel -- Nice
[01:39 am]
Ultraviolet -- no u elky skeleton guy, I'll use em better
[2024-4-18. : 10:50 pm]
Vrael -- Ultraviolet
Ultraviolet shouted: How about you all send me your minerals instead of washing them into the gambling void? I'm saving up for a new name color and/or glow
hey cut it out I'm getting all the minerals
[2024-4-18. : 10:11 pm]
Ultraviolet -- :P
[2024-4-18. : 10:11 pm]
Ultraviolet -- How about you all send me your minerals instead of washing them into the gambling void? I'm saving up for a new name color and/or glow
[2024-4-17. : 11:50 pm]
O)FaRTy1billion[MM] -- nice, now i have more than enough
[2024-4-17. : 11:49 pm]
O)FaRTy1billion[MM] -- if i don't gamble them away first
[2024-4-17. : 11:49 pm]
O)FaRTy1billion[MM] -- o, due to a donation i now have enough minerals to send you minerals
Please log in to shout.


Members Online: C(a)HeK, Roy, RIVE