MuckyFoot-UrbanChaos/fallen/Source/balloon.cpp
2017-05-20 11:14:17 +10:00

577 lines
9.7 KiB
C++

//
// Balloons.
//
#include "game.h"
#include "animate.h"
#include "balloon.h"
#include "mav.h"
//
// The balloons...
//
BALLOON_Balloon *BALLOON_balloon;//[BALLOON_MAX_BALLOONS];
SLONG BALLOON_balloon_upto;
//
// The desired distance between balloon points.
//
#ifndef TARGET_DC
#ifndef PSX
#define BALLOON_POINT_DIST (0x2000)
void BALLOON_init()
{
SLONG i;
//
// Initialise the balloon array.
//
memset(BALLOON_balloon, 0, sizeof(BALLOON_Balloon)*BALLOON_MAX_BALLOONS);
BALLOON_balloon_upto = 1;
}
//
// Returns the point on a thing that a balloon is attached to.
//
void BALLOON_get_attached_point(
UWORD thing,
SLONG *ax,
SLONG *ay,
SLONG *az)
{
SLONG px;
SLONG py;
SLONG pz;
Thing *p_thing = TO_THING(thing);
switch(p_thing->Class)
{
case CLASS_PERSON:
calc_sub_objects_position(
p_thing,
p_thing->Draw.Tweened->AnimTween,
SUB_OBJECT_LEFT_HAND,
&px,
&py,
&pz);
px <<= 8;
py <<= 8;
pz <<= 8;
px += p_thing->WorldPos.X;
py += p_thing->WorldPos.Y;
pz += p_thing->WorldPos.Z;
break;
default:
ASSERT(0);
break;
}
*ax = px;
*ay = py;
*az = pz;
return;
}
UBYTE BALLOON_create(UWORD thing, UBYTE type)
{
SLONG i;
SLONG ax;
SLONG ay;
SLONG az;
Thing *p_thing = TO_THING(thing);
BALLOON_Balloon *bb;
if (!WITHIN(BALLOON_balloon_upto, 1, BALLOON_MAX_BALLOONS - 1))
{
//
// No balloons left.
//
return NULL;
}
ASSERT(WITHIN(type, 1, BALLOON_TYPE_NUMBER - 1));
bb = &BALLOON_balloon[BALLOON_balloon_upto];
bb->type = type;
bb->next = NULL;
bb->thing = thing;
bb->yaw = 0;
bb->pitch = 0;
//
// Where is this balloon attached to the thing?
//
BALLOON_get_attached_point(
thing,
&ax,
&ay,
&az);
//
// Initilise the points.
//
for (i = 0; i < BALLOON_POINTS_PER_BALLOON; i++)
{
bb->bp[i].x = ax;
bb->bp[i].y = ay;
bb->bp[i].z = az;
ay += BALLOON_POINT_DIST;
}
//
// Attach to the thing.
//
switch(p_thing->Class)
{
case CLASS_PERSON:
bb->next = p_thing->Genus.Person->Balloon;
p_thing->Genus.Person->Balloon = BALLOON_balloon_upto;
break;
default:
// ASSERT(0);
break;
}
return BALLOON_balloon_upto++;
}
void BALLOON_process()
{
SLONG i;
SLONG j;
SLONG ax;
SLONG ay;
SLONG az;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG ddist;
SLONG hyp;
SLONG other;
SLONG px;
SLONG py;
SLONG pz;
SLONG yaw;
SLONG pitch;
BALLOON_Balloon *bb;
BALLOON_Balloon *bbo;
BALLOON_Point *bp;
BALLOON_Point *bp1;
BALLOON_Point *bp2;
for (i = 1; i < BALLOON_balloon_upto; i++)
{
bb = &BALLOON_balloon[i];
if (bb->type == BALLOON_TYPE_UNUSED)
{
continue;
}
if (bb->thing)
{
#define BALLOON_RADIUS 0x30
#define BALLOON_BOUNCE 0x100
/*
//
// PEOPLE ONLY CARRY ONE BALLOON NOW.
//
//
// If this person is carrying more than one balloon- make sure that
// it bounces off all the others.
//
other = TO_THING(bb->thing)->Genus.Person->Balloon;
while(other)
{
ASSERT(WITHIN(other, 1, BALLOON_MAX_BALLOONS - 1));
bbo = &BALLOON_balloon[other];
if (other != i && other < i)
{
dx = bb->bp[BALLOON_POINTS_PER_BALLOON - 1].x - bbo->bp[BALLOON_POINTS_PER_BALLOON - 1].x;
dy = bb->bp[BALLOON_POINTS_PER_BALLOON - 1].y - bbo->bp[BALLOON_POINTS_PER_BALLOON - 1].y;
dz = bb->bp[BALLOON_POINTS_PER_BALLOON - 1].z - bbo->bp[BALLOON_POINTS_PER_BALLOON - 1].z;
dist = QDIST3(abs(dx),abs(dy),abs(dz));
if (dist < (BALLOON_RADIUS << 9))
{
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dx -= dx >> 1;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dy -= dy >> 1;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dz -= dz >> 1;
bbo->bp[BALLOON_POINTS_PER_BALLOON - 1].dx += dx >> 1;
bbo->bp[BALLOON_POINTS_PER_BALLOON - 1].dy += dy >> 1;
bbo->bp[BALLOON_POINTS_PER_BALLOON - 1].dz += dz >> 1;
}
}
other = bbo->next;
}
*/
//
// Point zero is attached to the thing.
//
BALLOON_get_attached_point(
bb->thing,
&ax,
&ay,
&az);
bb->bp[0].x = ax;
bb->bp[0].y = ay;
bb->bp[0].z = az;
for (j = 1; j < BALLOON_POINTS_PER_BALLOON; j++)
{
bp1 = &bb->bp[j - 1];
bp2 = &bb->bp[j - 0];
bp2->x += bp2->dx;
bp2->y += bp2->dy;
bp2->z += bp2->dz;
dx = bp2->x - bp1->x;
dy = bp2->y - bp1->y;
dz = bp2->z - bp1->z;
//
// Avoid overflows.
//
if (dx > 0x7000) {dx = 0x7000;}
if (dy > 0x7000) {dy = 0x7000;}
if (dz > 0x7000) {dz = 0x7000;}
if (dx < -0x7000) {dx = -0x7000;}
if (dy < -0x7000) {dy = -0x7000;}
if (dz < -0x7000) {dz = -0x7000;}
dist = QDIST3(abs(dx),abs(dy),abs(dz)) + 1;
if (dist > BALLOON_POINT_DIST)
{
ddist = dist - BALLOON_POINT_DIST;
dx = (dx * ddist) / dist;
dy = (dy * ddist) / dist;
dz = (dz * ddist) / dist;
bp2->x -= dx;
bp2->y -= dy;
bp2->z -= dz;
bp2->dx -= dx / 0x10;
bp2->dy -= dy / 0x10;
bp2->dz -= dz / 0x10;
}
bp2->dy += 0x40;
bp2->dx -= bp2->dx / 0x10;
bp2->dy -= bp2->dy / 0x10;
bp2->dz -= bp2->dz / 0x10;
}
//
// Stop the balloon going through walls.
//
bp = &bb->bp[BALLOON_POINTS_PER_BALLOON - 1];
px = bp->x >> 8;
py = bp->y >> 8;
pz = bp->z >> 8;
if (MAV_inside(px + BALLOON_RADIUS, py, pz)) {bp->dx -= BALLOON_BOUNCE;}
if (MAV_inside(px - BALLOON_RADIUS, py, pz)) {bp->dx += BALLOON_BOUNCE;}
if (MAV_inside(px, py, pz + BALLOON_RADIUS)) {bp->dz -= BALLOON_BOUNCE;}
if (MAV_inside(px, py, pz - BALLOON_RADIUS)) {bp->dz += BALLOON_BOUNCE;}
}
else
{
//
// Make the balloon drift away...
//
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dy += 0x40;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dx -= bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dx / 0x10;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dy -= bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dy / 0x10;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dz -= bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dz / 0x10;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].x += bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dx;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].y += bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dy;
bb->bp[BALLOON_POINTS_PER_BALLOON - 1].z += bb->bp[BALLOON_POINTS_PER_BALLOON - 1].dz;
if (bb->bp[BALLOON_POINTS_PER_BALLOON - 1].y > 0x100000)
{
//
// Kill the balloon- its too high up.
//
bb->type = BALLOON_TYPE_UNUSED;
}
else
{
//
// ...and pull the string with it.
//
for (j = BALLOON_POINTS_PER_BALLOON - 2; j >= 0; j--)
{
bp1 = &bb->bp[j + 1];
bp2 = &bb->bp[j + 0];
bp2->x += bp2->dx;
bp2->y += bp2->dy;
bp2->z += bp2->dz;
dx = bp2->x - bp1->x;
dy = bp2->y - bp1->y;
dz = bp2->z - bp1->z;
if (dx > 0x4000) {dx = 0x4000;}
if (dy > 0x4000) {dy = 0x4000;}
if (dz > 0x4000) {dz = 0x4000;}
if (dx < -0x4000) {dx = -0x4000;}
if (dy < -0x4000) {dy = -0x4000;}
if (dz < -0x4000) {dz = -0x4000;}
dist = QDIST3(abs(dx),abs(dy),abs(dz)) + 1;
if (dist > BALLOON_POINT_DIST)
{
ddist = dist - BALLOON_POINT_DIST;
dx = (dx * ddist) / dist;
dy = (dy * ddist) / dist;
dz = (dz * ddist) / dist;
bp2->x -= dx;
bp2->y -= dy;
bp2->z -= dz;
bp2->dx = bp1->dx;
bp2->dy = bp1->dy;
bp2->dz = bp1->dz;
}
bp2->dy -= 0x100;
bp2->dx -= bp2->dx / 0x10;
bp2->dy -= bp2->dy / 0x10;
bp2->dz -= bp2->dz / 0x10;
}
}
}
//
// Work out the yaw/pitch of the balloon.
//
dx = bb->bp[BALLOON_POINTS_PER_BALLOON - 1].x - bb->bp[BALLOON_POINTS_PER_BALLOON - 2].x;
dy = bb->bp[BALLOON_POINTS_PER_BALLOON - 1].y - bb->bp[BALLOON_POINTS_PER_BALLOON - 2].y;
dz = bb->bp[BALLOON_POINTS_PER_BALLOON - 1].z - bb->bp[BALLOON_POINTS_PER_BALLOON - 2].z;
hyp = QDIST2(abs(dx),abs(dz));
yaw = calc_angle(dx,dz) + 1024;
pitch = calc_angle(dy,hyp);
pitch = -pitch;
pitch += 512;
pitch &= 2047;
bb->yaw = yaw;
bb->pitch = pitch;
}
}
void BALLOON_release(UBYTE balloon)
{
ASSERT(WITHIN(balloon, 1, BALLOON_MAX_BALLOONS - 1));
BALLOON_Balloon *bb;
bb = &BALLOON_balloon[balloon];
ASSERT(bb->type);
//
// detach from the thing.
//
Thing *p_thing = TO_THING(bb->thing);
switch(p_thing->Class)
{
case CLASS_PERSON:
p_thing->Genus.Person->Balloon = NULL;
break;
default:
ASSERT(0);
break;
}
while(balloon)
{
ASSERT(WITHIN(balloon, 1, BALLOON_balloon_upto - 1));
bb = &BALLOON_balloon[balloon];
bb->thing = NULL;
balloon = bb->next;
}
}
void BALLOON_find_grab(UWORD thing)
{
SLONG i;
SLONG ax;
SLONG ay;
SLONG az;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
Thing *p_thing = TO_THING(thing);
BALLOON_Balloon *bb;
if (BALLOON_balloon_upto == 1)
{
//
// No balloons, so no point doing anything.
//
return;
}
//
// PEOPLE ONLY CARRY ONE BALLOON NOW.
//
if (p_thing->Genus.Person->Balloon)
{
return;
}
//
// Where would the balloon be attached to?
//
BALLOON_get_attached_point(
thing,
&ax,
&ay,
&az);
//
// Look for a released balloon near this position.
//
#define BALLOON_GRAB_DIST (0x80)
for (i = 1; i < BALLOON_balloon_upto; i++)
{
bb = &BALLOON_balloon[i];
if (bb->type == BALLOON_TYPE_UNUSED ||
bb->thing != NULL)
{
continue;
}
dx = abs(bb->bp[0].x - ax);
dy = abs(bb->bp[0].y - ay);
dz = abs(bb->bp[0].z - az);
dist = QDIST3(dx,dy,dz);
if (dist < 0x10000)
{
//
// Attach this balloon to the person.
//
bb->thing = thing;
bb->next = p_thing->Genus.Person->Balloon;
p_thing->Genus.Person->Balloon = i;
return;
}
}
}
#endif
#endif //#ifndef TARGET_DC