ReC98/th01/main/player/orb.cpp

134 lines
3.8 KiB
C++

#include "th01/main/player/orb.hpp"
extern const double ORB_VELOCITY_Y_MIN;
extern const float ORB_VELOCITY_Y_MAX;
extern const double ORB_COEFFICIENT_OF_RESTITUTION;
inline double gravity_for(const double& force)
{
return ((orb_force_frame / 5) + orb_force);
}
/// Temporary data segment workarounds
/// ----------------------------------
// Also needs to be spelled out in ASM to avoid the unwanted WAIT instruction
// afterwards.
#define GRAVITY_FOR(force) \
_AX = orb_force_frame / 5; \
__asm mov [bp-2], ax; \
__asm fild word ptr [bp-2]; \
__asm fadd force;
// Neither WAIT nor FWAIT emit the emulated WAIT we want...
#define FWAIT db 0xCD, 0x3D;
/// ----------------------------------
int orb_velocity_y_update(void)
{
/* TODO: Proper decompilation, once data can be emitted here:
* ----------------------------------------------------------
orb_velocity_y = gravity_for(orb_force);
if(orb_velocity_y > ORB_VELOCITY_Y_MAX) {
orb_velocity_y = ORB_VELOCITY_Y_MAX;
} else if(orb_velocity_y < ORB_VELOCITY_Y_MIN) {
orb_velocity_y = ORB_VELOCITY_Y_MIN;
}
return gravity_for(orb_force);
* ----------------------------------------------------------
* Performing arithmetic or comparisons between a double (orb_velocity_y)
* and a float (ORB_VELOCITY_Y_MAX) variable always FLDs the float first,
* before emitting the corresponding FPU instruction with the double,
* which is not what we want here.
*/
GRAVITY_FOR(orb_force);
__asm {
fstp orb_velocity_y;
fld orb_velocity_y;
fcomp ORB_VELOCITY_Y_MAX;
fstsw [bp-2];
FWAIT;
mov ax, [bp-2];
sahf;
jbe min_velocity_check;
fld ORB_VELOCITY_Y_MAX;
}
goto set_velocity;
min_velocity_check:
if(orb_velocity_y < ORB_VELOCITY_Y_MIN) __asm {
fld ORB_VELOCITY_Y_MIN;
set_velocity:
fstp orb_velocity_y;
FWAIT;
}
return gravity_for(orb_force);
}
#define random_velocity_change(val, new_velocity) \
if(orb_force_frame < 17) { \
if((rand() % 50) == val) { \
orb_velocity_x = new_velocity; \
} \
}
void orb_force_new(double immediate, orb_force_t force)
{
extern const float ORB_FORCE_2_0;
extern const double ORB_FORCE_SHOT_BASE;
if(force == OF_BOUNCE_FROM_GROUND) {
orb_force = (-orb_velocity_y * ORB_COEFFICIENT_OF_RESTITUTION);
if(orb_velocity_x == OVX_0) {
random_velocity_change(0, OVX_4_LEFT);
random_velocity_change(1, OVX_4_RIGHT);
}
}
if(force == OF_BOUNCE_FROM_TOP) {
orb_force = ((-orb_velocity_y) - (orb_force_frame / 4));
}
if(force == OF_SHOT) {
/* TODO: Proper decompilation, once data can be emitted here:
* ----------------------------------------------------------
orb_force = ((orb_velocity_y / ORB_FORCE_2_0) + ORB_FORCE_SHOT_BASE);
* ----------------------------------------------------------
* Performing arithmetic or comparisons between a double
* (orb_velocity_y) and a float (ORB_FORCE_2_0) variable always FLDs
* the float first, before emitting the corresponding FPU instruction
* with the double, which is not what we want here.
*/
__asm {
fld orb_velocity_y;
fdiv ORB_FORCE_2_0;
fadd ORB_FORCE_SHOT_BASE;
fstp orb_force;
FWAIT;
}
}
if(force == OF_IMMEDIATE) {
orb_force = immediate;
}
orb_force_frame = 0;
}
void orb_move_x(orb_velocity_x_t velocity_x)
{
switch(velocity_x) {
case OVX_4_LEFT: orb_cur_left -= 4; break;
case OVX_4_RIGHT: orb_cur_left += 4; break;
case OVX_8_LEFT: orb_cur_left -= 8; break;
case OVX_8_RIGHT: orb_cur_left += 8; break;
}
if(orb_cur_left <= ORB_LEFT_MIN) {
if(orb_velocity_x == OVX_4_LEFT) {
orb_velocity_x = OVX_4_RIGHT;
} else if(orb_velocity_x == OVX_8_LEFT) {
orb_velocity_x = OVX_8_RIGHT;
}
}
if(orb_cur_left >= ORB_LEFT_MAX) {
if(orb_velocity_x == OVX_4_RIGHT) {
orb_velocity_x = OVX_4_LEFT;
} else if(orb_velocity_x == OVX_8_RIGHT) {
orb_velocity_x = OVX_8_LEFT;
}
}
}