Skip to content

Commit

Permalink
A_ChangeModeldef
Browse files Browse the repository at this point in the history
-Added A_ChangeModelDef
A_ChangeModel(modeldef, modelpath, model, modelindex, skinpath, skin, skinid, flags)

This can change the modeldef, model and skins of an actor.

Currently, modelindex and skinindex accept indices from 0-15.

An actor MUST have a modeldef in order to use this function, either defined from modeldef, or given one through the modeldef parameter. You can pass "" to use the same modeldef. Likewise, passing "" for model or skin will just revert to the default model.

Available flags:
CMDL_WEAPONTOPLAYER - If used on a weapon, this instead change's the model on the player instead.

One issue I am aware of right now is that clearing a model by "" sort of works but is buggy. For now you can just manually set the model back using the names explicitly. However, I am stumped and I think getting more eyes on it would help.
  • Loading branch information
ShinyMetagross authored and coelckers committed Jul 22, 2022
1 parent e649357 commit 5abadd3
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/playsim/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,9 @@ class AActor : public DThinker
DVector3 WorldOffset;
double Speed;
double FloatSpeed;
FName modelDef;
int models[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; //[SM] - I hate this solution, but it get's the job done
FTextureID skins[16];

// interaction info
FBlockNode *BlockNode; // links in blocks (if needed)
Expand Down
41 changes: 41 additions & 0 deletions src/playsim/p_actionfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
#include "sbar.h"
#include "actorinlines.h"
#include "types.h"
#include "model.h"

static FRandom pr_camissile ("CustomActorfire");
static FRandom pr_cabullet ("CustomBullet");
Expand Down Expand Up @@ -5020,6 +5021,46 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetMugshotState)
return 0;
}

//==========================================================================
//
// A_ChangeModel(modeldef, modelpath, model, modelindex, skinpath, skin, skinid, flags)
//
// This function allows the changing of an actor's modeldef, or models and/or skins at a given index
//==========================================================================

enum ChangeModelFlags
{
CMDL_WEAPONTOPLAYER = 1
};

DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_NAME(modeldef)
PARAM_STRING_VAL(modelpath)
PARAM_NAME(model)
PARAM_INT(modelindex)
PARAM_STRING_VAL(skinpath)
PARAM_NAME(skin)
PARAM_INT(skinindex)
PARAM_INT(flags)

if (self == nullptr)
ACTION_RETURN_BOOL(false);

AActor* mobj = ACTION_CALL_FROM_PSPRITE() && (flags & CMDL_WEAPONTOPLAYER) ? self : stateowner;

if (modelpath[(int)modelpath.Len() - 1] != '/') modelpath += '/';
if (skinpath[(int)skinpath.Len() - 1] != '/') skinpath += '/';

mobj->hasmodel = modeldef == nullptr && !mobj->hasmodel ? 1 : 0;
mobj->modelDef = modeldef;
mobj->models[modelindex] = model != nullptr ? FindModel(modelpath.GetChars(), model.GetChars()) : -1;
mobj->skins[skinindex] = skin != nullptr ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : mobj->skins[skinindex] = FNullTextureID();

return 0;
}

// This needs to account for the fact that internally renderstyles are stored as a series of operations,
// but the script side only cares about symbolic constants.
DEFINE_ACTION_FUNCTION(AActor, GetRenderStyle)
Expand Down
14 changes: 8 additions & 6 deletions src/r_data/models.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ EXTERN_CVAR (Bool, r_drawvoxels)
extern TDeletingArray<FVoxel *> Voxels;
extern TDeletingArray<FVoxelDef *> VoxelDefs;

void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame* smf, const FState* curState, const int curTics, const PClass* ti, int translation);
void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame* smf, const FState* curState, const int curTics, const PClass* ti, int translation, AActor* actor);


void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac)
Expand Down Expand Up @@ -176,14 +176,14 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod
float orientation = scaleFactorX * scaleFactorY * scaleFactorZ;

renderer->BeginDrawModel(actor->RenderStyle, smf, objectToWorldMatrix, orientation < 0);
RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, actor->GetClass(), translation);
RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, actor->modelDef != nullptr ? PClass::FindActor(actor->modelDef) : actor->GetClass(), translation, actor);
renderer->EndDrawModel(actor->RenderStyle, smf);
}

void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, float ofsX, float ofsY)
{
AActor * playermo = players[consoleplayer].camera;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelDef != nullptr ? PClass::FindActor(psp->Caller->modelDef) : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr;

// [BB] No model found for this sprite, so we can't render anything.
if (smf == nullptr)
Expand Down Expand Up @@ -224,11 +224,11 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, float ofsX, float o
renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0);
uint32_t trans = psp->GetTranslation() != 0 ? psp->GetTranslation() : 0;
if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation;
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), psp->Caller->GetClass(), trans);
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), psp->Caller->modelDef != nullptr ? PClass::FindActor(psp->Caller->modelDef) : psp->Caller->GetClass(), trans, psp->Caller);
renderer->EndDrawHUDModel(playermo->RenderStyle);
}

void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, int translation)
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, int translation, AActor* actor)
{
// [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation
// and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame.
Expand Down Expand Up @@ -278,10 +278,12 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr

for (int i = 0; i < smf->modelsAmount; i++)
{
if (actor->models[i] != -1)
smf->modelIDs[i] = actor->models[i];
if (smf->modelIDs[i] != -1)
{
FModel * mdl = Models[smf->modelIDs[i]];
auto tex = smf->skinIDs[i].isValid() ? TexMan.GetGameTexture(smf->skinIDs[i], true) : nullptr;
auto tex = actor->skins[i].isValid() ? TexMan.GetGameTexture(actor->skins[i], true) : smf->skinIDs[i].isValid() ? TexMan.GetGameTexture(smf->skinIDs[i], true) : nullptr;
mdl->BuildVertexBuffer(renderer);

mdl->PushSpriteMDLFrame(smf, i);
Expand Down
2 changes: 1 addition & 1 deletion src/rendering/hwrenderer/scene/hw_sprites.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
z += fz;
}

modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->modelDef != nullptr ? PClass::FindActor(thing->modelDef) : thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));

// don't bother drawing sprite shadows if this is a model (it will never look right)
if (modelframe && isSpriteShadow)
Expand Down
1 change: 1 addition & 0 deletions wadsrc/static/zscript/actors/actor.zs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,7 @@ class Actor : Thinker native
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.);
deprecated("2.3", "Use 'b<FlagName> = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value);
native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
action native void A_ChangeModel(name modeldef, string modelpath = "", name model = "", int modelindex = 0, string skinpath = "", name skin = "", int skinindex = 0, int flags = 0);

void A_SetFriendly (bool set)
{
Expand Down
6 changes: 6 additions & 0 deletions wadsrc/static/zscript/constants.zs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ enum ERadiusGiveFlags
RGF_EITHER = 1 << 17,
};

// Change model flags
enum ChangeModelFlags
{
CMDL_WEAPONTOPLAYER = 1
};

// Activation flags
enum EActivationFlags
{
Expand Down

1 comment on commit 5abadd3

@leohub2016
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be upgraded (in future), so other modeldef parameters will be changeable, for example scale, offset etc? With possibility to change zoffset it will be very flexible to easy change offset for example from 10 to 0 with 35 frames (which is pain in ass to do in modeldef)

Please sign in to comment.