warzone2100/src/baseobject.cpp

218 lines
6.9 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2013 Warzone 2100 Project
Warzone 2100 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.
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib/framework/frame.h"
#include "lib/netplay/netplay.h"
#include "lib/sound/audio.h"
#include "baseobject.h"
#include "droid.h"
#include "projectile.h"
#include "structure.h"
#include "feature.h"
#include "intdisplay.h"
#include "map.h"
static inline uint16_t interpolateAngle(uint16_t v1, uint16_t v2, uint32_t t1, uint32_t t2, uint32_t t)
{
const int numer = t - t1, denom = t2 - t1;
return v1 + angleDelta(v2 - v1) * numer/denom;
}
static Position interpolatePos(Position p1, Position p2, uint32_t t1, uint32_t t2, uint32_t t)
{
const int numer = t - t1, denom = t2 - t1;
return p1 + (p2 - p1) * numer/denom;
}
Rotation interpolateRot(Rotation v1, Rotation v2, uint32_t t1, uint32_t t2, uint32_t t)
{
//return v1 + (v2 - v1) * (t - t1) / (t2 - t1);
return Rotation( interpolateAngle(v1.direction, v2.direction, t1, t2, t),
interpolateAngle(v1.pitch, v2.pitch, t1, t2, t),
interpolateAngle(v1.roll, v2.roll, t1, t2, t)
);
}
static Spacetime interpolateSpacetime(Spacetime st1, Spacetime st2, uint32_t t)
{
// Cyp says this should never happen, #3037 and #3238 say it does though.
ASSERT_OR_RETURN(st1, st1.time != st2.time, "Spacetime overlap!");
return Spacetime(interpolatePos(st1.pos, st2.pos, st1.time, st2.time, t), interpolateRot(st1.rot, st2.rot, st1.time, st2.time, t), t);
}
Spacetime interpolateObjectSpacetime(const SIMPLE_OBJECT *obj, uint32_t t)
{
switch (obj->type)
{
default:
return getSpacetime(obj);
case OBJ_DROID:
return interpolateSpacetime(castDroid(obj)->prevSpacetime, getSpacetime(obj), t);
case OBJ_PROJECTILE:
return interpolateSpacetime(castProjectile(obj)->prevSpacetime, getSpacetime(obj), t);
}
}
SIMPLE_OBJECT::SIMPLE_OBJECT(OBJECT_TYPE type, uint32_t id, unsigned player)
: type(type)
, id(id)
, pos(0, 0, 0)
, rot(0, 0, 0)
, player(player)
, born(gameTime)
, died(0)
, time(0)
{}
SIMPLE_OBJECT::~SIMPLE_OBJECT()
{
#ifdef DEBUG
const_cast<OBJECT_TYPE &>(type) = (OBJECT_TYPE)(type + 1000000000); // Hopefully this will trigger an assert if someone uses the freed object.
player += 100; // Hopefully this will trigger an assert and/or crash if someone uses the freed object.
#endif //DEBUG
}
BASE_OBJECT::BASE_OBJECT(OBJECT_TYPE type, uint32_t id, unsigned player)
: SIMPLE_OBJECT(type, id, player)
, selected(false)
, cluster(0)
, numWatchedTiles(0)
, lastEmission(0)
, lastHitWeapon(WSC_NUM_WEAPON_SUBCLASSES) // No such weapon.
, timeLastHit(UDWORD_MAX)
, body(0)
, periodicalDamageStart(0)
, periodicalDamage(0)
, flags(0)
, watchedTiles(NULL)
{
memset(visible, 0, sizeof(visible));
sDisplay.imd = NULL;
sDisplay.frameNumber = 0;
sDisplay.screenX = 0;
sDisplay.screenY = 0;
sDisplay.screenR = 0;
}
BASE_OBJECT::~BASE_OBJECT()
{
// Make sure to get rid of some final references in the sound code to this object first
audio_RemoveObj(this);
visRemoveVisibility(this);
free(watchedTiles);
#ifdef DEBUG
psNext = this; // Hopefully this will trigger an infinite loop if someone uses the freed object.
psNextFunc = this; // Hopefully this will trigger an infinite loop if someone uses the freed object.
#endif //DEBUG
}
void checkObject(const SIMPLE_OBJECT *psObject, const char *const location_description, const char *function, const int recurse)
{
if (recurse < 0)
return;
ASSERT(psObject != NULL, "NULL pointer");
switch (psObject->type)
{
case OBJ_DROID:
checkDroid((const DROID *)psObject, location_description, function, recurse - 1);
break;
case OBJ_STRUCTURE:
checkStructure((const STRUCTURE *)psObject, location_description, function, recurse - 1);
break;
case OBJ_PROJECTILE:
checkProjectile((const PROJECTILE *)psObject, location_description, function, recurse - 1);
break;
case OBJ_FEATURE:
case OBJ_TARGET:
break;
default:
ASSERT_HELPER(!"invalid object type", location_description, function, "CHECK_OBJECT: Invalid object type (type num %u)", (unsigned int)psObject->type);
break;
}
}
void _syncDebugObject(const char *function, SIMPLE_OBJECT const *psObject, char ch)
{
switch (psObject->type)
{
case OBJ_DROID: _syncDebugDroid (function, (const DROID *) psObject, ch); break;
case OBJ_STRUCTURE: _syncDebugStructure (function, (const STRUCTURE *) psObject, ch); break;
case OBJ_FEATURE: _syncDebugFeature (function, (const FEATURE *) psObject, ch); break;
case OBJ_PROJECTILE: _syncDebugProjectile(function, (const PROJECTILE *)psObject, ch); break;
default: _syncDebug (function, "%c unidentified_object%d = p%d;objectType%d", ch, psObject->id, psObject->player, psObject->type);
ASSERT_HELPER(!"invalid object type", "_syncDebugObject", function, "syncDebug: Invalid object type (type num %u)", (unsigned int)psObject->type);
break;
}
}
Vector2i getStatsSize(BASE_STATS const *pType, uint16_t direction)
{
if (StatIsStructure(pType))
{
return getStructureStatsSize(static_cast<STRUCTURE_STATS const *>(pType), direction);
}
else if(StatIsFeature(pType))
{
return getFeatureStatsSize(static_cast<FEATURE_STATS const *>(pType));
}
return Vector2i(1, 1);
}
StructureBounds getStructureBounds(BASE_OBJECT const *object)
{
STRUCTURE const *psStructure = castStructure(object);
FEATURE const *psFeature = castFeature(object);
if (psStructure != NULL)
{
return getStructureBounds(psStructure);
}
else if (psFeature != NULL)
{
return getStructureBounds(psFeature);
}
return StructureBounds(Vector2i(32767, 32767), Vector2i(-65535, -65535)); // Default to an invalid area.
}
StructureBounds getStructureBounds(BASE_STATS const *stats, Vector2i pos, uint16_t direction)
{
if (StatIsStructure(stats))
{
return getStructureBounds(static_cast<STRUCTURE_STATS const *>(stats), pos, direction);
}
else if (StatIsFeature(stats))
{
return getStructureBounds(static_cast<FEATURE_STATS const *>(stats), pos);
}
return StructureBounds(map_coord(pos), Vector2i(1, 1)); // Default to a 1×1 tile.
}