Blood: scriptified item spawning

This was merely a testbed with a limited amount of code, the biggest gain here is that the spawning no longer depends on item IDs but classes so new ones can be added later.
This commit is contained in:
Christoph Oelckers 2023-10-03 22:25:28 +02:00
parent d83c9f51c3
commit 64d8fd6072
19 changed files with 1087 additions and 265 deletions

View file

@ -247,7 +247,7 @@ PClassActor *PClassActor::GetReplacee()
void FActorInfo::ResolveTextures(const char* clsname, DCoreActor* defaults)
{
SpriteSet.Resize(SpriteSetNames.Size());
SpriteSet.Set((FTextureID*)ClassDataAllocator.Alloc(SpriteSetNames.Size() * sizeof(FTextureID)), SpriteSetNames.Size());
for (unsigned i = 0; i < SpriteSet.Size(); i++)
{
SpriteSet[i] = TexMan.CheckForTexture(SpriteSetNames[i].GetChars(), ETextureType::Any);
@ -259,6 +259,7 @@ void FActorInfo::ResolveTextures(const char* clsname, DCoreActor* defaults)
if (defaults->spritesetindex < 0 || defaults->spritesetindex >= (int)SpriteSet.Size()) defaults->spritesetindex = 0;
defaults->spr.setspritetexture(SpriteSet[defaults->spritesetindex]);
}
if (!DefaultScale.isZero()) defaults->spr.scale = DefaultScale;
SpriteSetNames.Reset();
}

View file

@ -22,7 +22,7 @@ enum EDefaultFlags
struct FActorInfo
{
TArray<FInternalLightAssociation *> LightAssociations;
TArray<FTextureID> SpriteSet;
TArrayView<FTextureID> SpriteSet;
PClassActor *Replacement = nullptr;
PClassActor *Replacee = nullptr;
DVector2 DefaultScale = { 0, 0 };

View file

@ -378,8 +378,18 @@ void DCoreActor::initFromSprite(spritetype* mspr)
spr.sectp = mspr->sectp;
spr.clipdist = mspr->clipdist;
// picnum may only be used if the class allows it.
if (!(actorinfo->DefaultFlags & DEFF_PICNUM)) spr.picnum = mspr->picnum;
// picnum may only be used if the class allows it.
if (!isBlood())
{
if (!(actorinfo->DefaultFlags & DEFF_PICNUM)) spr.picnum = mspr->picnum;
}
else
{
// In Blood, actor type and picnum are distinct entities so the logic must be different.
// Here this only gets set if the map sprite's pic is 0
if (mspr->picnum != 0) spr.picnum = mspr->picnum;
}
if (!mspr->scale.isZero()) spr.scale = mspr->scale; // only use default scale if not set in the map.
#define setter(var) spr.var = mspr->var;
@ -395,7 +405,6 @@ void DCoreActor::initFromSprite(spritetype* mspr)
setter(shade);
setter(pal);
setter(blend);
setter(scale);
setter(xoffset);
setter(yoffset);
setter(intowner);

View file

@ -636,7 +636,7 @@ int GameMain()
gi->FreeLevelData();
for (int i = 0; i < MAXPLAYERS; i++)
{
PlayerArray[i]->Destroy();
if (PlayerArray[i]) PlayerArray[i]->Destroy();
PlayerArray[i] = nullptr;
}
}

View file

@ -43,6 +43,18 @@
#include "buildtiles.h"
int Raze_getspawnnum(PClassActor* actor)
{
return actor->ActorInfo()->TypeNum;
}
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, getspawnnum, Raze_getspawnnum)
{
PARAM_PROLOGUE;
PARAM_POINTER(p, PClassActor);
ACTION_RETURN_INT(Raze_getspawnnum(p));
}
sectortype* Raze_updatesector(double x, double y, sectortype* sec, double dist)
{
updatesector(DVector2(x, y), &sec, dist);
@ -1135,3 +1147,16 @@ DEFINE_ACTION_FUNCTION_NATIVE(_CollisionData, setvoid, collision_setvoid)
return 0;
}
void collision_setnone(CollisionBase* coll)
{
coll->type = kHitNone;
coll->hitActor = nullptr;
}
DEFINE_ACTION_FUNCTION_NATIVE(_CollisionData, setnone, collision_setnone)
{
PARAM_SELF_STRUCT_PROLOGUE(CollisionBase);
collision_setnone(self);
return 0;
}

View file

@ -2721,142 +2721,6 @@ static void actNapalmMove(DBloodActor* actor)
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static DBloodActor* actSpawnFloor(DBloodActor* actor)
{
auto pSector = actor->sector();
auto pos = actor->spr.pos;
updatesector(pos, &pSector);
double zFloor = getflorzofslopeptr(pSector, pos.X, pos.Y);
auto spawned = actSpawnSprite(pSector, DVector3(pos.XY(), zFloor), 3, 0);
if (spawned) spawned->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL;
return spawned;
}
static DBloodActor* actDropAmmo(DBloodActor* actor, int nType)
{
if (!actor) return nullptr;
if (actor->spr.statnum < kMaxStatus && nType >= kItemAmmoBase && nType < kItemAmmoMax)
{
auto act2 = actSpawnFloor(actor);
const AMMOITEMDATA* pAmmo = &gAmmoItemData[nType - kItemAmmoBase];
act2->ChangeType(nType);
act2->spr.setspritetexture(pAmmo->textureID());
act2->spr.shade = pAmmo->shade;
act2->spr.scale = DVector2(pAmmo->xrepeat * REPEAT_SCALE, pAmmo->yrepeat * REPEAT_SCALE);
return act2;
}
return nullptr;
}
static DBloodActor* actDropWeapon(DBloodActor* actor, int nType)
{
if (!actor) return nullptr;
if (actor->spr.statnum < kMaxStatus && nType >= kItemWeaponBase && nType < kItemWeaponMax)
{
auto act2 = actSpawnFloor(actor);
const WEAPONITEMDATA* pWeapon = &gWeaponItemData[nType - kItemWeaponBase];
act2->ChangeType(nType);
act2->spr.setspritetexture(pWeapon->textureID());
act2->spr.shade = pWeapon->shade;
act2->spr.scale = DVector2(pWeapon->xrepeat * REPEAT_SCALE, pWeapon->yrepeat * REPEAT_SCALE);
return act2;
}
return nullptr;
}
static DBloodActor* actDropItem(DBloodActor* actor, int nType)
{
if (!actor) return nullptr;
if (actor->spr.statnum < kMaxStatus && nType >= kItemBase && nType < kItemMax)
{
auto act2 = actSpawnFloor(actor);
const ITEMDATA* pItem = &gItemData[nType - kItemBase];
act2->ChangeType(nType);
act2->spr.setspritetexture(pItem->textureID());
act2->spr.shade = pItem->shade;
act2->spr.scale = DVector2(pItem->xrepeat * REPEAT_SCALE, pItem->yrepeat * REPEAT_SCALE);
return act2;
}
return nullptr;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static DBloodActor* actDropKey(DBloodActor* actor, int nType)
{
if (!actor) return nullptr;
if (actor->spr.statnum < kMaxStatus && nType >= kItemKeyBase && nType < kItemKeyMax)
{
auto act2 = actDropItem(actor, nType);
if (act2 && gGameOptions.nGameType == 1)
{
act2->addX();
act2->xspr.respawn = 3;
act2->hit.florhit.setNone();
act2->hit.ceilhit.setNone();
}
return act2;
}
return nullptr;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static DBloodActor* actDropFlag(DBloodActor* actor, int nType)
{
if (!actor) return nullptr;
if (actor->spr.statnum < kMaxStatus && (nType == 147 || nType == 148))
{
auto act2 = actDropItem(actor, nType);
if (act2 && gGameOptions.nGameType == 3)
{
evPostActor(act2, 1800, kCallbackReturnFlag);
}
return act2;
}
return nullptr;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
DBloodActor* actDropObject(DBloodActor* actor, int nType)
{
DBloodActor* act2 = nullptr;
if (nType >= kItemKeyBase && nType < kItemKeyMax) act2 = actDropKey(actor, nType);
else if (nType == kItemFlagA || nType == kItemFlagB) act2 = actDropFlag(actor, nType);
else if (nType >= kItemBase && nType < kItemMax) act2 = actDropItem(actor, nType);
else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) act2 = actDropAmmo(actor, nType);
else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) act2 = actDropWeapon(actor, nType);
if (act2)
{
double top, bottom;
GetActorExtents(act2, &top, &bottom);
if (bottom >= act2->spr.pos.Z)
act2->spr.pos.Z -= (bottom - act2->spr.pos.Z);
}
return act2;
}
//---------------------------------------------------------------------------
//

View file

@ -114,14 +114,14 @@ struct WEAPONITEMDATA
struct ITEMDATA
{
int16_t cstat;
int16_t __cstat_;
int16_t picno;
int8_t shade;
uint8_t pal;
uint8_t xrepeat;
uint8_t yrepeat;
int8_t __shade_;
uint8_t __pal_;
uint8_t __xrepeat_;
uint8_t __yrepeat_;
int16_t packSlot;
FTextureID textureID() const { return tileGetTextureID(picno); }
FTextureID __textureID_() const { return tileGetTextureID(picno); }
};
struct MissileType

View file

@ -695,6 +695,23 @@ void GameInterface::FreeLevelData()
return new GameInterface;
}
void GameInterface::FinalizeSetup()
{
// assign spawn types to actor classes. Some code will need them.
SpawnMap::Iterator it(spawnMap);
SpawnMap::Pair* pair;
// this is only reliable for unambiguous assignments, which applies to everything aside from BloodActor itself.
while (it.NextPair(pair))
{
auto cls = pair->Value.cls;
if (cls != RUNTIME_CLASS(DBloodActor))
{
auto actorinfo = static_cast<PClassActor*>(cls)->ActorInfo();
actorinfo->TypeNum = pair->Key;
}
}
}
//---------------------------------------------------------------------------
//
//
@ -719,81 +736,4 @@ inline DBloodPlayer* getPlayer(DBloodActor* actor)
return getPlayer(actor->GetType() - kDudePlayer1);
}
DEFINE_ACTION_FUNCTION(_Blood, OriginalLoadScreen)
{
static int bLoadScreenCrcMatch = -1;
if (bLoadScreenCrcMatch == -1)
{
auto gtex = TexMan.FindGameTexture("LOADSCREEN", ETextureType::Any);
if (gtex)
{
auto img = gtex->GetTexture()->GetImage();
bLoadScreenCrcMatch = tileGetCRC32(img) == kLoadScreenCRC;
}
else bLoadScreenCrcMatch = true; // if the LOADSCREEN texture is invalid, allow the widescreen fallback.
}
ACTION_RETURN_INT(bLoadScreenCrcMatch);
}
DEFINE_ACTION_FUNCTION(_Blood, PlayIntroMusic)
{
Mus_Play("PESTIS.MID", false);
return 0;
}
DEFINE_ACTION_FUNCTION(_Blood, sndStartSample)
{
PARAM_PROLOGUE;
PARAM_INT(id);
PARAM_INT(vol);
PARAM_INT(chan);
PARAM_BOOL(looped);
PARAM_INT(chanflags);
sndStartSample(id, vol, chan, looped, EChanFlags::FromInt(chanflags));
return 0;
}
DEFINE_ACTION_FUNCTION(_Blood, sndStartSampleNamed)
{
PARAM_PROLOGUE;
PARAM_STRING(id);
PARAM_INT(vol);
PARAM_INT(chan);
sndStartSample(id.GetChars(), vol, chan);
return 0;
}
DEFINE_ACTION_FUNCTION(_Blood, PowerupIcon)
{
PARAM_PROLOGUE;
PARAM_INT(pwup);
FTextureID tile = FNullTextureID();
if (pwup >= 0 && pwup < (int)countof(gPowerUpInfo))
{
tile = gPowerUpInfo[pwup].textureID();
}
FGameTexture* tex = TexMan.GetGameTexture(tile);
ACTION_RETURN_INT(tex ? tex->GetID().GetIndex() : -1);
}
DEFINE_ACTION_FUNCTION(_Blood, GetViewPlayer)
{
PARAM_PROLOGUE;
ACTION_RETURN_POINTER(getPlayer(gViewIndex));
}
DEFINE_ACTION_FUNCTION(_BloodPlayer, GetHealth)
{
PARAM_SELF_STRUCT_PROLOGUE(DBloodPlayer);
ACTION_RETURN_INT(self->GetActor()->xspr.health);
}
DEFINE_ACTION_FUNCTION_NATIVE(_BloodPlayer, powerupCheck, powerupCheck)
{
PARAM_SELF_STRUCT_PROLOGUE(DBloodPlayer);
PARAM_INT(pwup);
ACTION_RETURN_INT(powerupCheck(self, pwup));
}
END_BLD_NS

View file

@ -136,6 +136,7 @@ struct GameInterface : public ::GameInterface
void RemoveQAVInterpProps(const int res_id) override;
void StartSoundEngine() override;
unsigned getCrouchState() override;
void FinalizeSetup() override;
};
END_BLD_NS

View file

@ -53,7 +53,10 @@ DBloodActor* InsertSprite(sectortype* pSector, int nStat, PClass* cls)
auto act = static_cast<DBloodActor*>(::InsertActor(cls, pSector, nStat));
act->spr.cstat = CSTAT_SPRITE_YCENTER;
act->clipdist = 8;
act->spr.scale = DVector2(1, 1);
// default to full scale.
if (act->spr.scale.isZero())
act->spr.scale = DVector2(1, 1);
return act;
}

View file

@ -42,6 +42,12 @@ x(AmmoIcon8, 820)
x(AmmoIcon9, 525)
x(AmmoIcon10, 811)
x(AmmoIcon11, 810)
x(AmmoTNTBox, 809)
x(AmmoShotgunFew, 812)
x(AmmoShotgunBox, 813)
x(AmmoUseless1, 814)
x(AmmoUseless2, 818)
x(AmmoUseless3, 819)
x(MedPouchIcon, 822)
x(LifeSeedIcon, 2433)

View file

@ -1204,9 +1204,6 @@ bool PickupItem(DBloodPlayer* pPlayer, DBloodActor* itemactor)
pickupSnd = 779;
break;
}
case kItemCrystalBall:
if (gGameOptions.nGameType == 0 || !packAddItem(pPlayer, gItemData[nType].packSlot)) return 0;
break;
case kItemKeySkull:
case kItemKeyEye:
case kItemKeyFire:
@ -1232,6 +1229,9 @@ bool PickupItem(DBloodPlayer* pPlayer, DBloodActor* itemactor)
if (!actHealDude(pPlayer->GetActor(), addPower, gPowerUpInfo[nType].maxTime)) return 0;
return 1;
}
case kItemCrystalBall:
if (gGameOptions.nGameType == 0) return 0;
case kItemHealthDoctorBag:
case kItemJumpBoots:
case kItemDivingSuit:
@ -2199,7 +2199,7 @@ int playerDamageSprite(DBloodActor* source, DBloodPlayer* pPlayer, DAMAGE_TYPE n
if (gModernMap && gGameOptions.nGameType != 0 && pPlayer->GetActor()->xspr.health <= 0) {
DBloodActor* pItem = nullptr;
if (pPlayer->GetActor()->xspr.dropMsg && (pItem = actDropItem(pActor, pPlayer->GetActor()->xspr.dropMsg)) != NULL)
if (pPlayer->GetActor()->xspr.dropMsg && (pItem = actDropObject(pActor, pPlayer->GetActor()->xspr.dropMsg)) != NULL)
evPostActor(pItem, 500, kCallbackRemove);
if (pPlayer->GetActor()->xspr.key) {
@ -2210,7 +2210,7 @@ int playerDamageSprite(DBloodActor* source, DBloodPlayer* pPlayer, DAMAGE_TYPE n
break;
}
if (i == 0 && (pItem = actDropKey(pActor, (pPlayer->GetActor()->xspr.key + kItemKeyBase) - 1)) != NULL)
if (i == 0 && (pItem = actDropObject(pActor, (pPlayer->GetActor()->xspr.key + kItemKeyBase) - 1)) != NULL)
evPostActor(pItem, 500, kCallbackRemove);
}

View file

@ -24,6 +24,92 @@ See the GNU General Public License for more details.
#include "blood.h"
BEGIN_BLD_NS
DEFINE_ACTION_FUNCTION(_Blood, OriginalLoadScreen)
{
static int bLoadScreenCrcMatch = -1;
if (bLoadScreenCrcMatch == -1)
{
auto gtex = TexMan.FindGameTexture("LOADSCREEN", ETextureType::Any);
if (gtex)
{
auto img = gtex->GetTexture()->GetImage();
bLoadScreenCrcMatch = tileGetCRC32(img) == kLoadScreenCRC;
}
else bLoadScreenCrcMatch = true; // if the LOADSCREEN texture is invalid, allow the widescreen fallback.
}
ACTION_RETURN_INT(bLoadScreenCrcMatch);
}
DEFINE_ACTION_FUNCTION(_Blood, PlayIntroMusic)
{
Mus_Play("PESTIS.MID", false);
return 0;
}
DEFINE_ACTION_FUNCTION(_Blood, sndStartSample)
{
PARAM_PROLOGUE;
PARAM_INT(id);
PARAM_INT(vol);
PARAM_INT(chan);
PARAM_BOOL(looped);
PARAM_INT(chanflags);
sndStartSample(id, vol, chan, looped, EChanFlags::FromInt(chanflags));
return 0;
}
DEFINE_ACTION_FUNCTION(_Blood, sndStartSampleNamed)
{
PARAM_PROLOGUE;
PARAM_STRING(id);
PARAM_INT(vol);
PARAM_INT(chan);
sndStartSample(id.GetChars(), vol, chan);
return 0;
}
DEFINE_ACTION_FUNCTION(_Blood, PowerupIcon)
{
PARAM_PROLOGUE;
PARAM_INT(pwup);
FTextureID tile = FNullTextureID();
if (pwup >= 0 && pwup < (int)countof(gPowerUpInfo))
{
tile = gPowerUpInfo[pwup].textureID();
}
FGameTexture* tex = TexMan.GetGameTexture(tile);
ACTION_RETURN_INT(tex ? tex->GetID().GetIndex() : -1);
}
DEFINE_ACTION_FUNCTION(_Blood, GetViewPlayer)
{
PARAM_PROLOGUE;
ACTION_RETURN_POINTER(getPlayer(gViewIndex));
}
static int blood_gameMode()
{
return gGameOptions.nGameType;
}
DEFINE_ACTION_FUNCTION_NATIVE(_Blood, gameType, blood_gameMode)
{
PARAM_PROLOGUE;
ACTION_RETURN_INT(gGameOptions.nGameType);
}
DEFINE_ACTION_FUNCTION(_BloodPlayer, GetHealth)
{
PARAM_SELF_STRUCT_PROLOGUE(DBloodPlayer);
ACTION_RETURN_INT(self->GetActor()->xspr.health);
}
DEFINE_ACTION_FUNCTION_NATIVE(_BloodPlayer, powerupCheck, powerupCheck)
{
PARAM_SELF_STRUCT_PROLOGUE(DBloodPlayer);
PARAM_INT(pwup);
ACTION_RETURN_INT(powerupCheck(self, pwup));
}
DEFINE_FIELD_X(XSECTOR, XSECTOR, flags)
DEFINE_FIELD_X(XSECTOR, XSECTOR, flags2)
@ -135,7 +221,7 @@ DEFINE_FIELD(DBloodActor, cumulDamage)
DEFINE_FIELD(DBloodActor, interpolated)
void Blood_ChangeType(DBloodActor* self, PClassActor* type)
static void Blood_ChangeType(DBloodActor* self, PClassActor* type)
{
self->ChangeType(type);
}
@ -148,4 +234,78 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, ChangeType, Blood_ChangeType)
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, InsertSprite, InsertSprite)
{
PARAM_PROLOGUE;
PARAM_POINTER(sect, sectortype);
PARAM_INT(stat);
PARAM_POINTER(type, PClassActor);
ACTION_RETURN_POINTER(InsertSprite(sect, stat, type));
}
static void bloodactor_addX(DBloodActor* a)
{
a->addX();
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, addX, bloodactor_addX)
{
PARAM_SELF_PROLOGUE(DBloodActor);
self->addX();
return 0;
}
static void bloodactor_evPostActorCallback(DBloodActor* act, int delta, int id)
{
evPostActor(act, delta, (CALLBACK_ID)id);
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, evPostActorCallback, bloodactor_evPostActorCallback)
{
PARAM_SELF_PROLOGUE(DBloodActor);
PARAM_INT(d);
PARAM_INT(id);
bloodactor_evPostActorCallback(self, d, id);
return 0;
}
double bloodactor_getActorExtents(DBloodActor* act, double* bottom)
{
double top;
GetActorExtents(act, &top, bottom);
return top;
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, getActorExtents, bloodactor_getActorExtents)
{
PARAM_SELF_PROLOGUE(DBloodActor);
double top, bottom;
GetActorExtents(self, &top, &bottom);
if (numret > 0) ret[0].SetFloat(top);
if (numret > 1) ret[1].SetFloat(bottom);
return min(numret, 2);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
DBloodActor* actDropObject(DBloodActor* actor, int nType)
{
IFVM(BloodActor, dropObject)
{
PClass* ty = GetSpawnType(nType);
if (ty == nullptr) ty = RUNTIME_CLASS(DBloodActor);
DBloodActor* spawned;
VMReturn ret((void**)&spawned);
VMValue param[] = { actor, ty };
VMCall(func, param, 2, &ret, 1);
return spawned;
}
return nullptr;
}
END_BLD_NS

View file

@ -26,6 +26,12 @@ spawnclasses
73 = BloodAmmoTeslaCharge
76 = BloodAmmoFlares
79 = BloodAmmoGasolineCan
61 = BloodAmmoObsolete61
71 = BloodAmmoObsolete71
74 = BloodAmmoObsolete74
75 = BloodAmmoObsolete75
77 = BloodAmmoObsolete77
78 = BloodAmmoObsolete78
// items (keys)

View file

@ -1,209 +1,528 @@
class BloodItemBase : BloodActor
{
meta int packslot;
Property prefix: none;
property packslot: packslot;
}
class BloodKeyBase : BloodItemBase
{
}
// items (keys)
class BloodItemKeySkull : BloodItemBase
class BloodItemKeySkull : BloodKeyBase
{
default
{
pic "HudKeyIcon1";
shade -8;
scale 0.5, 0.5;
}
}
class BloodItemKeyEye : BloodItemBase
class BloodItemKeyEye : BloodKeyBase
{
default
{
pic "HudKeyIcon2";
shade -8;
scale 0.5, 0.5;
}
}
class BloodItemKeyFire : BloodItemBase
class BloodItemKeyFire : BloodKeyBase
{
default
{
pic "HudKeyIcon3";
shade -8;
scale 0.5, 0.5;
}
}
class BloodItemKeyDagger : BloodItemBase
class BloodItemKeyDagger : BloodKeyBase
{
default
{
pic "HudKeyIcon4";
shade -8;
scale 0.5, 0.5;
}
}
class BloodItemKeySpider : BloodItemBase
class BloodItemKeySpider : BloodKeyBase
{
default
{
pic "HudKeyIcon5";
shade -8;
scale 0.5, 0.5;
}
}
class BloodItemKeyMoon : BloodItemBase
class BloodItemKeyMoon : BloodKeyBase
{
default
{
pic "HudKeyIcon6";
shade -8;
scale 0.5, 0.5;
}
}
class BloodItemKeyKey7 : BloodItemBase
class BloodItemKeyKey7 : BloodKeyBase
{
default
{
pic "HudKeyIcon7";
shade -8;
scale 0.5, 0.5;
}
}
// items (health)
class BloodItemHealthDoctorBag : BloodItemBase
{
default
{
pic "Pack2Icon1";
shade -8;
scale 0.75, 0.75;
packslot 0;
}
}
class BloodItemHealthMedPouch : BloodItemBase
{
default
{
pic "MedPouchIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemHealthLifeEssense : BloodItemBase
{
default
{
pic "Healthicon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemHealthLifeSeed : BloodItemBase
{
default
{
pic "LifeSeedIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemHealthRedPotion : BloodItemBase
{
default
{
pic "RedPotionIcon";
shade -8;
scale 0.625, 0.625;
}
}
// items (misc)
class BloodItemFeatherFall : BloodItemBase
{
default
{
pic "FeatherFallIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemShadowCloak : BloodItemBase
{
default
{
pic "ShadowCloakIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemDeathMask : BloodItemBase
{
default
{
pic "DeathMaskIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemJumpBoots : BloodItemBase
{
default
{
pic "Pack2Icon5";
shade -8;
scale 0.625, 0.625;
packslot 4;
}
}
class BloodItemTwoGuns : BloodItemBase
{
default
{
pic "GunsAkimboIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemDivingSuit : BloodItemBase
{
default
{
pic "Pack2Icon2";
shade -8;
scale 1.25, 1.25;
packslot 1;
}
}
class BloodItemGasMask : BloodItemBase
{
default
{
pic "GasMaskIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemCrystalBall : BloodItemBase
{
default
{
pic "Pack2Icon3";
shade -8;
scale 0.625, 0.625;
packslot 2;
}
}
class BloodItemReflectShots : BloodItemBase
{
default
{
pic "ReflectiveIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemBeastVision : BloodItemBase
{
default
{
pic "Pack2Icon4";
shade -8;
scale 0.625, 0.625;
packslot 3;
}
}
class BloodItemShroomDelirium : BloodItemBase
{
default
{
pic "DeliriumIcon";
shade -8;
scale 0.75, 0.75;
}
}
class BloodItemArmorAsbest : BloodItemBase
{
default
{
pic "AsbestIcon";
shade -8;
scale 1.25, 1;
}
}
class BloodItemArmorBasic : BloodItemBase
{
default
{
pic "BasicArmorIcon";
shade -8;
scale 1, 1;
}
}
class BloodItemArmorBody : BloodItemBase
{
default
{
pic "Armor3Icon";
shade -8;
scale 1, 1;
}
}
class BloodItemArmorFire : BloodItemBase
{
default
{
pic "Armor1Icon";
shade -8;
scale 1, 1;
}
}
class BloodItemArmorSpirit : BloodItemBase
{
default
{
pic "Armor2Icon";
shade -8;
scale 1, 1;
}
}
class BloodItemArmorSuper : BloodItemBase
{
default
{
pic "SuperArmorIcon";
shade -8;
scale 1, 1;
}
}
class BloodItemFlagABase : BloodItemBase
{
default
{
pic "FlagBaseIcon";
shade -8;
scale 1, 1;
}
}
class BloodItemFlagBBase : BloodItemBase
{
default
{
pic "FlagBaseIcon";
shade -8;
pal 7;
scale 1, 1;
}
}
class BloodItemFlagA : BloodItemBase
class BloodFlagBase : BloodActor
{
}
class BloodItemFlagB : BloodItemBase
class BloodItemFlagA : BloodFlagBase
{
default
{
pic "FlagIcon";
shade -128;
scale 1, 1;
}
}
class BloodItemFlagB : BloodFlagBase
{
default
{
pic "FlagIcon";
shade -128;
pal 7;
scale 1, 1;
}
}
// others
class BloodItemRavenFlight : BloodItemBase
{
default
{
pic "RavenFlightIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemClone : BloodItemBase
{
default
{
pic "CloneIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemDecoy : BloodItemBase
{
default
{
pic "DecoyIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemDoppleganger : BloodItemBase
{
default
{
pic "DoppleIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemShadowCloakUseless : BloodItemBase
{
default
{
pic "UselessIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemRageShroom : BloodItemBase
{
default
{
pic "RageShroomIcon";
shade -8;
scale 0.75, 0.75;
}
}
class BloodItemGrowShroom : BloodItemBase
{
default
{
pic "GrowShroomIcon";
shade -8;
scale 0.75, 0.75;
}
}
class BloodItemShrinkShroom : BloodItemBase
{
default
{
pic "ShrinkShroomIcon";
shade -8;
scale 0.75, 0.75;
}
}
class BloodItemDeathMaskUseless : BloodItemBase
{
default
{
pic "UselessIcon2";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemWineGoblet : BloodItemBase
{
default
{
pic "WineGobletIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemWineBottle : BloodItemBase
{
default
{
pic "WineBottleIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemSkullGrail : BloodItemBase
{
default
{
pic "SkullGrailIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemSilverGrail : BloodItemBase
{
default
{
pic "SilverGrailIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemTome : BloodItemBase
{
default
{
pic "TomeIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemBlackChest : BloodItemBase
{
default
{
pic "BlackChestIcon";
shade -8;
scale 0.625, 0.625;
}
}
class BloodItemWoodenChest : BloodItemBase
{
default
{
pic "WoodenChestIcon";
shade -8;
scale 0.625, 0.625;
}
}

View file

@ -1,27 +1,381 @@
// (weapons)
class BloodWeaponSawedoff : BloodActor {}
class BloodWeaponTommygun : BloodActor {}
class BloodWeaponFlarePistol : BloodActor {}
class BloodWeaponVoodooDoll : BloodActor {}
class BloodWeaponTeslaCannon : BloodActor {}
class BloodWeaponNapalmLauncher : BloodActor {}
class BloodWeaponPitchfork : BloodActor {}
class BloodWeaponSprayCan : BloodActor {}
class BloodWeaponTNT : BloodActor {}
class BloodWeaponLifeLeech : BloodActor {}
class BloodWeaponBase : BloodActor
{
meta int count;
meta int type;
meta int ammotype;
property prefix: none;
property count: count;
property type: type;
property ammotype: ammotype;
}
class BloodWeaponSawedoff : BloodWeaponBase
{
default
{
pic "ICONSHOTGUN";
shade -8;
scale 0.750000, 0.750000;
count 8;
type 3;
ammotype 2;
}
}
class BloodWeaponTommygun : BloodWeaponBase
{
default
{
pic "ICONTOMMY";
shade -8;
scale 0.750000, 0.750000;
count 50;
type 4;
ammotype 3;
}
}
class BloodWeaponFlarePistol : BloodWeaponBase
{
default
{
pic "ICONFLAREGUN";
shade -8;
scale 0.750000, 0.750000;
count 9;
type 2;
ammotype 1;
}
}
class BloodWeaponVoodooDoll : BloodWeaponBase
{
default
{
pic "AmmoIcon9";
shade -8;
scale 0.750000, 0.750000;
count 100;
type 10;
ammotype 9;
}
}
class BloodWeaponTeslaCannon : BloodWeaponBase
{
default
{
pic "ICONTESLA";
shade -8;
scale 0.750000, 0.750000;
count 64;
type 8;
ammotype 7;
}
}
class BloodWeaponNapalmLauncher : BloodWeaponBase
{
default
{
pic "ICONNAPALM";
shade -8;
scale 0.750000, 0.750000;
count 6;
type 5;
ammotype 4;
}
}
class BloodWeaponPitchfork : BloodWeaponBase
{
default
{
type 1;
}
}
class BloodWeaponSprayCan : BloodWeaponBase
{
default
{
pic "AmmoIcon6";
shade -8;
scale 0.750000, 0.750000;
count 480;
type 7;
ammotype 6;
}
}
class BloodWeaponTNT : BloodWeaponBase
{
default
{
pic "AmmoIcon5";
shade -8;
scale 0.750000, 0.750000;
count 1;
type 6;
ammotype 5;
}
}
class BloodWeaponLifeLeech : BloodWeaponBase
{
default
{
pic "ICONLEECH";
shade -8;
scale 0.750000, 0.750000;
count 35;
type 9;
ammotype 8;
}
}
// items (ammos)
class BloodAmmoSprayCan : BloodActor {}
class BloodAmmoTNTBundle : BloodActor {}
class BloodAmmoTNTBox : BloodActor {}
class BloodAmmoProxBombBundle : BloodActor {}
class BloodAmmoRemoteBombBundle : BloodActor {}
class BloodAmmoTrappedSoul : BloodActor {}
class BloodAmmoSawedoffFew : BloodActor {}
class BloodAmmoSawedoffBox : BloodActor {}
class BloodAmmoTommygunFew : BloodActor {}
class BloodAmmoVoodooDoll : BloodActor {}
class BloodAmmoTommygunDrum : BloodActor {}
class BloodAmmoTeslaCharge : BloodActor {}
class BloodAmmoFlares : BloodActor {}
class BloodAmmoGasolineCan : BloodActor {}
class BloodAmmoBase : BloodActor
{
meta int count;
meta int type;
meta int weapontype;
property prefix: none;
property count: count;
property type: type;
property weapontype: weapontype;
}
class BloodAmmoSprayCan : BloodAmmoBase
{
default
{
pic "AmmoIcon6";
shade -8;
scale 0.625, 0.625;
count 480;
type 6;
weapontype 7;
}
}
class BloodAmmoTNTBundle : BloodAmmoBase
{
default
{
pic "AmmoIcon5";
shade -8;
scale 0.75, 0.75;
count 1;
type 5;
weapontype 6;
}
}
class BloodAmmoTNTBox : BloodAmmoBase
{
default
{
pic "AmmoTNTBox";
shade -8;
scale 0.75, 0.75;
count 5;
type 5;
weapontype 6;
}
}
class BloodAmmoProxBombBundle : BloodAmmoBase
{
default
{
pic "AmmoIcon10";
shade -8;
scale 0.75, 0.75;
count 1;
type 10;
weapontype 11;
}
}
class BloodAmmoRemoteBombBundle : BloodAmmoBase
{
default
{
pic "AmmoIcon11";
shade -8;
scale 0.75, 0.75;
count 1;
type 11;
weapontype 12;
}
}
class BloodAmmoTrappedSoul : BloodAmmoBase
{
default
{
pic "AmmoIcon8";
shade -8;
scale 0.375, 0.375;
count 10;
type 8;
weapontype 0;
}
}
class BloodAmmoSawedoffFew : BloodAmmoBase
{
default
{
pic "AmmoIcon2";
shade -8;
scale 0.75, 0.75;
count 4;
type 2;
weapontype 0;
}
}
class BloodAmmoSawedoffBox : BloodAmmoBase
{
default
{
pic "AmmoShotgunFew";
shade -8;
scale 0.75, 0.75;
count 15;
type 2;
weapontype 0;
}
}
class BloodAmmoTommygunFew : BloodAmmoBase
{
default
{
pic "AmmoShotgunBox";
shade -8;
scale 0.75, 0.75;
count 15;
type 3;
weapontype 0;
}
}
class BloodAmmoVoodooDoll : BloodAmmoBase
{
default
{
pic "AmmoIcon9";
shade -8;
scale 0.75, 0.75;
count 1;
type 9;
weapontype 10;
}
}
class BloodAmmoTommygunDrum : BloodAmmoBase
{
default
{
pic "AmmoIcon3";
shade -8;
scale 0.75, 0.75;
count 1;
type 3;
weapontype 0;
}
}
class BloodAmmoTeslaCharge : BloodAmmoBase
{
default
{
pic "AmmoIcon7";
shade -8;
scale 0.375, 0.375;
count 32;
type 7;
weapontype 0;
}
}
class BloodAmmoFlares : BloodAmmoBase
{
default
{
pic "AmmoIcon1";
shade -8;
scale 0.75, 0.75;
count 8;
type 1;
weapontype 0;
}
}
class BloodAmmoGasolineCan : BloodAmmoBase
{
default
{
pic "AmmoIcon4";
shade -8;
scale 0.75, 0.75;
count 6;
type 4;
weapontype 0;
}
}
// while these are marked obsolete we need to define them to work to the degree they originally do, i.e. they need their spawn info set.
class BloodAmmoObsolete61 : BloodAmmoBase
{
default
{
pic "AmmoIcon5";
shade -8;
scale 0.75, 0.75;
count 1;
type 5;
weapontype 6;
}
}
class BloodAmmoObsolete71 : BloodAmmoBase
{
default
{
pic "AmmoUseless1";
shade -8;
scale 0.75, 0.75;
count 15;
type 255;
weapontype 0;
}
}
class BloodAmmoObsolete74 : BloodAmmoBase
{
default
{
shade -8;
scale 0.75, 0.75;
count 6;
type 255;
weapontype 0;
}
}
class BloodAmmoObsolete75 : BloodAmmoBase
{
default
{
shade -8;
scale 0.75, 0.75;
count 6;
type 255;
weapontype 0;
}
}
class BloodAmmoObsolete77 : BloodAmmoBase
{
default
{
pic "AmmoUseless2";
shade -8;
scale 0.75, 0.75;
count 8;
type 255;
weapontype 0;
}
}
class BloodAmmoObsolete78 : BloodAmmoBase
{
default
{
pic "AmmoUseless3";
shade -8;
scale 0.75, 0.75;
count 8;
type 255;
weapontype 0;
}
}

View file

@ -90,6 +90,71 @@ struct DUDEEXTRA
class BloodActor : CoreActor native
{
meta int defshade;
meta int defpal;
Property prefix: none;
property shade: defshade;
property pal: defpal;
enum GAME_TYPE
{
kSingleplayer = 1,
kDeathmatch = 2,
kTeamplay = 3
}
enum STAT_ID {
kStatDecoration = 0,
kStatFX = 1,
kStatExplosion = 2,
kStatItem = 3,
kStatThing = 4,
kStatProjectile = 5,
kStatDude = 6,
kStatInactive = 7, // inactive (ambush) dudes
kStatRespawn = 8,
kStatPurge = 9,
kStatMarker = 10,
kStatTraps = 11,
kStatAmbience = 12,
kStatSpares = 13,
kStatFlare = 14,
kStatDebris = 15,
kStatPathMarker = 16,
kStatFree = 1024,
};
enum CALLBACK_ID {
kCallbackNone = -1,
kCallbackFXFlameLick = 0,
kCallbackRemove = 1,
kCallbackFXFlareBurst = 2,
kCallbackFXFlareSpark = 3,
kCallbackFXFlareSparkLite = 4,
kCallbackFXZombieSpurt = 5,
kCallbackFXBloodSpurt = 6,
kCallbackFXArcSpark = 7,
kCallbackFXDynPuff = 8,
kCallbackRespawn = 9,
kCallbackPlayerBubble = 10,
kCallbackEnemeyBubble = 11,
kCallbackCounterCheck = 12,
kCallbackFinishHim = 13,
kCallbackFXBloodBits = 14,
kCallbackFXTeslaAlt = 15,
kCallbackFXBouncingSleeve = 16,
kCallbackReturnFlag = 17,
kCallbackFXPodBloodSpray = 18,
kCallbackFXPodBloodSplat = 19,
kCallbackLeechStateTimer = 20,
kCallbackDropVoodoo = 21, // unused
kCallbackMissileBurst = 22,
kCallbackMissileSpriteBlock = 23,
kCallbackGenDudeUpdate = 24,
kCallbackCondition = 25,
}
native double dudeSlope;
native readonly bool hasx;
native bool explosionhackflag; // this originally hijacked the target field which is not safe when working with pointers.
@ -111,5 +176,71 @@ class BloodActor : CoreActor native
native void ChangeType(class<BloodActor> newtype);
native static BloodActor InsertSprite(sectortype pSector, int nStat, Class<BloodActor> cls);
native void addX();
native void evPostActorCallback(int delta, int callback);
native double, double getActorExtents();
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static BloodActor spawnSprite(sectortype pSector, Vector3 pos, int nStat, bool setextra, Class<BloodActor> cls)
{
let spawned = InsertSprite(pSector, nStat, cls);
spawned.lotag = Raze.getSpawnNum(cls); // we still need this, mapping may not be ambiguous.
spawned.setposition(pos);
if (setextra && !spawned.hasX)
{
spawned.addX();
spawned.hit.florhit.setNone();
spawned.hit.ceilhit.setNone();
}
return spawned;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
BloodActor dropObject(class<BloodActor> itemtype)
{
if (!(itemtype is 'BloodItemBase') &&
!(itemtype is 'BloodAmmoBase') &&
!(itemtype is 'BloodWeaponBase')) return null;
let pos = self.pos;
let sector = Raze.updatesector(pos.XY, self.sector);
double c,f;
[c, f] = sector.getSlopes(pos.XY);
let spawned = spawnSprite(sector, (pos.xy, f), kStatItem, false, itemtype);
if (!spawned) return null;
spawned.cstat &= ~CSTAT_SPRITE_BLOCK_ALL;
spawned.shade = spawned.defshade;
if (itemtype is 'BloodKeyBase' && Blood.GameType() == kSingleplayer)
{
spawned.xspr.respawn = 3;
}
if (itemtype is 'BloodFlagBase' && Blood.GameType() == kTeamplay)
{
spawned.evPostActorCallback(1800, kCallbackReturnFlag);
}
double top, bottom;
[top, bottom] = spawned.GetActorExtents();
if (bottom >= spawned.pos.Z)
spawned.pos.Z -= (bottom - spawned.pos.Z);
return spawned;
}
}

View file

@ -49,6 +49,7 @@ struct Blood native
native static void sndStartSampleNamed(String sname, int volume, int channel);
native static TextureID PowerupIcon(int pwup);
native static BloodPlayer GetViewPlayer();
native static int gameType();
// These are just dummies to make the MP statusbar code compile.

View file

@ -185,6 +185,7 @@ struct CollisionData
native void setWall(walltype w);
native void setActor(CoreActor a);
native void setVoid();
native void setNone();
}
struct HitInfo
@ -213,6 +214,7 @@ struct Raze
native static void SetReverb(int r);
native static void SetReverbDelay(int d);
native static Sound FindSoundByResID(int id);
native static int getSpawnNum(class<CoreActor> act);
native static int tileflags(TextureID tex);
native static int tilesurface(TextureID tex);