For #3, I would suggest looking in wpnspellhit.cpp. Code there controls the on-hit effect of Restoration. Take a look at the code in the same file for EMP Shockwave, that's a fairly clear example of how to make an AOE on-hit effect.
my efforts so far (ok,ok I know " i didnt take enough of it":
wpnspellhit.cpp after initial " I can do it", I just start copy paste EMP code
.
void RestoreHit(CUnit* attacker, int x, int y, CBullet* bullet) {
static u16* const maxBoxRightValue = (u16*) 0x00628450; //should usually be mapTileSize->width * 32
static u16* const maxBoxBottomValue = (u16*) 0x006284B4; //should usually be mapTileSize->height * 32
Box16 area_of_effect;
CUnit** unitsInAreaOfEffect;
CUnit* current_unit;
//define the base area of effect
area_of_effect.left = (u16)x - weapons_dat::InnerSplashRadius[WeaponId::EMP_Shockwave];
area_of_effect.right = (u16)x + weapons_dat::InnerSplashRadius[WeaponId::EMP_Shockwave];
area_of_effect.top = (u16)y - weapons_dat::InnerSplashRadius[WeaponId::EMP_Shockwave];
area_of_effect.bottom = (u16)y + weapons_dat::InnerSplashRadius[WeaponId::EMP_Shockwave];
//check and fix effect if beyond width of map
if(area_of_effect.left < 0)
area_of_effect.left = 0;
else
if(area_of_effect.right > *maxBoxRightValue)
area_of_effect.right = *maxBoxRightValue;
//check and fix effect if beyond height of map
if(area_of_effect.top < 0)
area_of_effect.top = 0;
else
if(area_of_effect.bottom > *maxBoxBottomValue)
area_of_effect.bottom = *maxBoxBottomValue;
//find all units in area of effect and pick the first
unitsInAreaOfEffect = getAllUnitsInBounds(&area_of_effect);
current_unit = *unitsInAreaOfEffect;
while(current_unit != NULL) {
if(
current_unit != attacker && //EMP doesn't affect the attacker
(
attacker == NULL || //EMP doesn't affect the attacker
current_unit != attacker->subunit //subunit
)
)
{
if(current_unit->status & UnitStatus::IsHallucination)
current_unit->remove();
else {
//create impact overlay
u32 overlayImageId;
CUnit* overlayTargetUnit;
if(units_dat::BaseProperty[current_unit->id] & UnitProperty::MediumOverlay)
overlayImageId = ImageId::RestorationHit_Medium;
else
if(units_dat::BaseProperty[current_unit->id] & UnitProperty::LargeOverlay)
overlayImageId = ImageId::RestorationHit_Large;
else
overlayImageId = ImageId::RestorationHit_Small;
if(current_unit->subunit != NULL)
overlayTargetUnit = current_unit->subunit;
else
overlayTargetUnit = current_unit;
(overlayTargetUnit->sprite)->createTopOverlay(overlayImageId,0,0,0);
//remove status effects and corresponding overlays
//timers set to 0 twice reflect the original code
current_unit->parasiteFlags = 0;
current_unit->isBlind = 0;
if(current_unit->ensnareTimer != 0) {
current_unit->ensnareTimer = 0;
current_unit->removeOverlay(ImageId::EnsnareOverlay_Small,ImageId::EnsnareOverlay_Large);
current_unit->ensnareTimer = 0;
//specific update following ensnare removal
current_unit->updateSpeed();
}
if(current_unit->plagueTimer != 0) {
current_unit->plagueTimer = 0;
current_unit->removeOverlay(ImageId::PlagueOverlay_Small,ImageId::PlagueOverlay_Large);
current_unit->plagueTimer = 0;
}
if(current_unit->irradiateTimer != 0) {
current_unit->irradiateTimer = 0;
current_unit->removeOverlay(ImageId::Irradiate_Small,ImageId::Irradiate_Large);
current_unit->irradiateTimer = 0;
//specific updates following irradiate removal
current_unit->irradiatedBy = NULL;
current_unit->irradiatePlayerId = 8;
}
if(current_unit->lockdownTimer != 0)
current_unit->removeLockdown();
if(current_unit->maelstromTimer != 0)
current_unit->removeMaelstrom();
if(current_unit->acidSporeCount != 0)
current_unit->removeAcidSpores();
//was hardcoded in original code
scbw::refreshConsole();
}
} //void RestoreHit(CUnit* target)
unitsInAreaOfEffect++; //go on next unit of the list (or null)
current_unit = *unitsInAreaOfEffect;
} //while(current_unit != NULL)
//reload the previous temporary unit list from before the call to getAllUnitsInBounds
*tempUnitsListArraysCountsListLastIndex = *tempUnitsListArraysCountsListLastIndex - 1;
*tempUnitsListCurrentArrayCount = tempUnitsListArraysCountsList[*tempUnitsListArraysCountsListLastIndex];
} //void EMPShockwaveHit(CUnit* attacker, int x, int y)
;
next butchered file
WpnSpellH.h//The header file for the Weapon/Spell hit hook module.
#pragma once
#include <SCBW/structures/CUnit.h>
#include <SCBW/structures/CBullet.h>
namespace hooks {
void IrradiateHit(CUnit* attacker, CUnit* target, u8 attackingPlayerId); //00454E00
void OpticalFlareHit(CUnit* target, u32 attackingPlayerId, CBullet* bullet); //00455170
void RestoreHit(CUnit* attacker, int x, int y, CBullet* bullet); //00455230
void LockdownHit(CUnit* target, u8 previousLockdownTimer, CBullet* bullet); //00455380
and
wpnspellhit_inject.cpp last but not least (because also in initialize.cpp i uncomment the inject)
void __declspec(naked) RestoreHitWrapper() {
static CUnit* attacker;
static CBullet* bullet;
static int x;
static int y;
__asm {
PUSH EBP
MOV EBP, ESP
MOV y, EAX
MOV x, ECX
MOV EAX, [EBP+0x08]
MOV attacker, EAX
MOV bullet, EBX
PUSHAD
}
hooks::RestoreHit(attacker,x,y,bullet);
__asm {
POPAD
MOV ESP, EBP
POP EBP
RETN 4
}
}
;
Its compile into successfully .gpt, that will crash Starcraft, as soon as you cast Restoration with medic, and its not Area of Effect, because required to take target.
I stop enjoying starcraft
None.