raze/source/games/duke/src/animatesprites.cpp
Christoph Oelckers a8e03723ef - NOSHADOW flag.
2023-05-19 23:03:20 +02:00

219 lines
5.9 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2003 - 3D Realms Entertainment
Copyright (C) 2020 - Christoph Oelckers
This file is part of Raze
Duke Nukem 3D is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Original Source: 1996 - Todd Replogle
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#include "ns.h"
#include "global.h"
#include "dukeactor.h"
#include "gamefuncs.h"
#include "models/modeldata.h"
#include "buildtiles.h"
BEGIN_DUKE_NS
void drawshadows(tspriteArray& tsprites, tspritetype* t, DDukeActor* h)
{
if (r_shadows && !(h->flags1 & SFLAG_NOSHADOW) && !(h->spr.cstat2 & CSTAT2_SPRITE_NOSHADOW))
{
auto sectp = t->sectp;
double floorz;
if ((sectp->lotag & 0xff) > 2 || h->spr.statnum == STAT_PROJECTILE || h->spr.statnum == STAT_MISC || (h->flags2 & SFLAG2_FLOATING))
floorz = sectp->floorz;
else
floorz = h->floorz;
if (h->spr.pos.Z - floorz < 8 && ps[screenpeek].GetActor()->getOffsetZ() < floorz)
{
auto shadowspr = tsprites.newTSprite();
*shadowspr = *t;
shadowspr->statnum = STAT_TEMP;
shadowspr->scale.Y = (max(t->scale.Y * 0.125, 0.0625));
shadowspr->shade = 127;
shadowspr->cstat |= CSTAT_SPRITE_TRANSLUCENT;
shadowspr->pos.Z = floorz;
shadowspr->pal = 4;
if (hw_models && modelManager.CheckModel(t->spritetexture(), t->pal))
{
shadowspr->scale.Y = (0);
// 512:trans reverse
//1024:tell MD2SPRITE.C to use Z-buffer hacks to hide overdraw issues (todo: use a stencil to do this right.)
shadowspr->clipdist |= TSPR_FLAGS_MDHACK;
shadowspr->cstat |= CSTAT_SPRITE_TRANS_FLIP;
}
else
{
// Alter the shadow's position so that it appears behind the sprite itself.
auto look = (shadowspr->pos.XY() - ps[screenpeek].GetActor()->spr.pos.XY()).Angle();
shadowspr->pos.XY() += look.ToVector() * 2;
}
}
}
}
// ---------------------------------------------------------------------------
//
// some ugly stuff here: RRRA forces some animations fullbright,
// but there is no good way to set this up for CON in any decent way.
// These frames are being hacked in here. No need to make this configurable, though.
// For our new format this can be done as a real feature.
//
// ---------------------------------------------------------------------------
bool RRRAFullbrightHack(tspritetype* t, int k)
{
if (t->ownerActor->IsKindOf(RedneckBillyRayClass))
{
return k >= 102 && k <= 151;
}
else if (t->ownerActor->IsKindOf(RedneckBikerClass))
{
return (k >= 54 && k <= 58) || (k >= 84 && k <= 88);
}
else if (t->ownerActor->IsKindOf(RedneckCheerleaderClass))
{
return k >= 102 && k <= 151;
}
return false;
}
void applyanimations(tspritetype* t, DDukeActor* h, const DVector2& viewVec, DAngle viewang)
{
if (!(h->flags2 & SFLAG2_DONTANIMATE))// && (t->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) != CSTAT_SPRITE_ALIGNMENT_SLAB)
{
DAngle kang;
auto action = h->curAction;
int k = 0, l = 0;
if (h->curAction->name != NAME_None)
{
l = action->rotationtype;
if (tilehasmodelorvoxel(h->spr.spritetexture(), h->spr.pal))
{
k = 0;
t->cstat &= ~CSTAT_SPRITE_XFLIP;
}
else switch (l)
{
case 2:
k = angletorotation1(t->Angles.Yaw, viewang, 8, 1);
break;
case 3:
case 4:
k = angletorotation1(t->Angles.Yaw, viewang, 7);
if (k > 3)
{
t->cstat |= CSTAT_SPRITE_XFLIP;
k = 7 - k;
}
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
break;
case 5:
kang = (t->pos.XY() - viewVec).Angle();
k = angletorotation1(t->Angles.Yaw, kang);
if (k > 4)
{
k = 8 - k;
t->cstat |= CSTAT_SPRITE_XFLIP;
}
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
break;
case 7:
kang = (t->pos.XY() - viewVec).Angle();
k = angletorotation2(t->Angles.Yaw, kang);
if (k > 6)
{
k = 12 - k;
t->cstat |= CSTAT_SPRITE_XFLIP;
}
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
break;
case 8:
k = angletorotation1(t->Angles.Yaw, viewang);
t->cstat &= ~CSTAT_SPRITE_XFLIP;
break;
default:
if (isRR())
{
bool bg = badguy(h);
if (bg && h->spr.statnum == STAT_ZOMBIEACTOR && h->spr.extra > 0)
{
kang = (t->pos.XY() - viewVec).Angle();
k = angletorotation1(t->Angles.Yaw, kang);
if (k > 4)
{
k = 8 - k;
t->cstat |= CSTAT_SPRITE_XFLIP;
}
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
break;
}
k = 0;
bg = 0;
break;
}
}
k += action->offset + l * h->curframe;
int texid = t->spritetexture().GetIndex() + k; // we cannot work with texture IDs here because their arithmetics are limited.
if (isRRRA() && RRRAFullbrightHack(t, k)) t->shade = -127;
FGameTexture* tex = TexMan.GameByIndex(texid);
if (l > 0)
{
while(1)
{
if (!tex || tex->isValid()) break;
texid -= l; //back up one frame if this one is invald.
tex = TexMan.GameByIndex(texid);
}
}
if (!tex)
{
t->setspritetexture(FNullTextureID());
t->scale = DVector2(0, 0);
}
else t->setspritetexture(tex->GetID());
if (h->dispictex.isValid())
h->dispictex = t->spritetexture();
}
else if (display_mirror == 1)
t->cstat |= CSTAT_SPRITE_XFLIP;
}
}
END_DUKE_NS