Merge branch 'talk-point' into 'master'

Talk Point visual (for dialogue)

See merge request KartKrew/Kart!1944
This commit is contained in:
Gunla 2024-02-24 02:37:20 +00:00
commit 8063866479
9 changed files with 304 additions and 43 deletions

View file

@ -3005,6 +3005,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
// MT_STARSTREAM
"S_STARSTREAM",
// MT_SCRIPT_THING
"S_TALKPOINT",
"S_TALKPOINT_ORB",
};
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
@ -3726,6 +3730,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_CHECKPOINT_END",
"MT_SCRIPT_THING",
"MT_SCRIPT_THING_ORB",
"MT_RIDEROID",
"MT_RIDEROIDNODE",

View file

@ -734,6 +734,9 @@ char sprnames[NUMSPRITES + 1][5] =
"SENC",
"SEAS",
// Tutorial
"TLKP", // Talk Point
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
"VIEW",
};
@ -3515,6 +3518,10 @@ state_t states[NUMSTATES] =
// MT_STARSTREAM
{SPR_SEAS, FF_ANIMATE|0, 30, {NULL}, 29, 1, S_NULL}, // S_STARSTREAM
// MT_SCRIPT_THING
{SPR_TLKP, 0|FF_SEMIBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_TALKPOINT
{SPR_TLKP, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_TALKPOINT_ORB
};
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
@ -18517,7 +18524,34 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_SCRIPT_THING
4096, // doomednum
S_INVISIBLE, // spawnstate
S_TALKPOINT, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_SCRIPT_THING_ORB
-1, // doomednum
S_TALKPOINT_ORB, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound

View file

@ -1269,6 +1269,9 @@ typedef enum sprite
SPR_SENC, // Cabotron
SPR_SEAS, // Starstream
// Tutorial
SPR_TLKP, // Talk Point
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
@ -4002,6 +4005,10 @@ typedef enum state
// MT_STARSTREAM
S_STARSTREAM,
// MT_SCRIPT_THING
S_TALKPOINT,
S_TALKPOINT_ORB,
S_FIRSTFREESLOT,
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
NUMSTATES
@ -4742,6 +4749,7 @@ typedef enum mobj_type
MT_CHECKPOINT_END,
MT_SCRIPT_THING,
MT_SCRIPT_THING_ORB,
MT_RIDEROID,
MT_RIDEROIDNODE,

View file

@ -392,6 +392,11 @@ void Obj_SSCabotronMobjSpawn(mobj_t* mo);
void Obj_SSCabotronMobjThink(mobj_t* mo);
void Obj_SSCabotronStarMobjThink(mobj_t* mo);
/* Talk Point */
void Obj_TalkPointInit(mobj_t* mo);
void Obj_TalkPointThink(mobj_t* mo);
void Obj_TalkPointOrbThink(mobj_t* mo);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -53,6 +53,7 @@ target_sources(SRB2SDL2 PRIVATE
cloud.c
waterfall-particle.c
sealed-star.c
talk-point.cpp
)
add_subdirectory(versus)

231
src/objects/talk-point.cpp Normal file
View file

@ -0,0 +1,231 @@
// DR. ROBOTNIK'S RING RACERS
//-------------------------------
// Copyright (C) 2024 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <algorithm>
#include <array>
#include "objects.hpp"
#include "../doomdef.h"
#include "../g_game.h"
#include "../p_spec.h"
#include "../tables.h"
using namespace srb2::objects;
namespace
{
Vec2<Fixed> angle_vector(angle_t x)
{
return Vec2<Fixed> {FCOS(x), FSIN(x)};
}
struct TalkPoint : Mobj
{
static constexpr angle_t kSpinSpeed = ANGLE_11hh;
static constexpr tic_t kCollectDuration = 12;
void thing_args() = delete;
Fixed radius() const { return mobj_t::thing_args[0] * FRACUNIT; }
bool oneshot() const { return !mobj_t::thing_args[1]; }
bool disabled() const { return mobj_t::thing_args[2]; }
bool invisible() const { return mobj_t::thing_args[3]; }
void extravalue1() = delete;
tic_t collect() const { return mobj_t::extravalue1; }
void collect(tic_t n) { mobj_t::extravalue1 = n; }
// This value scales up as the radius gets larger
Fixed scaling() const { return std::min<Fixed>(FRACUNIT, Fixed {320 * mapobjectscale} / radius()); }
void init();
void think()
{
if (disabled())
{
// turned off
return;
}
if (collect() > 0)
{
collect(collect() - 1);
if (collect() == 0)
{
remove();
return;
}
// Collect animation: stretch upward, spin faster, fade out
spriteyscale(kCollectDuration * FRACUNIT / collect());
angle += kCollectDuration * kSpinSpeed / collect();
renderflags = (renderflags & ~RF_TRANSMASK) |
((9 - (collect() * 9 / kCollectDuration)) << RF_TRANSSHIFT);
return;
}
angle += kSpinSpeed;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false || players[i].spectator == true)
{
continue;
}
Mobj* player_mobj = static_cast<Mobj*>(players[i].mo);
if (!Mobj::valid(player_mobj))
{
continue;
}
Fixed dist = (pos2d() - player_mobj->pos2d()).magnitude();
if (dist < radius())
{
P_ActivateThingSpecial(this, player_mobj);
if (oneshot())
{
// Collect animation: appear brighter during fade-out
renderflags |= RF_FULLBRIGHT;
collect(kCollectDuration);
}
if (!invisible() && P_IsDisplayPlayer(&players[i]))
{
S_StartSound(nullptr, sfx_hint);
}
break;
}
}
}
};
struct Orb : Mobj
{
static constexpr std::array<skincolornum_t, 10> kColors = {
SKINCOLOR_NONE,
SKINCOLOR_JAWZ,
SKINCOLOR_AQUAMARINE,
SKINCOLOR_LIME,
SKINCOLOR_BANANA,
SKINCOLOR_CREAMSICLE,
SKINCOLOR_DAWN,
SKINCOLOR_TAFFY,
SKINCOLOR_VIOLET,
SKINCOLOR_RUST,
};
void target() = delete;
TalkPoint* origin() const { return Mobj::target<TalkPoint>(); }
void origin(TalkPoint* n) { Mobj::target(n); }
void extravalue1() = delete;
angle_t speed() const { return mobj_t::extravalue1; }
void speed(angle_t n) { mobj_t::extravalue1 = n; }
bool valid() const { return Mobj::valid(origin()) && origin()->valid(); }
static Orb* spawn(TalkPoint* origin, UINT8 index, angle_t angle)
{
Orb* orb = Mobj::spawn<Orb>({origin->pos2d() + radius_vector(origin, angle), origin->z}, MT_SCRIPT_THING_ORB);
orb->origin(origin);
orb->color = kColors[index % kColors.size()]; // cycle colors
orb->colorized = true;
orb->angle = angle;
orb->sprzoff(20 * mapobjectscale); // roughly eye level with the player
orb->speed(FixedAngle(Fixed {45*FRACUNIT/8} * origin->scaling())); // slower with larger radius
return orb;
}
void think()
{
if (!valid())
{
remove();
return;
}
// rotate
angle += speed();
move_origin({origin()->pos2d() + radius_vector(), origin()->z});
// bob
spriteyoffset(8 * FSIN(angle + (leveltime * speed())));
}
private:
static vec2 radius_vector(TalkPoint* origin, angle_t angle)
{
// Collect animation: orbs fly outward
return angle_vector(angle) * origin->radius() * origin->spriteyscale();
}
vec2 radius_vector() const { return radius_vector(origin(), angle); }
};
void TalkPoint::init()
{
if (invisible())
{
renderflags |= RF_DONTDRAW;
return;
}
if (scaling() == 0)
{
return;
}
// Orbs get spaced further apart as the radius increases
fixed_t orb_rad = Fixed {88 * mapobjectscale} / scaling();
if (orb_rad == 0)
{
return;
}
// Spawn more orbs within a larger radius
INT32 count = (Fixed {M_TAU_FIXED} * radius()) / orb_rad;
if (count == 0)
{
return;
}
angle_t step = ANGLE_MAX / count;
angle_t angle = 0;
for (INT32 i = 0; i < count; ++i)
{
Orb::spawn(this, i, angle);
angle += step;
}
}
}; // namespace
void Obj_TalkPointInit(mobj_t* mo)
{
static_cast<TalkPoint*>(mo)->init();
}
void Obj_TalkPointThink(mobj_t* mo)
{
static_cast<TalkPoint*>(mo)->think();
}
void Obj_TalkPointOrbThink(mobj_t* mo)
{
static_cast<Orb*>(mo)->think();
}

View file

@ -6458,48 +6458,11 @@ static void P_MobjSceneryThink(mobj_t *mobj)
Obj_CheckpointThink(mobj);
break;
case MT_SCRIPT_THING:
{
if (mobj->thing_args[2] != 0)
{
// turned off
break;
}
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false || players[i].spectator == true)
{
continue;
}
player_t *player = &players[i];
if (P_MobjWasRemoved(player->mo) == true)
{
continue;
}
fixed_t dist = R_PointToDist2(
mobj->x, mobj->y,
player->mo->x, player->mo->y
);
if (dist < mobj->thing_args[0] * FRACUNIT)
{
P_ActivateThingSpecial(mobj, player->mo);
if (mobj->thing_args[1] == 0)
{
P_RemoveMobj(mobj);
Obj_TalkPointThink(mobj);
return;
case MT_SCRIPT_THING_ORB:
Obj_TalkPointOrbThink(mobj);
return;
}
break;
}
}
break;
}
case MT_SPIKEDTARGET:
{
if (P_MobjWasRemoved(mobj->target) || (mobj->target->health <= 0) || (mobj->target->z == mobj->target->floorz))
@ -10605,6 +10568,10 @@ fixed_t P_GetMobjDefaultScale(mobj_t *mobj)
return 4*FRACUNIT;
case MT_WALLSPIKE:
return 2*FRACUNIT;
case MT_SCRIPT_THING:
return 4*FRACUNIT;
case MT_SCRIPT_THING_ORB:
return 2*FRACUNIT;
default:
break;
}
@ -13881,6 +13848,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
Obj_SSWindowMapThingSpawn(mobj, mthing);
break;
}
case MT_SCRIPT_THING:
{
Obj_TalkPointInit(mobj);
break;
}
default:
break;
}

View file

@ -1263,6 +1263,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"ssbmpr", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "UNDESCRIBED SSBMPR"}, // SF_X4AWAYSOUND
{"chcrun", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "UNDESCRIBED CHCRUN"},
{"hint", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hint Ring"},
// Damage sounds
{"dmga1", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"},
{"dmga2", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"},

View file

@ -1338,6 +1338,9 @@ typedef enum
sfx_ssbmpr,
sfx_chcrun,
// Tutorial Hint
sfx_hint,
// Damage sounds
sfx_dmga1,
sfx_dmga2,