||This article or section is incomplete. It doesn't have all of the necessary core information on this topic. Please help the SRB2 Wiki by finishing this article.
||This article or section is outdated and has not been updated to reflect the release of SRB2 v2.2.
Please help the Wiki by correcting or removing any misinformation, as well as adding any new information to the page.
Update for 2.2.0:
- ...oh boy, there so many new options stuffed in Var2 alone
MF_GRENADEBOUNCE does something special here too
A_OrbitNights is an action that is used to make the Chaos Emeralds that appear in NiGHTS-themed Special Stages – after destroying the Ideya Capture – orbit around Super Sonic as he flies around the track. The actor will orbit around its target, with a fixed radius of 32 fracunits, as long as it is a player who is playing as Super Sonic in a NiGHTS level, otherwise it will remove itself from existence. The actor's Z position will also oscillate as it orbits the target player.
Var1 determines the angle increment to apply for each use of this action; this action should be called every tic for the actor to orbit around its target properly. The value in degrees cannot simply be placed here however – instead, the angle constants or multiples of them should be used here; e.g.
ANG2*2 for an angle increment of 4 degrees/tic (the angle increment used by the orbiting Chaos Emeralds). Note that Var1 will also affect the rate at which the actor modifies its Z position accordingly with the horizontal movement.
The lower 16 bits of Var2 determine the offset of the angle calculated for the actor's Z position – unlike with Var1, the value for Var2 lower 16 bits is to be given in degrees as an integer. If the lower 16 bits of Var2 is set to 0, the actor will appear to orbit its target in a tilted elliptical orbit, rather than just oscillating vertically while orbiting its target in a horizontal circle. Note that the actual Z position of the actor will be 16 fracunits above the Z position of the actor's target, offsetted by up to 20 fracunits in either direction relative to this position.
The upper 16 bits of Var2 determine whether the actor is a Nightopian Helper or not; any value other than 0 will turn this effect on. When turned on, the actor additionally requires the target player's Nightopian Helper powerup timer (
pw_nights_helper) to still be in effect; if it is not, the actor will remove itself from existence. This feature is used by the Nightopian Helper that orbits the player while the power-up is in effect.
Code – A_OrbitNights
// Function: A_OrbitNights
// Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.)
// var1 = Angle adjustment (aka orbit speed)
// Bits 1-10: height offset, max 1023
// Bits 11-16: X radius factor (max 63, default 20)
// Bit 17: set if object is Nightopian Helper
// Bit 18: set to define X/Y/Z rotation factor
// Bits 19-20: Unused
// Bits 21-26: Y radius factor (max 63, default 32)
// Bits 27-32: Z radius factor (max 63, default 32)
// If MF_GRENADEBOUNCE is flagged on mobj, use actor->threshold to define X/Y/Z radius factor, max 1023 each:
// Bits 1-10: X factor
// Bits 11-20: Y factor
// Bits 21-30: Z factor
void A_OrbitNights(mobj_t* actor)
INT32 ofs = (var2 & 0x3FF);
boolean ishelper = (var2 & 0x10000);
boolean donotrescale = (var2 & 0x40000);
INT32 xfactor = 32, yfactor = 32, zfactor = 20;
if (LUA_CallAction("A_OrbitNights", actor))
if (actor->flags & MF_GRENADEBOUNCE)
xfactor = (actor->threshold & 0x3FF);
yfactor = (actor->threshold & 0xFFC00) >> 10;
zfactor = (actor->threshold & 0x3FF00000) >> 20;
else if (var2 & 0x20000)
xfactor = (var2 & 0xFC00) >> 10;
yfactor = (var2 & 0x3F00000) >> 20;
zfactor = (var2 & 0xFC000000) >> 26;
|| (actor->target->player &&
// if NiGHTS special stage and not NiGHTSmode.
(((maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE))
// Also remove this object if they no longer have a NiGHTS helper
|| (ishelper && !actor->target->player->powers[pw_nights_helper]))))
actor->extravalue1 += var1;
const angle_t fa = (angle_t)actor->extravalue1 >> ANGLETOFINESHIFT;
const angle_t ofa = ((angle_t)actor->extravalue1 + (ofs*ANG1)) >> ANGLETOFINESHIFT;
const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(xfactor*FRACUNIT, actor->scale));
const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(zfactor*FRACUNIT, actor->scale));
const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(yfactor*FRACUNIT, actor->scale));
actor->x = actor->target->x + fc;
actor->y = actor->target->y + fs;
actor->z = actor->target->z + fh + FixedMul(16*FRACUNIT, actor->scale);
// Semi-lazy hack
actor->angle = (angle_t)actor->extravalue1 + ANGLE_90;
if (ishelper && actor->target->player) // Flash a helper that's about to be removed.
if ((actor->target->player->powers[pw_nights_helper] < TICRATE)
&& (actor->target->player->powers[pw_nights_helper] & 1))
actor->flags2 |= MF2_DONTDRAW;
actor->flags2 &= ~MF2_DONTDRAW;
if (!donotrescale && actor->destscale != actor->target->destscale)
actor->destscale = actor->target->destscale;