SHADOW WARRIOR MODDING TUTORIAL:
Turning Ninja Stars into the Duke3D expander weapon.
In this tutorial we will make it so enemies will grow very big and blow up when the ninja stars hit a enemy actor.
In Actor.cpp at the very end of the add the following code.
void InitActorGrow(int spritenum, int scalex, int scaley)
{
USERp u = User[spritenum];
if (u == nullptr)
return;
u->isGrowingTillDeath = true;
u->growingTicTimer = 0;
u->growScaleX = scalex;
u->growScaleY = scaley;
}
bool DoGenericGrowCode(int spritenum)
{
USERp u = User[spritenum];
if (u == nullptr)
return FALSE;
if (!u->isGrowingTillDeath)
return FALSE;
SPRITEp sprite = u->SpriteP;
if (u->growingTicTimer < 32)
{
sprite->xrepeat += ksgn(u->growScaleX);
sprite->yrepeat += ksgn(u->growScaleX);
u->growingTicTimer++;
}
else
{
// spawn explosion
int explosion = SpawnSectorExp(spritenum);
ASSERT(explosion >= 0);
SPRITEp exp = &sprite[explosion];
USERp eu = User[explosion];
exp->xrepeat += (RANDOM_P2(32 << 8) >> 8) - 16;
exp->yrepeat += (RANDOM_P2(32 << 8) >> 8) - 16;
eu->xchange = MOVEx(92, exp->ang);
eu->ychange = MOVEy(92, exp->ang);
KillSprite(spritenum);
return TRUE;
}
return FALSE;
}
The above code is our expander logic. The above logic is based on the expander logic in duke3d.
In actor.h at the bottom of the header add the following code:
void InitActorGrow(int spritenum, int scalex, int scaley);
bool DoGenericGrowCode(int spritenum);
In game.h find the USER struct and add the following just above the filler variable:
bool isGrowingTillDeath;
int growingTicTimer;
int growScaleX;
int growScaleY;
In sprite.cpp just below #include "player.h" add the following:
#include "actor.h"
Also in sprite.cpp find the function SpriteControl just above the CloseToPlayer = FALSE; line(inside of the move bad guys around TRAVERSE_SPRITE_STAT) add the following code.
if (DoGenericGrowCode(sp - sprite))
continue;
Were executing our exploding logic here, there is probably a better place for it but we don't continue in the loop if DoGenericGrowCode has removed destroyed this actor.
Finally in weapon.cpp around line 6373(case STAR1/case CROSSBOLT) modify that condition from
case STAR1:
case CROSSBOLT:
damage = GetDamage(SpriteNum, Weapon, WPN_STAR);
if (u->sop_parent)
{
break;
}
else if (u->PlayerP)
{
MONO_PRINT("Stat Hit Actor");
// Is the player blocking?
if (u->PlayerP->WpnKungFuMove == 3)
damage /= 3;
PlayerDamageSlide(u->PlayerP, damage, wp->ang);
if (PlayerTakeDamage(u->PlayerP, Weapon))
{
PlayerUpdateHealth(u->PlayerP, damage);
PlayerCheckDeath(u->PlayerP, Weapon);
}
if (u->PlayerP->Armor)
PlaySound(DIGI_ARMORHIT,&u->PlayerP->posx,&u->PlayerP->posy,&
u->PlayerP->posz,v3df_dontpan|v3df_follow|v3df_doppler);
}
else
{
MONO_PRINT("Star Hit Actor");
ActorHealth(SpriteNum, damage);
ActorPain(SpriteNum);
ActorStdMissile(SpriteNum, Weapon);
ActorDamageSlide(SpriteNum, damage, wp->ang);
ActorChooseDeath(SpriteNum, Weapon);
}
StarBlood(SpriteNum, Weapon);
wu->ID = 0;
SetSuicide(Weapon);
break;
to
case STAR1:
InitActorGrow(SpriteNum, 100, 100);
StarBlood(SpriteNum, Weapon);
wu->ID = 0;
SetSuicide(Weapon);
break;
case CROSSBOLT:
damage = GetDamage(SpriteNum, Weapon, WPN_STAR);
if (u->sop_parent)
{
break;
}
else if (u->PlayerP)
{
MONO_PRINT("Stat Hit Actor");
// Is the player blocking?
if (u->PlayerP->WpnKungFuMove == 3)
damage /= 3;
PlayerDamageSlide(u->PlayerP, damage, wp->ang);
if (PlayerTakeDamage(u->PlayerP, Weapon))
{
PlayerUpdateHealth(u->PlayerP, damage);
PlayerCheckDeath(u->PlayerP, Weapon);
}
if (u->PlayerP->Armor)
PlaySound(DIGI_ARMORHIT,&u->PlayerP->posx,&u->PlayerP->posy,&
u->PlayerP->posz,v3df_dontpan|v3df_follow|v3df_doppler);
}
else
{
MONO_PRINT("Star Hit Actor");
ActorHealth(SpriteNum, damage);
ActorPain(SpriteNum);
ActorStdMissile(SpriteNum, Weapon);
ActorDamageSlide(SpriteNum, damage, wp->ang);
ActorChooseDeath(SpriteNum, Weapon);
}
StarBlood(SpriteNum, Weapon);
wu->ID = 0;
SetSuicide(Weapon);
break;