2007-01-15 12:09:25 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
2013-01-16 12:34:57 -08:00
Copyright ( C ) 2005 - 2013 Warzone 2100 Project
2007-01-15 12:09:25 -08:00
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
*/
2008-02-16 05:05:34 -08:00
/**
2008-04-24 10:06:25 -07:00
* @ file display3d . c
2008-11-10 14:50:08 -08:00
* Draws the 3 D view .
* Originally by Alex McLean & Jeremy Sallis , Pumpkin Studios , EIDOS INTERACTIVE
*/
2010-03-10 04:31:27 -08:00
2008-03-16 05:39:08 -07:00
# include "lib/framework/frame.h"
2010-09-19 07:05:19 -07:00
# include "lib/framework/opengl.h"
2009-02-10 09:23:09 -08:00
# include "lib/framework/math_ext.h"
# include "lib/framework/stdio_ext.h"
2007-12-01 08:31:09 -08:00
2007-06-28 10:47:08 -07:00
/* Includes direct access to render library */
2010-12-31 13:37:14 -08:00
# include "lib/ivis_opengl/pieblitfunc.h"
# include "lib/ivis_opengl/piedef.h"
# include "lib/ivis_opengl/tex.h"
# include "lib/ivis_opengl/piestate.h"
# include "lib/ivis_opengl/piepalette.h"
2006-05-27 09:37:17 -07:00
# include "lib/ivis_opengl/piematrix.h"
2010-12-31 13:37:14 -08:00
# include "lib/ivis_opengl/piemode.h"
2009-02-10 09:23:18 -08:00
# include "lib/framework/fixedpoint.h"
2010-12-31 13:37:14 -08:00
# include "lib/ivis_opengl/piefunc.h"
2013-10-05 03:06:27 -07:00
# include "lib/ivis_opengl/screen.h"
2008-03-16 05:39:08 -07:00
# include "lib/gamelib/gtime.h"
# include "lib/gamelib/animobj.h"
# include "lib/script/script.h"
# include "lib/sound/audio.h"
# include "lib/sound/audio_id.h"
2010-03-14 05:27:05 -07:00
# include "lib/netplay/netplay.h"
2007-06-28 10:47:08 -07:00
# include "loop.h"
# include "atmos.h"
# include "levels.h"
# include "map.h"
# include "move.h"
# include "visibility.h"
# include "geometry.h"
# include "messagedef.h"
# include "miscimd.h"
# include "effects.h"
# include "edit3d.h"
# include "feature.h"
# include "hci.h"
# include "display.h"
# include "intdisplay.h"
# include "radar.h"
# include "display3d.h"
# include "lighting.h"
# include "console.h"
# include "projectile.h"
# include "bucket3d.h"
# include "intelmap.h"
# include "mapdisplay.h"
# include "message.h"
# include "component.h"
# include "warcam.h"
# include "scripttabs.h"
# include "scriptextern.h"
# include "scriptcb.h"
# include "keymap.h"
# include "drive.h"
# include "gateway.h"
# include "transporter.h"
# include "warzoneconfig.h"
# include "action.h"
# include "keybind.h"
# include "combat.h"
# include "order.h"
# include "scores.h"
# include "multiplay.h"
# include "advvis.h"
# include "texture.h"
# include "anim_id.h"
# include "cmddroid.h"
2009-02-21 15:35:21 -08:00
# include "terrain.h"
2007-06-28 10:47:08 -07:00
2006-08-08 11:48:06 -07:00
/******************** Prototypes ********************/
2007-03-16 15:45:30 -07:00
2013-10-05 04:37:53 -07:00
static void displayDelivPoints ( ) ;
static void displayProximityMsgs ( ) ;
static void displayDynamicObjects ( ) ;
static void displayStaticObjects ( ) ;
static void displayFeatures ( ) ;
2007-03-16 15:45:30 -07:00
static UDWORD getTargettingGfx ( void ) ;
static void drawDroidGroupNumber ( DROID * psDroid ) ;
2007-06-19 16:18:44 -07:00
static void trackHeight ( float desiredHeight ) ;
2007-03-30 10:38:35 -07:00
static void renderSurroundings ( void ) ;
2007-03-16 15:45:30 -07:00
static void locateMouse ( void ) ;
2011-03-12 17:32:15 -08:00
static bool renderWallSection ( STRUCTURE * psStructure ) ;
2007-03-16 15:45:30 -07:00
static void drawDragBox ( void ) ;
static void calcFlagPosScreenCoords ( SDWORD * pX , SDWORD * pY , SDWORD * pR ) ;
2008-01-27 11:31:58 -08:00
static void drawTiles ( iView * player ) ;
2007-03-16 15:45:30 -07:00
static void display3DProjectiles ( void ) ;
static void drawDroidSelections ( void ) ;
static void drawStructureSelections ( void ) ;
2011-03-12 17:32:15 -08:00
static void displayAnimation ( ANIM_OBJECT * psAnimObj , bool bHoldOnFirstFrame ) ;
2009-03-11 15:55:41 -07:00
static void displayBlueprints ( void ) ;
2007-03-16 15:45:30 -07:00
static void processSensorTarget ( void ) ;
static void processDestinationTarget ( void ) ;
2011-03-12 17:32:15 -08:00
static bool eitherSelected ( DROID * psDroid ) ;
2007-12-01 12:24:10 -08:00
static void structureEffects ( void ) ;
2007-03-16 15:45:30 -07:00
static void showDroidSensorRanges ( void ) ;
static void showSensorRange2 ( BASE_OBJECT * psObj ) ;
static void drawRangeAtPos ( SDWORD centerX , SDWORD centerY , SDWORD radius ) ;
static void addConstructionLine ( DROID * psDroid , STRUCTURE * psStructure ) ;
static void doConstructionLines ( void ) ;
2007-03-17 08:30:34 -07:00
static void drawDroidCmndNo ( DROID * psDroid ) ;
static void drawDroidRank ( DROID * psDroid ) ;
static void drawDroidSensorLock ( DROID * psDroid ) ;
2007-12-07 13:49:28 -08:00
static void calcAverageTerrainHeight ( iView * player ) ;
2011-03-12 17:32:15 -08:00
bool doWeDrawProximitys ( void ) ;
2010-01-28 06:50:18 -08:00
static PIELIGHT getBlueprintColour ( STRUCT_STATES state ) ;
2007-03-17 08:30:34 -07:00
2013-02-26 01:45:50 -08:00
static void NetworkDisplayPlainForm ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void NetworkDisplayImage ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
2012-03-17 15:12:07 -07:00
extern bool writeGameInfo ( const char * pFileName ) ; // Used to help debug issues when we have fatal errors & crash handler testing.
2007-03-17 08:30:34 -07:00
/******************** Variables ********************/
// Should be cleaned up properly and be put in structures.
2007-03-16 15:45:30 -07:00
2011-12-28 12:34:29 -08:00
// Initialised at start of drawTiles().
// In model coordinates where x is east, y is up and z is north, rather than world coordinates where x is east, y is south and z is up.
// To get the real camera position, still need to add Vector3i(player.p.x, 0, player.p.z).
static Vector3i actualCameraPosition ;
2011-03-12 17:32:15 -08:00
bool bRender3DOnly ;
static bool bRangeDisplay = false ;
2007-11-04 07:52:34 -08:00
static SDWORD rangeCenterX , rangeCenterY , rangeRadius ;
2011-03-12 17:32:15 -08:00
static bool bDrawProximitys = true ;
bool godMode ;
bool showGateways = false ;
bool showPath = false ;
2006-08-08 11:48:06 -07:00
2013-02-17 02:17:54 -08:00
// Skybox data
2012-11-15 12:30:59 -08:00
static float wind = 0.0f ;
static float windSpeed = 0.0f ;
static float skybox_scale = 10000.0f ;
2008-01-12 07:10:02 -08:00
2008-11-10 14:50:08 -08:00
/// When to display HP bars
2007-12-09 06:25:54 -08:00
UWORD barMode ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// Have we made a selection by clicking the mouse? - used for dragging etc
2011-03-12 17:32:15 -08:00
bool selectAttempt = false ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// Vectors that hold the player and camera directions and positions
2007-10-23 08:07:44 -07:00
iView player ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// How far away are we from the terrain
2012-12-09 12:16:51 -08:00
static float distance ;
2006-08-08 11:48:06 -07:00
2013-03-30 19:09:19 -07:00
/// Stores the screen coordinates of the transformed terrain tiles
static Vector3i tileScreenInfo [ VISIBLE_YTILES + 1 ] [ VISIBLE_XTILES + 1 ] ;
2008-11-10 14:50:08 -08:00
/// Records the present X and Y values for the current mouse tile (in tiles)
2007-05-29 19:06:46 -07:00
SDWORD mouseTileX , mouseTileY ;
2011-03-03 14:15:40 -08:00
Vector2i mousePos ( 0 , 0 ) ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// Do we want the radar to be rendered
2012-02-02 15:48:38 -08:00
bool radarOnScreen = true ;
2012-01-14 10:39:54 -08:00
bool radarPermitted = true ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// Show unit/building gun/sensor range
2007-12-24 06:48:44 -08:00
bool rangeOnScreen = false ; // For now, most likely will change later! -Q 5-10-05 A very nice effect - Per
2006-08-08 11:48:06 -07:00
2009-08-20 10:20:09 -07:00
/// Tactical UI: show/hide target origin icon
bool tuiTargetOrigin = false ;
2011-04-30 09:41:50 -07:00
/// Temporary values for the terrain render - center of grid to be rendered
2007-12-08 09:50:38 -08:00
static int playerXTile , playerZTile ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// The cached value of frameGetFrameNumber()
2008-04-13 02:41:48 -07:00
static UDWORD currentGameFrame ;
2008-11-10 14:50:08 -08:00
/// The box used for multiple selection - present screen coordinates
2007-05-21 11:57:11 -07:00
static QUAD dragQuad ;
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/** Number of tiles visible
* \ todo This should become dynamic ! ( A function of resolution , angle and zoom maybe . )
*/
2012-09-16 06:28:34 -07:00
const Vector2i visibleTiles ( VISIBLE_XTILES , VISIBLE_YTILES ) ;
2007-07-02 13:37:01 -07:00
2008-11-10 14:50:08 -08:00
/// The tile we use for drawing the bottom of a body of water
2007-11-07 14:54:19 -08:00
static unsigned int underwaterTile = WATER_TILE ;
2008-11-10 14:50:08 -08:00
/** The tile we use for drawing rubble
* \ note Unused .
*/
2007-11-07 14:54:19 -08:00
static unsigned int rubbleTile = BLOCKING_RUBBLE_TILE ;
2007-06-28 10:47:08 -07:00
2008-11-10 14:50:08 -08:00
/** Show how many frames we are rendering per second
* default OFF , turn ON via console command ' showfps '
*/
bool showFPS = false ; //
/** Show how many samples we are rendering per second
* default OFF , turn ON via console command ' showsamples '
*/
bool showSAMPLES = false ;
2009-04-26 14:35:32 -07:00
/** Show the current selected units order / action
* default OFF , turn ON via console command ' showorders '
*/
2010-07-18 03:31:36 -07:00
bool showORDERS = false ;
2010-03-19 21:07:55 -07:00
/** Show the current level name on the screen, toggle via the 'showlevelname'
* console command
*/
bool showLevelName = true ;
2009-02-21 14:09:58 -08:00
/** When we have a connection issue, we will flash a message on screen
*/
2013-12-01 10:10:38 -08:00
static const char * errorWaiting = NULL ;
2010-12-05 16:51:10 -08:00
static uint32_t lastErrorTime = 0 ;
2010-03-14 05:27:05 -07:00
2009-02-21 14:09:58 -08:00
# define NETWORK_FORM_ID 0xFAAA
# define NETWORK_BUT_ID 0xFAAB
2009-06-04 10:52:05 -07:00
/** When enabled, this causes a segfault in the game, to test out the crash handler */
bool CauseCrash = false ;
2009-02-21 14:09:58 -08:00
2009-04-26 14:35:32 -07:00
/** tells us in realtime, what droid is doing (order / action)
*/
char DROIDDOING [ 512 ] ;
2008-11-10 14:50:08 -08:00
/// Geometric offset which will be passed to pie_SetGeometricOffset
2010-10-13 13:47:04 -07:00
static const int geoOffset = 192 ;
2008-11-10 14:50:08 -08:00
/// The average terrain height for the center of the area the camera is looking at
2007-07-30 13:20:06 -07:00
static int averageCentreTerrainHeight ;
2007-06-28 10:47:08 -07:00
2008-11-10 14:50:08 -08:00
/** The time at which a sensor target was last asssigned
* Used to draw a visual effect .
*/
2006-08-08 11:48:06 -07:00
static UDWORD lastTargetAssignation = 0 ;
2008-11-10 14:50:08 -08:00
/** The time at which an order concerning a destination was last given
* Used to draw a visual effect .
*/
2006-08-08 11:48:06 -07:00
static UDWORD lastDestAssignation = 0 ;
2011-03-12 17:32:15 -08:00
static bool bSensorTargetting = false ;
static bool bDestTargetting = false ;
2006-08-08 11:48:06 -07:00
static BASE_OBJECT * psSensorObj = NULL ;
static UDWORD destTargetX , destTargetY ;
static UDWORD destTileX = 0 , destTileY = 0 ;
2007-06-28 10:47:08 -07:00
2011-11-17 03:27:01 -08:00
struct Blueprint
{
2012-01-02 11:35:21 -08:00
Blueprint ( STRUCTURE_STATS const * stats , Vector2i pos , uint16_t dir , uint32_t index , STRUCT_STATES state )
2011-11-17 03:27:01 -08:00
: stats ( stats )
, pos ( pos )
, dir ( dir )
2012-01-02 11:35:21 -08:00
, index ( index )
2011-11-17 03:27:01 -08:00
, state ( state )
{ }
int compare ( Blueprint const & b ) const
{
if ( stats - > ref ! = b . stats - > ref ) return stats - > ref < b . stats - > ref ? - 1 : 1 ;
if ( pos . x ! = b . pos . x ) return pos . x < b . pos . x ? - 1 : 1 ;
if ( pos . y ! = b . pos . y ) return pos . y < b . pos . y ? - 1 : 1 ;
if ( dir ! = b . dir ) return dir < b . dir ? - 1 : 1 ;
2012-01-02 11:35:21 -08:00
if ( index ! = b . index ) return index < b . index ? - 1 : 1 ;
2011-11-17 03:27:01 -08:00
if ( state ! = b . state ) return state < b . state ? - 1 : 1 ;
return 0 ;
}
bool operator < ( Blueprint const & b ) const { return compare ( b ) < 0 ; }
bool operator = = ( Blueprint const & b ) const { return compare ( b ) = = 0 ; }
STRUCTURE * buildBlueprint ( ) const ///< Must delete after use.
{
2012-01-02 11:35:21 -08:00
return : : buildBlueprint ( stats , pos , dir , index , state ) ;
2011-11-17 03:27:01 -08:00
}
void renderBlueprint ( ) const
{
if ( clipXY ( pos . x , pos . y ) )
{
STRUCTURE * psStruct = buildBlueprint ( ) ;
renderStructure ( psStruct ) ;
delete psStruct ;
}
}
2011-11-18 10:27:46 -08:00
STRUCTURE_STATS const * stats ;
2011-11-17 03:27:01 -08:00
Vector2i pos ;
uint16_t dir ;
2012-01-02 11:35:21 -08:00
uint32_t index ;
2011-11-17 03:27:01 -08:00
STRUCT_STATES state ;
} ;
static std : : vector < Blueprint > blueprints ;
2010-12-20 18:24:32 -08:00
2007-06-28 10:47:08 -07:00
# define TARGET_TO_SENSOR_TIME ((4*(GAME_TICKS_PER_SEC)) / 5)
# define DEST_TARGET_TIME (GAME_TICKS_PER_SEC / 4)
2008-11-10 14:50:08 -08:00
/// The distance the selection box will pulse
2007-12-01 12:24:10 -08:00
# define BOX_PULSE_SIZE 10
2007-06-28 10:47:08 -07:00
2009-03-11 15:55:41 -07:00
/// the opacity at which building blueprints will be drawn
static const int BLUEPRINT_OPACITY = 120 ;
2006-08-08 11:48:06 -07:00
/******************** Functions ********************/
2007-06-28 10:47:08 -07:00
2013-02-24 02:36:14 -08:00
static void setScreenDisp ( SCREEN_DISP_DATA * sDisplay )
{
Vector3i zero ( 0 , 0 , 0 ) ;
Vector2i s ( 0 , 0 ) ;
pie_RotateProject ( & zero , & s ) ;
sDisplay - > screenX = s . x ;
sDisplay - > screenY = s . y ;
}
2012-11-15 12:30:59 -08:00
void setSkyBox ( const char * page , float mywind , float myscale )
{
windSpeed = mywind ;
wind = 0.0f ;
skybox_scale = myscale ;
2013-02-17 02:17:54 -08:00
pie_Skybox_Texture ( page ) ;
2012-11-15 12:30:59 -08:00
}
2011-12-28 12:34:29 -08:00
static inline void rotateSomething ( int & x , int & y , uint16_t angle )
{
int64_t cra = iCos ( angle ) , sra = iSin ( angle ) ;
int newX = ( x * cra - y * sra ) > > 16 ;
int newY = ( x * sra + y * cra ) > > 16 ;
x = newX ;
y = newY ;
}
2011-11-17 04:14:56 -08:00
static Blueprint getTileBlueprint ( int mapX , int mapY )
2010-12-20 18:24:32 -08:00
{
2010-12-21 12:51:29 -08:00
Vector2i mouse ( world_coord ( mapX ) + TILE_UNITS / 2 , world_coord ( mapY ) + TILE_UNITS / 2 ) ;
2010-12-20 18:24:32 -08:00
2011-11-17 03:27:01 -08:00
for ( std : : vector < Blueprint > : : const_iterator blueprint = blueprints . begin ( ) ; blueprint ! = blueprints . end ( ) ; + + blueprint )
2010-12-20 18:24:32 -08:00
{
2011-11-17 03:27:01 -08:00
Vector2i size = getStructureStatsSize ( blueprint - > stats , blueprint - > dir ) * TILE_UNITS ;
2011-11-17 04:14:56 -08:00
if ( abs ( mouse . x - blueprint - > pos . x ) < size . x / 2 & & abs ( mouse . y - blueprint - > pos . y ) < size . y / 2 )
2010-12-20 18:24:32 -08:00
{
2011-11-17 04:14:56 -08:00
return * blueprint ;
2010-12-20 18:24:32 -08:00
}
}
2012-01-02 11:35:21 -08:00
return Blueprint ( NULL , Vector2i ( ) , 0 , 0 , SS_BEING_BUILT ) ;
2011-11-17 04:14:56 -08:00
}
STRUCTURE * getTileBlueprintStructure ( int mapX , int mapY )
{
static STRUCTURE * psStruct = NULL ;
Blueprint blueprint = getTileBlueprint ( mapX , mapY ) ;
if ( blueprint . state = = SS_BLUEPRINT_PLANNED )
{
delete psStruct ; // Delete previously returned structure, if any.
psStruct = blueprint . buildBlueprint ( ) ;
return psStruct ; // This blueprint was clicked on.
}
2010-12-20 18:24:32 -08:00
return NULL ;
}
2011-11-18 10:27:46 -08:00
STRUCTURE_STATS const * getTileBlueprintStats ( int mapX , int mapY )
2011-11-17 04:14:56 -08:00
{
return getTileBlueprint ( mapX , mapY ) . stats ;
}
2011-12-24 15:37:16 -08:00
bool anyBlueprintTooClose ( STRUCTURE_STATS const * stats , Vector2i pos , uint16_t dir )
{
for ( std : : vector < Blueprint > : : const_iterator blueprint = blueprints . begin ( ) ; blueprint ! = blueprints . end ( ) ; + + blueprint )
{
if ( ( blueprint - > state = = SS_BLUEPRINT_PLANNED | | blueprint - > state = = SS_BLUEPRINT_PLANNED_BY_ALLY )
& & isBlueprintTooClose ( stats , pos , dir , blueprint - > stats , blueprint - > pos , blueprint - > dir ) )
{
return true ;
}
}
return false ;
}
2012-03-11 10:33:12 -07:00
void clearBlueprints ( )
{
blueprints . clear ( ) ;
}
2010-01-28 06:50:18 -08:00
static PIELIGHT structureBrightness ( STRUCTURE * psStructure )
{
PIELIGHT buildingBrightness ;
if ( structureIsBlueprint ( psStructure ) )
{
buildingBrightness = getBlueprintColour ( psStructure - > status ) ;
}
else
{
2010-11-16 05:48:06 -08:00
buildingBrightness = pal_SetBrightness ( 200 - 100 / 65536.f * getStructureDamage ( psStructure ) ) ;
2010-01-28 06:50:18 -08:00
/* If it's selected, then it's brighter */
if ( psStructure - > selected )
{
SDWORD brightVar ;
if ( ! gamePaused ( ) )
{
2010-02-06 09:07:52 -08:00
brightVar = getModularScaledGraphicsTime ( 990 , 110 ) ;
2010-01-28 06:50:18 -08:00
if ( brightVar > 55 )
{
brightVar = 110 - brightVar ;
}
}
else
{
brightVar = 55 ;
}
buildingBrightness = pal_SetBrightness ( 200 + brightVar ) ;
}
2012-11-16 05:16:59 -08:00
if ( ! getRevealStatus ( ) )
2010-01-28 06:50:18 -08:00
{
buildingBrightness = pal_SetBrightness ( avGetObjLightLevel ( ( BASE_OBJECT * ) psStructure , buildingBrightness . byte . r ) ) ;
}
if ( ! hasSensorOnTile ( mapTile ( map_coord ( psStructure - > pos . x ) , map_coord ( psStructure - > pos . y ) ) , selectedPlayer ) )
{
buildingBrightness . byte . r / = 2 ;
buildingBrightness . byte . g / = 2 ;
buildingBrightness . byte . b / = 2 ;
}
}
return buildingBrightness ;
}
2008-11-10 14:50:08 -08:00
/// Display the multiplayer chat box
2007-09-25 12:13:37 -07:00
static void displayMultiChat ( void )
2007-06-28 10:47:08 -07:00
{
2012-02-03 01:14:43 -08:00
iV_SetFont ( font_regular ) ;
2007-09-25 12:13:37 -07:00
UDWORD pixelLength ;
UDWORD pixelHeight ;
2007-06-28 10:47:08 -07:00
2007-09-25 12:13:37 -07:00
pixelLength = iV_GetTextWidth ( sTextToSend ) ;
pixelHeight = iV_GetTextLineSize ( ) ;
2007-06-28 10:47:08 -07:00
2012-02-03 01:14:43 -08:00
if ( ( realTime % 500 ) < 250 )
2007-09-25 12:13:37 -07:00
{
2007-11-26 14:59:21 -08:00
// implement blinking cursor in multiplayer chat
pie_BoxFill ( RET_X + pixelLength + 3 , 474 + E_H - ( pixelHeight / 4 ) , RET_X + pixelLength + 10 , 473 + E_H , WZCOL_CURSOR ) ;
2007-09-25 12:13:37 -07:00
}
2007-06-28 10:47:08 -07:00
2007-09-25 12:13:37 -07:00
/* FIXME: GET RID OF THE MAGIC NUMBERS BELOW */
iV_TransBoxFill ( RET_X + 1 , 474 + E_H - pixelHeight , RET_X + 1 + pixelLength + 2 , 473 + E_H ) ;
2007-06-28 10:47:08 -07:00
2007-09-25 12:13:37 -07:00
iV_DrawText ( sTextToSend , RET_X + 3 , 469 + E_H ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Show all droid movement parts by displaying an explosion at every step
2008-03-20 06:40:34 -07:00
static void showDroidPaths ( void )
{
DROID * psDroid ;
2011-02-27 03:10:40 -08:00
if ( ( graphicsTime / 250 % 2 ) ! = 0 )
2008-03-20 06:40:34 -07:00
{
return ;
}
for ( psDroid = apsDroidLists [ selectedPlayer ] ; psDroid ; psDroid = psDroid - > psNext )
{
2010-02-28 14:35:15 -08:00
if ( psDroid - > selected & & psDroid - > sMove . Status ! = MOVEINACTIVE )
2008-03-20 06:40:34 -07:00
{
int len = psDroid - > sMove . numPoints ;
2011-02-27 03:10:40 -08:00
int i = std : : max ( psDroid - > sMove . pathIndex - 1 , 0 ) ;
2008-03-23 13:04:37 -07:00
for ( ; i < len ; i + + )
2008-03-20 06:40:34 -07:00
{
Vector3i pos ;
2010-03-03 11:23:14 -08:00
ASSERT ( worldOnMap ( psDroid - > sMove . asPath [ i ] . x , psDroid - > sMove . asPath [ i ] . y ) , " Path off map! " ) ;
pos . x = psDroid - > sMove . asPath [ i ] . x ;
pos . z = psDroid - > sMove . asPath [ i ] . y ;
2008-03-20 06:40:34 -07:00
pos . y = map_Height ( pos . x , pos . z ) + 16 ;
effectGiveAuxVar ( 80 ) ;
2008-03-24 09:51:17 -07:00
addEffect ( & pos , EFFECT_EXPLOSION , EXPLOSION_TYPE_LASER , false , NULL , 0 ) ;
2008-03-20 06:40:34 -07:00
}
}
}
}
2009-02-21 14:09:58 -08:00
/// Renders the Network Issue form
2013-02-26 01:45:50 -08:00
static void NetworkDisplayPlainForm ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2009-02-21 14:09:58 -08:00
{
2013-03-12 01:32:55 -07:00
int x0 = xOffset + psWidget - > x ( ) ;
int y0 = yOffset + psWidget - > y ( ) ;
int x1 = x0 + psWidget - > width ( ) ;
int y1 = y0 + psWidget - > height ( ) ;
2009-02-21 14:09:58 -08:00
2010-07-18 03:31:36 -07:00
// Don't draw anything, a rectangle behind the icon just looks strange, if you notice it.
//RenderWindowFrame(FRAME_NORMAL, x0, y0, x1 - x0, y1 - y0);
( void ) x0 ;
( void ) y0 ;
( void ) x1 ;
( void ) y1 ;
2009-02-21 14:09:58 -08:00
}
/// Displays an image for the Network Issue button
2013-02-26 01:45:50 -08:00
static void NetworkDisplayImage ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2009-02-21 14:09:58 -08:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) ;
2009-02-21 14:09:58 -08:00
UWORD ImageID ;
2010-12-05 08:25:43 -08:00
CONNECTION_STATUS status = ( CONNECTION_STATUS ) UNPACKDWORD_TRI_A ( psWidget - > UserData ) ;
2009-02-21 14:09:58 -08:00
ASSERT ( psWidget - > type = = WIDG_BUTTON , " Not a button " ) ;
// cheap way to do a button flash
2012-10-02 07:54:33 -07:00
if ( ( realTime / 250 ) % 2 = = 0 )
2009-02-21 14:09:58 -08:00
{
ImageID = UNPACKDWORD_TRI_B ( psWidget - > UserData ) ;
}
else
{
ImageID = UNPACKDWORD_TRI_C ( psWidget - > UserData ) ;
}
2010-08-01 04:06:50 -07:00
if ( NETcheckPlayerConnectionStatus ( status , NET_ALL_PLAYERS ) )
{
unsigned width , height ;
unsigned n , c = 0 ;
char players [ MAX_PLAYERS + 1 ] ;
2011-01-03 05:48:41 -08:00
PlayerMask playerMaskMapped = 0 ;
2010-08-01 04:06:50 -07:00
for ( n = 0 ; n < MAX_PLAYERS ; + + n )
{
if ( NETcheckPlayerConnectionStatus ( status , n ) )
{
playerMaskMapped | = 1 < < NetPlay . players [ n ] . position ;
}
}
for ( n = 0 ; n < MAX_PLAYERS ; + + n )
{
if ( ( playerMaskMapped & 1 < < n ) ! = 0 )
{
2011-01-03 05:48:41 -08:00
STATIC_ASSERT ( MAX_PLAYERS < = 32 ) ; // If increasing MAX_PLAYERS, check all the 1<<playerNumber shifts, since the 1 is usually a 32-bit type.
players [ c + + ] = " 0123456789ABCDEFGHIJKLMNOPQRSTUV " [ n ] ;
2010-08-01 04:06:50 -07:00
}
}
players [ c ] = ' \0 ' ;
2013-01-18 18:13:58 -08:00
iV_SetFont ( font_regular ) ;
2010-08-01 04:06:50 -07:00
width = iV_GetTextWidth ( players ) + 10 ;
height = iV_GetTextHeight ( players ) + 10 ;
2013-01-18 18:13:58 -08:00
iV_SetTextColour ( WZCOL_TEXT_BRIGHT ) ;
2010-08-01 04:06:50 -07:00
iV_DrawText ( players , x - width , y + height ) ;
}
2009-02-21 14:09:58 -08:00
iV_DrawImage ( IntImages , ImageID , x , y ) ;
}
2008-03-20 06:40:34 -07:00
2010-08-01 04:06:50 -07:00
static void setupConnectionStatusForm ( void )
2010-03-14 05:27:05 -07:00
{
2010-08-01 04:06:50 -07:00
static unsigned prevStatusMask = 0 ;
2010-03-14 05:27:05 -07:00
2010-07-18 03:31:36 -07:00
const int separation = 3 ;
2010-08-01 04:06:50 -07:00
unsigned statusMask = 0 ;
unsigned total = 0 ;
2010-07-18 03:31:36 -07:00
unsigned i ;
2010-08-01 04:06:50 -07:00
for ( i = 0 ; i < CONNECTIONSTATUS_NORMAL ; + + i )
{
if ( NETcheckPlayerConnectionStatus ( ( CONNECTION_STATUS ) i , NET_ALL_PLAYERS ) )
{
statusMask | = 1 < < i ;
+ + total ;
}
}
2010-07-18 03:31:36 -07:00
2010-08-01 04:06:50 -07:00
if ( prevStatusMask ! = 0 & & statusMask ! = prevStatusMask )
2010-03-14 05:27:05 -07:00
{
2010-07-18 03:31:36 -07:00
// Remove the icons.
2010-08-01 04:06:50 -07:00
for ( i = 0 ; i < CONNECTIONSTATUS_NORMAL ; + + i )
2010-07-18 03:31:36 -07:00
{
2010-08-01 04:06:50 -07:00
if ( ( statusMask & 1 < < i ) ! = 0 )
2010-07-18 03:31:36 -07:00
{
2010-08-01 04:06:50 -07:00
widgDelete ( psWScreen , NETWORK_BUT_ID + i ) ; // kill button
2010-07-18 03:31:36 -07:00
}
}
2010-03-14 05:27:05 -07:00
widgDelete ( psWScreen , NETWORK_FORM_ID ) ; // kill form
2010-08-01 04:06:50 -07:00
prevStatusMask = 0 ;
2010-03-14 05:27:05 -07:00
}
2010-08-01 04:06:50 -07:00
if ( prevStatusMask = = 0 & & statusMask ! = 0 )
2010-03-14 05:27:05 -07:00
{
2010-07-18 03:31:36 -07:00
unsigned n = 0 ;
2010-03-14 05:27:05 -07:00
// Create the basic form
2010-12-22 06:02:14 -08:00
W_FORMINIT sFormInit ;
2010-03-14 05:27:05 -07:00
sFormInit . formID = 0 ;
sFormInit . id = NETWORK_FORM_ID ;
sFormInit . style = WFORM_PLAIN ;
sFormInit . x = ( int ) ( pie_GetVideoBufferWidth ( ) - 52 ) ;
sFormInit . y = 80 ;
sFormInit . width = 36 ;
2010-07-18 03:31:36 -07:00
sFormInit . height = ( 24 + separation ) * total - separation ;
sFormInit . pDisplay = NetworkDisplayPlainForm ; // NetworkDisplayPlainForm used to do something, but it looks ugly.
2010-03-14 05:27:05 -07:00
if ( ! widgAddForm ( psWScreen , & sFormInit ) )
{
//return false;
}
/* Now add the buttons */
2010-08-01 04:06:50 -07:00
for ( i = 0 ; i < CONNECTIONSTATUS_NORMAL ; + + i )
2010-03-14 05:27:05 -07:00
{
2010-08-01 04:06:50 -07:00
if ( ( statusMask & 1 < < i ) = = 0 )
2010-07-18 03:31:36 -07:00
{
continue ;
}
2010-03-14 05:27:05 -07:00
2010-07-18 03:31:36 -07:00
//set up default button data
2010-12-22 06:02:14 -08:00
W_BUTINIT sButInit ;
2010-07-18 03:31:36 -07:00
sButInit . formID = NETWORK_FORM_ID ;
sButInit . id = NETWORK_BUT_ID + i ;
sButInit . width = 36 ;
sButInit . height = 24 ;
//add button
sButInit . style = WBUT_PLAIN ;
sButInit . x = 0 ;
sButInit . y = ( 24 + separation ) * n ;
sButInit . pDisplay = NetworkDisplayImage ;
// Note we would set the image to be different based on which issue it is.
2010-08-01 04:06:50 -07:00
switch ( i )
2010-07-18 03:31:36 -07:00
{
default :
ASSERT ( false , " Bad connection status value. " ) ;
sButInit . pTip = " Bug " ;
2010-08-01 04:06:50 -07:00
sButInit . UserData = PACKDWORD_TRI ( 0 , IMAGE_DESYNC_HI , IMAGE_PLAYER_LEFT_LO ) ;
2010-07-18 03:31:36 -07:00
break ;
case CONNECTIONSTATUS_PLAYER_LEAVING :
sButInit . pTip = _ ( " Player left " ) ;
2010-08-01 04:06:50 -07:00
sButInit . UserData = PACKDWORD_TRI ( i , IMAGE_PLAYER_LEFT_HI , IMAGE_PLAYER_LEFT_LO ) ;
2010-07-18 03:31:36 -07:00
break ;
case CONNECTIONSTATUS_PLAYER_DROPPED :
sButInit . pTip = _ ( " Player dropped " ) ;
2010-08-01 04:06:50 -07:00
sButInit . UserData = PACKDWORD_TRI ( i , IMAGE_DISCONNECT_LO , IMAGE_DISCONNECT_HI ) ;
2010-07-18 03:31:36 -07:00
break ;
case CONNECTIONSTATUS_WAITING_FOR_PLAYER :
sButInit . pTip = _ ( " Waiting for other players " ) ;
2010-08-01 04:06:50 -07:00
sButInit . UserData = PACKDWORD_TRI ( i , IMAGE_WAITING_HI , IMAGE_WAITING_LO ) ;
2010-07-18 03:31:36 -07:00
break ;
case CONNECTIONSTATUS_DESYNC :
sButInit . pTip = _ ( " Out of sync " ) ;
2010-08-01 04:06:50 -07:00
sButInit . UserData = PACKDWORD_TRI ( i , IMAGE_DESYNC_HI , IMAGE_DESYNC_LO ) ;
2010-07-18 03:31:36 -07:00
break ;
}
if ( ! widgAddButton ( psWScreen , & sButInit ) )
{
//return false;
}
+ + n ;
2010-03-14 05:27:05 -07:00
}
2010-08-01 04:06:50 -07:00
prevStatusMask = statusMask ;
2010-03-14 05:27:05 -07:00
}
}
2008-11-10 14:50:08 -08:00
/// Render the 3D world
2007-06-28 10:47:08 -07:00
void draw3DScene ( void )
{
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_START_FRAME , " Start 3D scene " ) ;
2013-02-07 12:48:21 -08:00
2007-06-28 10:47:08 -07:00
/* What frame number are we on? */
currentGameFrame = frameGetFrameNumber ( ) ;
2011-10-16 12:01:58 -07:00
// Tell shader system what the time is
pie_SetShaderTime ( graphicsTime ) ;
2007-06-28 10:47:08 -07:00
/* Build the drag quad */
if ( dragBox3D . status = = DRAG_RELEASED )
{
dragQuad . coords [ 0 ] . x = dragBox3D . x1 ; // TOP LEFT
dragQuad . coords [ 0 ] . y = dragBox3D . y1 ;
dragQuad . coords [ 1 ] . x = dragBox3D . x2 ; // TOP RIGHT
dragQuad . coords [ 1 ] . y = dragBox3D . y1 ;
dragQuad . coords [ 2 ] . x = dragBox3D . x2 ; // BOTTOM RIGHT
dragQuad . coords [ 2 ] . y = dragBox3D . y2 ;
dragQuad . coords [ 3 ] . x = dragBox3D . x1 ; // BOTTOM LEFT
dragQuad . coords [ 3 ] . y = dragBox3D . y2 ;
}
pie_Begin3DScene ( ) ;
2007-03-08 11:39:00 -08:00
/* Set 3D world origins */
2010-10-13 12:25:26 -07:00
pie_SetGeometricOffset ( rendSurface . width / 2 , geoOffset ) ;
2007-03-30 10:38:35 -07:00
2014-01-25 04:39:07 -08:00
/* Now, draw the terrain */
drawTiles ( & player ) ;
wzPerfBegin ( PERF_MISC , " 3D scene - misc and text " ) ;
/* Show the drag Box if necessary */
drawDragBox ( ) ;
/* Have we released the drag box? */
if ( dragBox3D . status = = DRAG_RELEASED )
{
dragBox3D . status = DRAG_INACTIVE ;
}
2007-03-30 10:38:35 -07:00
2007-06-28 10:47:08 -07:00
pie_BeginInterface ( ) ;
drawDroidSelections ( ) ;
drawStructureSelections ( ) ;
2012-01-14 10:39:54 -08:00
if ( radarOnScreen & & radarPermitted )
2007-06-28 10:47:08 -07:00
{
pie_SetDepthBufferStatus ( DEPTH_CMP_ALWAYS_WRT_ON ) ;
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( false ) ;
2010-01-17 18:11:27 -08:00
if ( getWidgetsStatus ( ) )
{
2013-03-11 15:20:04 -07:00
GL_DEBUG ( " Draw 3D scene - radar " ) ;
2010-01-17 18:11:27 -08:00
drawRadar ( ) ;
}
2007-06-28 10:47:08 -07:00
pie_SetDepthBufferStatus ( DEPTH_CMP_LEQ_WRT_ON ) ;
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( true ) ;
2007-06-28 10:47:08 -07:00
}
2010-01-17 18:11:27 -08:00
if ( ! bRender3DOnly )
2007-06-28 10:47:08 -07:00
{
2007-06-18 07:25:06 -07:00
/* Ensure that any text messages are displayed at bottom of screen */
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( false ) ;
2012-02-03 01:14:43 -08:00
displayConsoleMessages ( ) ;
2010-01-17 18:11:27 -08:00
}
2007-06-28 10:47:08 -07:00
pie_SetDepthBufferStatus ( DEPTH_CMP_ALWAYS_WRT_OFF ) ;
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( false ) ;
2007-12-09 08:09:23 -08:00
iV_SetTextColour ( WZCOL_TEXT_BRIGHT ) ;
2007-06-28 10:47:08 -07:00
2007-04-15 13:45:09 -07:00
/* Dont remove this folks!!!! */
2007-06-28 10:47:08 -07:00
if ( ! bAllowOtherKeyPresses )
{
displayMultiChat ( ) ;
}
2010-12-05 16:51:10 -08:00
if ( errorWaiting )
{
2013-12-01 10:10:38 -08:00
// print the error message if none have been printed for one minute
2013-12-01 09:01:38 -08:00
if ( lastErrorTime = = 0 | | lastErrorTime + ( 60 * GAME_TICKS_PER_SEC ) < realTime )
2010-12-05 16:51:10 -08:00
{
char trimMsg [ 255 ] ;
audio_PlayTrack ( ID_SOUND_BUILD_FAIL ) ;
2013-12-01 10:10:38 -08:00
ssprintf ( trimMsg , " Error! (Check your logs!): %.78s " , errorWaiting ) ;
2010-12-05 16:51:10 -08:00
addConsoleMessage ( trimMsg , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
2013-12-01 10:10:38 -08:00
errorWaiting = NULL ;
2013-12-01 09:01:38 -08:00
lastErrorTime = realTime ;
2010-12-05 16:51:10 -08:00
}
}
2013-12-01 10:10:38 -08:00
else
{
errorWaiting = debugLastError ( ) ;
}
2007-12-19 12:17:54 -08:00
if ( showSAMPLES ) //Displays the number of sound samples we currently have
{
2012-02-03 01:14:43 -08:00
iV_SetFont ( font_regular ) ;
2007-12-19 12:17:54 -08:00
unsigned int width , height ;
const char * Qbuf , * Lbuf , * Abuf ;
2007-12-24 05:57:19 -08:00
2007-12-19 12:17:54 -08:00
sasprintf ( ( char * * ) & Qbuf , " Que: %04u " , audio_GetSampleQueueCount ( ) ) ;
sasprintf ( ( char * * ) & Lbuf , " Lst: %04u " , audio_GetSampleListCount ( ) ) ;
sasprintf ( ( char * * ) & Abuf , " Act: %04u " , sound_GetActiveSamplesCount ( ) ) ;
width = iV_GetTextWidth ( Qbuf ) + 11 ;
height = iV_GetTextHeight ( Qbuf ) ;
iV_DrawText ( Qbuf , pie_GetVideoBufferWidth ( ) - width , height + 2 ) ;
iV_DrawText ( Lbuf , pie_GetVideoBufferWidth ( ) - width , height + 48 ) ;
iV_DrawText ( Abuf , pie_GetVideoBufferWidth ( ) - width , height + 59 ) ;
}
2007-12-07 13:37:08 -08:00
if ( showFPS )
{
2012-02-03 01:14:43 -08:00
iV_SetFont ( font_regular ) ;
2007-12-16 13:09:34 -08:00
unsigned int width , height ;
const char * fps ;
2011-11-30 11:07:06 -08:00
sasprintf ( ( char * * ) & fps , " FPS: %d " , frameRate ( ) ) ;
2007-12-16 13:09:34 -08:00
width = iV_GetTextWidth ( fps ) + 10 ;
height = iV_GetTextHeight ( fps ) ;
iV_DrawText ( fps , pie_GetVideoBufferWidth ( ) - width , pie_GetVideoBufferHeight ( ) - height ) ;
2007-12-07 13:37:08 -08:00
}
2009-04-26 14:35:32 -07:00
if ( showORDERS )
{
2012-02-03 01:14:43 -08:00
iV_SetFont ( font_regular ) ;
2011-01-07 06:29:45 -08:00
unsigned int height ;
2009-04-26 14:35:32 -07:00
height = iV_GetTextHeight ( DROIDDOING ) ;
iV_DrawText ( DROIDDOING , 0 , pie_GetVideoBufferHeight ( ) - height ) ;
}
2010-08-01 04:06:50 -07:00
setupConnectionStatusForm ( ) ;
2010-07-18 03:31:36 -07:00
2010-03-21 07:22:05 -07:00
if ( getWidgetsStatus ( ) & & ! gamePaused ( ) )
2007-04-15 13:45:09 -07:00
{
2010-03-21 07:22:05 -07:00
char buildInfo [ 255 ] ;
if ( showLevelName )
2007-06-28 10:47:08 -07:00
{
2012-02-11 21:51:07 -08:00
iV_SetFont ( font_small ) ;
iV_SetTextColour ( WZCOL_TEXT_MEDIUM ) ;
iV_DrawText ( getLevelName ( ) , RET_X + 134 , 410 + E_H ) ;
2007-06-28 10:47:08 -07:00
}
2012-03-04 03:03:31 -08:00
getAsciiTime ( buildInfo , graphicsTime ) ;
2012-02-11 21:51:07 -08:00
iV_DrawText ( buildInfo , RET_X + 134 , 422 + E_H ) ;
2012-11-16 05:16:59 -08:00
if ( getDebugMappingStatus ( ) )
2010-03-21 07:22:05 -07:00
{
2012-02-11 21:51:07 -08:00
iV_DrawText ( " DEBUG " , RET_X + 134 , 436 + E_H ) ;
2010-03-21 07:22:05 -07:00
}
2007-04-15 13:45:09 -07:00
}
2007-06-28 10:47:08 -07:00
2007-04-15 13:45:09 -07:00
while ( player . r . y > DEG ( 360 ) )
2007-06-28 10:47:08 -07:00
{
player . r . y - = DEG ( 360 ) ;
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
/* If we don't have an active camera track, then track terrain height! */
if ( ! getWarCamStatus ( ) )
{
2007-06-18 07:25:06 -07:00
/* Move the autonomous camera if necessary */
2007-12-07 13:49:28 -08:00
calcAverageTerrainHeight ( & player ) ;
2007-12-15 15:33:24 -08:00
trackHeight ( averageCentreTerrainHeight + CAMERA_PIVOT_HEIGHT ) ;
2007-06-28 10:47:08 -07:00
}
else
{
processWarCam ( ) ;
}
processSensorTarget ( ) ;
processDestinationTarget ( ) ;
2006-05-27 09:37:17 -07:00
2007-12-01 12:24:10 -08:00
structureEffects ( ) ; // add fancy effects to structures
2007-06-28 10:47:08 -07:00
2007-12-08 09:32:05 -08:00
showDroidSensorRanges ( ) ; //shows sensor data for units/droids/whatever...-Q 5-10-05
2009-06-04 10:52:05 -07:00
if ( CauseCrash )
{
char * crash = 0 ;
2009-10-09 17:42:42 -07:00
# ifdef DEBUG
ASSERT ( false , " Yes, this is a assert. This should not happen on release builds! Use --noassert to bypass in debug builds. " ) ;
debug ( LOG_WARNING , " *** Warning! You have compiled in debug mode! *** " ) ;
# endif
2012-03-17 15:12:07 -07:00
writeGameInfo ( " WZdebuginfo.txt " ) ; //also test writing out this file.
2009-10-30 20:57:44 -07:00
debug ( LOG_FATAL , " Forcing a segfault! (crash handler test) " ) ;
2009-06-04 10:52:05 -07:00
// and here comes the crash
* crash = 0x3 ;
exit ( - 1 ) ; // will never reach this, but just in case...
}
2006-10-08 01:06:46 -07:00
//visualize radius if needed
2007-12-08 09:50:38 -08:00
if ( bRangeDisplay )
{
2006-10-08 01:06:46 -07:00
drawRangeAtPos ( rangeCenterX , rangeCenterY , rangeRadius ) ;
2007-12-08 09:50:38 -08:00
}
2008-03-20 06:40:34 -07:00
if ( showPath )
{
showDroidPaths ( ) ;
}
2013-02-07 12:48:21 -08:00
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_MISC ) ;
2007-06-28 10:47:08 -07:00
}
2007-04-28 06:53:41 -07:00
2007-06-28 10:47:08 -07:00
/***************************************************************************/
2011-03-12 17:32:15 -08:00
bool doWeDrawProximitys ( void )
2007-06-28 10:47:08 -07:00
{
return ( bDrawProximitys ) ;
}
/***************************************************************************/
2011-03-12 17:32:15 -08:00
void setProximityDraw ( bool val )
2007-06-28 10:47:08 -07:00
{
bDrawProximitys = val ;
}
/***************************************************************************/
2008-11-10 14:50:08 -08:00
/// Calculate the average terrain height for the area directly below the player
2007-12-07 13:49:28 -08:00
static void calcAverageTerrainHeight ( iView * player )
{
int numTilesAveraged = 0 , i , j ;
/* We track the height here - so make sure we get the average heights
of the tiles directly underneath us
*/
averageCentreTerrainHeight = 0 ;
2011-04-30 09:41:50 -07:00
for ( i = - 4 ; i < = 4 ; i + + )
2007-12-07 13:49:28 -08:00
{
2011-04-30 09:41:50 -07:00
for ( j = - 4 ; j < = 4 ; j + + )
2007-12-07 13:49:28 -08:00
{
if ( tileOnMap ( playerXTile + j , playerZTile + i ) )
{
/* Get a pointer to the tile at this location */
MAPTILE * psTile = mapTile ( playerXTile + j , playerZTile + i ) ;
2010-11-16 11:02:22 -08:00
averageCentreTerrainHeight + = psTile - > height ;
2007-12-07 13:49:28 -08:00
numTilesAveraged + + ;
}
}
}
/* Work out the average height. We use this information to keep the player camera
* above the terrain . */
if ( numTilesAveraged ) // might not be if off map
{
2011-04-30 09:41:50 -07:00
MAPTILE * psTile = mapTile ( playerXTile , playerZTile ) ;
2007-12-07 13:49:28 -08:00
averageCentreTerrainHeight / = numTilesAveraged ;
2010-11-16 11:02:22 -08:00
if ( averageCentreTerrainHeight < psTile - > height )
2007-12-07 13:49:28 -08:00
{
2010-11-16 11:02:22 -08:00
averageCentreTerrainHeight = psTile - > height ;
2007-12-07 13:49:28 -08:00
}
}
else
{
averageCentreTerrainHeight = ELEVATION_SCALE * TILE_UNITS ;
}
}
2007-12-13 14:00:54 -08:00
2008-11-10 14:50:08 -08:00
/// Draw the terrain and all droids, missiles and other objects on it
2008-01-27 11:31:58 -08:00
static void drawTiles ( iView * player )
2007-06-28 10:47:08 -07:00
{
2011-04-30 09:41:50 -07:00
int i , j ;
int idx , jdx ;
2010-03-06 15:06:35 -08:00
Vector3f theSun ;
2007-06-28 10:47:08 -07:00
2014-01-25 04:39:07 -08:00
// draw terrain
pie_PerspectiveBegin ( ) ;
2013-02-07 12:48:21 -08:00
2007-06-28 10:47:08 -07:00
/* ---------------------------------------------------------------- */
/* Do boundary and extent checking */
/* ---------------------------------------------------------------- */
/* Find our position in tile coordinates */
2007-09-29 12:42:29 -07:00
playerXTile = map_coord ( player - > p . x ) ;
playerZTile = map_coord ( player - > p . z ) ;
2007-06-28 10:47:08 -07:00
/* ---------------------------------------------------------------- */
/* Set up the geometry */
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
/* Push identity matrix onto stack */
pie_MatBegin ( ) ;
2007-04-28 06:53:41 -07:00
2011-12-28 12:34:29 -08:00
actualCameraPosition = Vector3i ( 0 , 0 , 0 ) ;
2011-04-25 03:29:26 -07:00
/* Set the camera position */
pie_TRANSLATE ( 0 , 0 , distance ) ;
2011-12-28 12:34:29 -08:00
actualCameraPosition . z - = distance ;
2007-06-28 10:47:08 -07:00
// Now, scale the world according to what resolution we're running in
2010-09-19 13:12:40 -07:00
pie_MatScale ( pie_GetResScalingFactor ( ) / 100.f ) ;
2007-04-28 06:53:41 -07:00
2011-12-28 12:34:29 -08:00
actualCameraPosition . z / = pie_GetResScalingFactor ( ) / 100.f ;
2007-06-28 10:47:08 -07:00
/* Rotate for the player */
2010-10-08 02:04:32 -07:00
pie_MatRotZ ( player - > r . z ) ;
pie_MatRotX ( player - > r . x ) ;
pie_MatRotY ( player - > r . y ) ;
2007-04-28 06:53:41 -07:00
2011-12-28 12:34:29 -08:00
rotateSomething ( actualCameraPosition . x , actualCameraPosition . y , - player - > r . z ) ;
rotateSomething ( actualCameraPosition . y , actualCameraPosition . z , - player - > r . x ) ;
rotateSomething ( actualCameraPosition . z , actualCameraPosition . x , - player - > r . y ) ;
2007-04-15 13:45:09 -07:00
/* Translate */
2011-04-25 03:29:26 -07:00
pie_TRANSLATE ( 0 , - player - > p . y , 0 ) ;
2007-04-28 06:53:41 -07:00
2011-12-28 12:34:29 -08:00
actualCameraPosition . y - = - player - > p . y ;
// Not sure if should do this here or whenever using, since this transform seems to be done all over the place.
//actualCameraPosition -= Vector3i(-player->p.x, 0, player->p.z);
2010-03-06 15:06:35 -08:00
// this also detemines the length of the shadows
theSun = getTheSun ( ) ;
2013-02-18 11:39:25 -08:00
pie_BeginLighting ( & theSun ) ;
2006-05-27 09:37:17 -07:00
2011-11-30 15:26:43 -08:00
// update the fog of war... FIXME: Remove this
2011-04-30 09:41:50 -07:00
for ( i = - visibleTiles . y / 2 , idx = 0 ; i < = visibleTiles . y / 2 ; i + + , + + idx )
2007-06-28 10:47:08 -07:00
{
/* Go through the x's */
2011-04-30 09:41:50 -07:00
for ( j = - visibleTiles . x / 2 , jdx = 0 ; j < = visibleTiles . x / 2 ; j + + , + + jdx )
2007-06-28 10:47:08 -07:00
{
2013-03-30 19:09:19 -07:00
Vector2i screen ( 0 , 0 ) ;
Position pos ;
pos . x = world_coord ( j ) ;
pos . z = - world_coord ( i ) ;
pos . y = 0 ;
2011-01-01 07:28:16 -08:00
if ( tileOnMap ( playerXTile + j , playerZTile + i ) )
2007-06-28 10:47:08 -07:00
{
2011-11-30 15:26:43 -08:00
MAPTILE * psTile = mapTile ( playerXTile + j , playerZTile + i ) ;
2013-03-30 19:09:19 -07:00
pos . y = map_TileHeight ( playerXTile + j , playerZTile + i ) ;
2011-11-30 15:26:43 -08:00
setTileColour ( playerXTile + j , playerZTile + i , pal_SetBrightness ( psTile - > level ) ) ;
2007-06-28 10:47:08 -07:00
}
2013-03-30 19:09:19 -07:00
tileScreenInfo [ idx ] [ jdx ] . z = pie_RotateProject ( & pos , & screen ) ;
tileScreenInfo [ idx ] [ jdx ] . x = screen . x ;
tileScreenInfo [ idx ] [ jdx ] . y = screen . y ;
2007-06-28 10:47:08 -07:00
}
}
2014-01-25 04:39:07 -08:00
wzPerfEnd ( PERF_START_FRAME ) ;
2007-06-28 10:47:08 -07:00
/* This is done here as effects can light the terrain - pause mode problems though */
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_EFFECTS , " 3D scene - effects " ) ;
2007-06-28 10:47:08 -07:00
processEffects ( ) ;
atmosUpdateSystem ( ) ;
2010-01-05 10:13:56 -08:00
avUpdateTiles ( ) ;
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_EFFECTS ) ;
2007-06-28 10:47:08 -07:00
2009-02-21 15:35:21 -08:00
// now we are about to draw the terrain
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_TERRAIN , " 3D scene - terrain " ) ;
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( true ) ;
2011-04-25 03:29:26 -07:00
2011-04-30 09:41:50 -07:00
pie_MatBegin ( ) ;
2009-02-21 15:35:21 -08:00
// also, make sure we can use world coordinates directly
2011-04-30 09:41:50 -07:00
pie_TRANSLATE ( - player - > p . x , 0 , player - > p . z ) ;
2011-04-25 03:29:26 -07:00
2009-02-21 15:35:21 -08:00
// and draw it
drawTerrain ( ) ;
2010-03-06 15:06:35 -08:00
2009-02-21 15:35:21 -08:00
// and to the warzone modelview transform
2011-04-30 09:41:50 -07:00
pie_MatEnd ( ) ;
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_TERRAIN ) ;
2009-06-01 12:47:28 -07:00
// draw skybox
2014-01-25 04:39:07 -08:00
wzPerfBegin ( PERF_SKYBOX , " 3D scene - skybox " ) ;
2009-06-01 12:47:28 -07:00
renderSurroundings ( ) ;
2014-01-25 04:39:07 -08:00
wzPerfEnd ( PERF_SKYBOX ) ;
2011-04-25 03:29:26 -07:00
2009-02-21 15:35:21 -08:00
// and prepare for rendering the models
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_MODEL_INIT , " Draw 3D scene - model init " ) ;
2010-02-04 01:02:16 -08:00
pie_SetRendMode ( REND_OPAQUE ) ;
2007-12-01 08:31:09 -08:00
2007-06-28 10:47:08 -07:00
/* ---------------------------------------------------------------- */
/* Now display all the static objects */
/* ---------------------------------------------------------------- */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
displayStaticObjects ( ) ; // may be bucket render implemented
displayFeatures ( ) ;
displayDynamicObjects ( ) ; // may be bucket render implemented
2007-06-28 10:47:08 -07:00
if ( doWeDrawProximitys ( ) )
{
2013-02-18 11:00:25 -08:00
displayProximityMsgs ( ) ;
2007-06-28 10:47:08 -07:00
}
2013-02-18 11:00:25 -08:00
displayDelivPoints ( ) ;
display3DProjectiles ( ) ; // may be bucket render implemented
pie_MatEnd ( ) ;
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_MODEL_INIT ) ;
2007-06-28 10:47:08 -07:00
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_PARTICLES , " 3D scene - particles " ) ;
2007-06-28 10:47:08 -07:00
atmosDrawParticles ( ) ;
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_PARTICLES ) ;
2011-04-25 03:29:26 -07:00
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_WATER , " 3D scene - water " ) ;
2009-02-21 15:35:21 -08:00
// prepare for the water and the lightmap
pie_SetFogStatus ( true ) ;
2011-04-25 03:29:26 -07:00
2011-04-30 09:41:50 -07:00
pie_MatBegin ( ) ;
2009-02-21 15:35:21 -08:00
// also, make sure we can use world coordinates directly
2011-04-30 09:41:50 -07:00
pie_TRANSLATE ( - player - > p . x , 0 , player - > p . z ) ;
2011-04-25 03:29:26 -07:00
2009-02-21 15:35:21 -08:00
drawWater ( ) ;
2011-04-25 03:29:26 -07:00
2009-02-21 15:35:21 -08:00
// and to the warzone modelview transform
2011-04-30 09:41:50 -07:00
pie_MatEnd ( ) ;
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_WATER ) ;
2007-04-05 08:24:03 -07:00
2013-10-05 03:06:27 -07:00
wzPerfBegin ( PERF_MODELS , " 3D scene - models " ) ;
2007-06-28 10:47:08 -07:00
bucketRenderCurrentList ( ) ;
2009-03-11 15:55:41 -07:00
2013-10-05 03:06:27 -07:00
GL_DEBUG ( " Draw 3D scene - blueprints " ) ;
2009-03-11 15:55:41 -07:00
displayBlueprints ( ) ;
2011-04-25 03:29:26 -07:00
2009-03-11 15:55:41 -07:00
pie_RemainingPasses ( ) ; // draws shadows and transparent shapes
2007-06-28 10:47:08 -07:00
if ( ! gamePaused ( ) )
{
doConstructionLines ( ) ;
}
/* Clear the matrix stack */
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2013-03-30 19:09:19 -07:00
locateMouse ( ) ;
2014-01-25 04:39:07 -08:00
pie_PerspectiveEnd ( ) ;
2013-10-05 03:06:27 -07:00
wzPerfEnd ( PERF_MODELS ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Initialise the fog, skybox and some other stuff
2011-03-12 17:32:15 -08:00
bool init3DView ( void )
2007-06-28 10:47:08 -07:00
{
2008-01-27 17:29:20 -08:00
/* Arbitrary choice - from direct read! */
2010-12-21 12:51:29 -08:00
Vector3f theSun ( 225.0f , - 600.0f , 450.0f ) ;
2008-03-16 04:05:08 -07:00
setTheSun ( theSun ) ;
2008-01-27 17:29:20 -08:00
2007-06-28 10:47:08 -07:00
/* There are no drag boxes */
dragBox3D . status = DRAG_INACTIVE ;
/* Get all the init stuff out of here? */
initWarCam ( ) ;
/* Init the game messaging system */
initConsoleMessages ( ) ;
atmosInitSystem ( ) ;
2007-03-20 13:46:26 -07:00
// Set the initial fog distance
UpdateFogDistance ( distance ) ;
2008-03-24 09:51:17 -07:00
bRender3DOnly = false ;
2007-06-28 10:47:08 -07:00
2013-02-17 02:17:54 -08:00
// default skybox, will override in script if not satisfactory
setSkyBox ( " texpages/page-25-sky-arizona.png " , 0.0f , 10000.0f ) ;
2008-03-05 10:09:12 -08:00
2008-02-05 11:24:56 -08:00
// distance is not saved, so initialise it now
distance = START_DISTANCE ; // distance
2011-04-25 03:29:26 -07:00
2009-05-04 13:05:09 -07:00
disp3d_resetView ( ) ; // clear player view variables
2009-03-11 05:44:04 -07:00
if ( ! initTerrain ( ) )
{
return false ;
}
2008-01-27 17:29:20 -08:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// set the view position from save game
2007-06-28 10:47:08 -07:00
void disp3d_setView ( iView * newView )
{
2006-05-27 09:37:17 -07:00
memcpy ( & player , newView , sizeof ( iView ) ) ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2008-11-10 14:50:08 -08:00
/// reset the camera rotation (used for save games <= 10)
2008-02-01 14:15:55 -08:00
void disp3d_resetView ( )
{
player . r . z = 0 ; // roll
player . r . y = INITIAL_DESIRED_ROTATION ; // rotation
player . r . x = DEG ( 360 + INITIAL_STARTING_PITCH ) ; // angle
// and set the camera position
player . p . y = START_HEIGHT ; // height
}
2008-11-10 14:50:08 -08:00
/// get the view position for save game
2007-06-28 10:47:08 -07:00
void disp3d_getView ( iView * newView )
{
2006-05-27 09:37:17 -07:00
memcpy ( newView , & player , sizeof ( iView ) ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Are the current tile coordinates visible on screen?
2011-03-12 17:32:15 -08:00
bool clipXY ( SDWORD x , SDWORD y )
2007-06-28 10:47:08 -07:00
{
2011-04-30 09:41:50 -07:00
// +2 for edge of visibility fading (see terrain.cpp)
if ( std : : abs ( x - player . p . x ) < world_coord ( visibleTiles . x / 2 + 2 ) & &
std : : abs ( y - player . p . z ) < world_coord ( visibleTiles . y / 2 + 2 ) )
2008-03-24 09:51:17 -07:00
return ( true ) ;
2007-06-28 10:47:08 -07:00
else
2008-03-24 09:51:17 -07:00
return ( false ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/** Get the screen coordinates for the current transform matrix.
* This function is used to determine the area the user can click for the
* intelligence screen buttons . The radius parameter is always set to the same value .
*/
2007-03-16 15:45:30 -07:00
static void calcFlagPosScreenCoords ( SDWORD * pX , SDWORD * pY , SDWORD * pR )
2007-06-28 10:47:08 -07:00
{
/* Get it's absolute dimensions */
2010-12-21 12:51:29 -08:00
Vector3i center3d ( 0 , 0 , 0 ) ;
Vector2i center2d ( 0 , 0 ) ;
2007-06-28 10:47:08 -07:00
/* How big a box do we want - will ultimately be calculated using xmax, ymax, zmax etc */
2007-05-21 07:06:31 -07:00
UDWORD radius = 22 ;
2007-06-28 10:47:08 -07:00
/* Pop matrices and get the screen coordinates for last point*/
2007-05-21 07:06:31 -07:00
pie_RotateProject ( & center3d , & center2d ) ;
2007-06-28 10:47:08 -07:00
/*store the coords*/
2007-05-21 07:06:31 -07:00
* pX = center2d . x ;
* pY = center2d . y ;
2007-06-28 10:47:08 -07:00
* pR = radius ;
}
2008-11-10 14:50:08 -08:00
/// Decide whether to render a projectile, and make sure it will be drawn
2007-03-16 15:45:30 -07:00
static void display3DProjectiles ( void )
2007-06-28 10:47:08 -07:00
{
2007-07-12 12:32:26 -07:00
PROJECTILE * psObj ;
2007-06-28 10:47:08 -07:00
psObj = proj_GetFirst ( ) ;
while ( psObj ! = NULL )
{
2011-12-27 06:04:54 -08:00
// If source or destination is visible, and projectile has been spawned and has not impacted.
if ( graphicsTime > = psObj - > prevSpacetime . time & & graphicsTime < = psObj - > time & & gfxVisible ( psObj ) )
2007-06-28 10:47:08 -07:00
{
2011-12-27 06:04:54 -08:00
/* Draw a bullet at psObj->pos.x for X coord
psObj - > pos . y for Z coord
whatever for Y ( height ) coord - arcing ?
*/
/* these guys get drawn last */
if ( psObj - > psWStats - > weaponSubClass = = WSC_ROCKET | |
psObj - > psWStats - > weaponSubClass = = WSC_MISSILE | |
psObj - > psWStats - > weaponSubClass = = WSC_COMMAND | |
psObj - > psWStats - > weaponSubClass = = WSC_SLOWMISSILE | |
psObj - > psWStats - > weaponSubClass = = WSC_SLOWROCKET | |
psObj - > psWStats - > weaponSubClass = = WSC_ENERGY | |
psObj - > psWStats - > weaponSubClass = = WSC_EMP )
2010-02-06 09:08:26 -08:00
{
2011-12-27 06:04:54 -08:00
bucketAddTypeToList ( RENDER_PROJECTILE , psObj ) ;
2010-02-06 09:08:26 -08:00
}
2011-12-27 06:04:54 -08:00
else
2007-06-28 10:47:08 -07:00
{
2011-12-27 06:04:54 -08:00
renderProjectile ( psObj ) ;
2007-06-28 10:47:08 -07:00
}
2011-12-27 06:04:54 -08:00
}
2007-06-28 10:47:08 -07:00
psObj = proj_GetNext ( ) ;
}
} /* end of function display3DProjectiles */
2008-11-10 14:50:08 -08:00
/// Draw a projectile to the screen
2007-07-12 12:32:26 -07:00
void renderProjectile ( PROJECTILE * psCurr )
2007-06-28 10:47:08 -07:00
{
WEAPON_STATS * psStats ;
2007-03-16 09:20:16 -07:00
Vector3i dv ;
2007-06-28 10:47:08 -07:00
iIMDShape * pIMD ;
2010-12-22 12:56:52 -08:00
Spacetime st ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
psStats = psCurr - > psWStats ;
/* Reject flame or command since they have interim drawn fx */
2007-02-10 08:39:39 -08:00
if ( psStats - > weaponSubClass = = WSC_FLAME | |
2007-04-15 13:45:09 -07:00
psStats - > weaponSubClass = = WSC_COMMAND | | // || psStats->weaponSubClass == WSC_ENERGY)
2007-02-10 08:39:39 -08:00
psStats - > weaponSubClass = = WSC_ELECTRONIC | |
2007-04-15 13:45:09 -07:00
psStats - > weaponSubClass = = WSC_EMP | |
( bMultiPlayer & & psStats - > weaponSubClass = = WSC_LAS_SAT ) )
2007-06-28 10:47:08 -07:00
{
/* We don't do projectiles from these guys, cos there's an effect instead */
return ;
}
2010-12-22 12:56:52 -08:00
st = interpolateObjectSpacetime ( psCurr , graphicsTime ) ;
2007-06-28 10:47:08 -07:00
//the weapon stats holds the reference to which graphic to use
2006-05-27 09:37:17 -07:00
/*Need to draw the graphic depending on what the projectile is doing - hitting target,
2007-06-28 10:47:08 -07:00
missing target , in flight etc - JUST DO IN FLIGHT FOR NOW ! */
pIMD = psStats - > pInFlightGraphic ;
2013-03-01 12:15:59 -08:00
if ( ! clipXY ( st . pos . x , st . pos . y ) )
{
return ;
}
for ( ; pIMD ! = NULL ; pIMD = pIMD - > next )
2007-06-28 10:47:08 -07:00
{
2011-12-28 12:34:29 -08:00
bool rollToCamera = false ;
bool pitchToCamera = false ;
2012-01-06 10:19:15 -08:00
bool premultiplied = false ;
2011-12-28 12:34:29 -08:00
bool additive = psStats - > weaponSubClass = = WSC_ROCKET | | psStats - > weaponSubClass = = WSC_MISSILE | | psStats - > weaponSubClass = = WSC_SLOWROCKET | | psStats - > weaponSubClass = = WSC_SLOWMISSILE ;
2012-02-05 08:18:29 -08:00
if ( pIMD - > flags & iV_IMD_ROLL_TO_CAMERA )
2011-12-28 12:34:29 -08:00
{
2012-02-05 08:18:29 -08:00
rollToCamera = true ;
}
if ( pIMD - > flags & iV_IMD_PITCH_TO_CAMERA )
{
rollToCamera = true ;
pitchToCamera = true ;
}
if ( pIMD - > flags & iV_IMD_NO_ADDITIVE )
{
additive = false ;
}
if ( pIMD - > flags & iV_IMD_ADDITIVE )
{
additive = true ;
}
if ( pIMD - > flags & iV_IMD_PREMULTIPLIED )
{
additive = false ;
premultiplied = true ;
2011-12-28 12:34:29 -08:00
}
2007-06-28 10:47:08 -07:00
/* Get bullet's x coord */
2011-04-30 09:41:50 -07:00
dv . x = st . pos . x - player . p . x ;
2007-06-28 10:47:08 -07:00
/* Get it's y coord (z coord in the 3d world */
2011-04-30 09:41:50 -07:00
dv . z = - ( st . pos . y - player . p . z ) ;
2007-06-28 10:47:08 -07:00
/* What's the present height of the bullet? */
2010-02-06 09:08:26 -08:00
dv . y = st . pos . z ;
2007-06-28 10:47:08 -07:00
/* Set up the matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2011-12-28 12:34:29 -08:00
Vector3i camera = actualCameraPosition ;
2007-06-28 10:47:08 -07:00
/* Translate to the correct position */
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2011-12-28 12:34:29 -08:00
camera - = Vector3i ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
/* Rotate it to the direction it's facing */
2013-01-11 11:45:11 -08:00
pie_MatRotY ( - st . rot . direction ) ;
rotateSomething ( camera . z , camera . x , - ( - st . rot . direction ) ) ;
2007-06-28 10:47:08 -07:00
2007-04-15 13:45:09 -07:00
/* pitch it */
2013-01-11 11:45:11 -08:00
pie_MatRotX ( st . rot . pitch ) ;
rotateSomething ( camera . y , camera . z , - st . rot . pitch ) ;
2011-12-28 12:34:29 -08:00
if ( pitchToCamera | | rollToCamera )
{
// Centre on projectile (relevant for twin projectiles).
2012-02-05 08:18:29 -08:00
pie_TRANSLATE ( pIMD - > connectors [ 0 ] . x , pIMD - > connectors [ 0 ] . y , pIMD - > connectors [ 0 ] . z ) ;
camera - = Vector3i ( pIMD - > connectors [ 0 ] . x , pIMD - > connectors [ 0 ] . y , pIMD - > connectors [ 0 ] . z ) ;
2011-12-28 12:34:29 -08:00
}
if ( pitchToCamera )
{
2013-01-11 11:45:11 -08:00
int x = iAtan2 ( camera . z , camera . y ) ;
pie_MatRotX ( x ) ;
rotateSomething ( camera . y , camera . z , - x ) ;
2011-12-28 12:34:29 -08:00
}
if ( rollToCamera )
{
2013-01-11 11:45:11 -08:00
int z = - iAtan2 ( camera . x , camera . y ) ;
pie_MatRotZ ( z ) ;
rotateSomething ( camera . x , camera . y , - z ) ;
2011-12-28 12:34:29 -08:00
}
if ( pitchToCamera | | rollToCamera )
{
// Undo centre on projectile (relevant for twin projectiles).
2012-02-05 08:18:29 -08:00
pie_TRANSLATE ( - pIMD - > connectors [ 0 ] . x , - pIMD - > connectors [ 0 ] . y , - pIMD - > connectors [ 0 ] . z ) ;
camera - = Vector3i ( - pIMD - > connectors [ 0 ] . x , - pIMD - > connectors [ 0 ] . y , - pIMD - > connectors [ 0 ] . z ) ;
2011-12-28 12:34:29 -08:00
}
2007-06-28 10:47:08 -07:00
2012-01-06 10:19:15 -08:00
if ( premultiplied )
{
pie_Draw3DShape ( pIMD , 0 , 0 , WZCOL_WHITE , pie_PREMULTIPLIED , 0 ) ;
}
else if ( additive )
2007-06-28 10:47:08 -07:00
{
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( pIMD , 0 , 0 , WZCOL_WHITE , pie_ADDITIVE , 164 ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( pIMD , 0 , 0 , WZCOL_WHITE , 0 , 0 ) ;
2007-06-28 10:47:08 -07:00
}
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
}
2008-11-10 14:50:08 -08:00
/// Draw an animated component
void renderAnimComponent ( const COMPONENT_OBJECT * psObj )
2007-06-28 10:47:08 -07:00
{
2007-06-02 16:01:29 -07:00
BASE_OBJECT * psParentObj = ( BASE_OBJECT * ) psObj - > psParent ;
2010-12-22 12:56:52 -08:00
Spacetime spacetime = interpolateObjectSpacetime ( psParentObj , graphicsTime ) ;
2010-02-06 09:10:20 -08:00
const SDWORD posX = spacetime . pos . x + psObj - > position . x ,
posY = spacetime . pos . y + psObj - > position . y ;
2007-06-28 10:47:08 -07:00
2013-03-01 12:15:59 -08:00
ASSERT ( psParentObj , " Invalid parent object pointer " ) ;
2007-06-28 10:47:08 -07:00
/* only draw visible bits */
2012-11-16 05:16:59 -08:00
if ( psParentObj - > type = = OBJ_DROID & & ( ( DROID * ) psParentObj ) - > visible [ selectedPlayer ] ! = UBYTE_MAX )
2007-06-28 10:47:08 -07:00
{
2007-06-02 16:01:29 -07:00
return ;
2007-06-28 10:47:08 -07:00
}
2013-03-01 12:15:59 -08:00
if ( ! clipXY ( posX , posY ) )
2007-06-28 10:47:08 -07:00
{
2013-03-01 12:15:59 -08:00
return ;
}
2007-06-02 16:01:29 -07:00
/* get parent object translation */
2010-12-21 12:51:29 -08:00
const Vector3i dv (
2011-04-30 09:41:50 -07:00
spacetime . pos . x - player . p . x ,
2010-02-06 09:10:20 -08:00
spacetime . pos . z ,
2011-04-30 09:41:50 -07:00
- ( spacetime . pos . y - player . p . z )
2010-12-21 12:51:29 -08:00
) ;
2011-10-16 12:01:58 -07:00
int iPlayer , pieFlag = pie_STATIC_SHADOW ;
2007-12-13 10:08:37 -08:00
PIELIGHT brightness ;
2011-10-16 12:01:58 -07:00
MAPTILE * psTile = worldTile ( psParentObj - > pos . x , psParentObj - > pos . y ) ;
if ( psTile - > jammerBits & alliancebits [ psParentObj - > player ] )
{
pieFlag | = pie_ECM ;
}
2007-06-02 16:01:29 -07:00
2007-06-28 10:47:08 -07:00
psParentObj - > sDisplay . frameNumber = currentGameFrame ;
2007-06-02 16:01:29 -07:00
2007-06-28 10:47:08 -07:00
/* Push the indentity matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2007-06-28 10:47:08 -07:00
/* parent object translation */
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
/* parent object rotations */
2013-01-11 11:45:11 -08:00
pie_MatRotY ( - spacetime . rot . direction ) ;
pie_MatRotX ( spacetime . rot . pitch ) ;
2007-06-28 10:47:08 -07:00
/* Set frame numbers - look into this later?? FIXME!!!!!!!! */
if ( psParentObj - > type = = OBJ_DROID )
{
2007-06-02 16:01:29 -07:00
DROID * psDroid = ( DROID * ) psParentObj ;
2007-06-28 10:47:08 -07:00
if ( psDroid - > droidType = = DROID_PERSON )
{
2007-06-02 16:01:29 -07:00
iPlayer = psParentObj - > player - 6 ;
2010-09-19 13:12:40 -07:00
pie_MatScale ( .75f ) ;
2007-06-28 10:47:08 -07:00
}
else
{
iPlayer = getPlayerColour ( psParentObj - > player ) ;
}
/* Get the onscreen coordinates so we can draw a bounding box */
calcScreenCoords ( psDroid ) ;
}
else
{
iPlayer = getPlayerColour ( psParentObj - > player ) ;
}
//brightness and fog calculation
if ( psParentObj - > type = = OBJ_STRUCTURE )
{
2007-06-02 16:01:29 -07:00
STRUCTURE * psStructure = ( STRUCTURE * ) psParentObj ;
2010-01-28 06:50:18 -08:00
brightness = structureBrightness ( psStructure ) ;
2013-02-24 02:36:14 -08:00
setScreenDisp ( & psStructure - > sDisplay ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2007-12-08 16:33:03 -08:00
brightness = pal_SetBrightness ( UBYTE_MAX ) ;
2011-10-20 18:04:50 -07:00
if ( ! getRevealStatus ( ) )
2010-01-28 06:50:18 -08:00
{
brightness = pal_SetBrightness ( avGetObjLightLevel ( ( BASE_OBJECT * ) psParentObj , brightness . byte . r ) ) ;
}
2007-06-28 10:47:08 -07:00
}
2007-06-02 16:01:29 -07:00
2010-02-04 10:05:52 -08:00
// Do translation and rotation after setting sDisplay.screen[XY], so that the health bars for animated objects (such as oil derricks and cyborgs) will show on the stationary part.
// object (animation) translations - ivis z and y flipped
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( psObj - > position . x , psObj - > position . z , psObj - > position . y ) ;
2010-02-04 10:05:52 -08:00
// object (animation) rotations
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - psObj - > orientation . z ) ;
pie_MatRotZ ( - psObj - > orientation . y ) ;
pie_MatRotX ( - psObj - > orientation . x ) ;
2010-02-04 10:05:52 -08:00
2011-10-16 12:01:58 -07:00
pie_Draw3DShape ( psObj - > psShape , 0 , iPlayer , brightness , pieFlag , 0 ) ;
2007-06-28 10:47:08 -07:00
/* clear stack */
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draw the buildings
2013-10-05 04:37:53 -07:00
static void displayStaticObjects ( )
2007-06-28 10:47:08 -07:00
{
ANIM_OBJECT * psAnimObj ;
2007-04-05 08:24:03 -07:00
// to solve the flickering edges of baseplates
pie_SetDepthOffset ( - 1.0f ) ;
2007-06-28 10:47:08 -07:00
/* Go through all the players */
2011-12-28 05:42:41 -08:00
for ( unsigned player = 0 ; player < = MAX_PLAYERS ; + + player )
2007-06-28 10:47:08 -07:00
{
2011-12-28 05:42:41 -08:00
BASE_OBJECT * list = player < MAX_PLAYERS ? apsStructLists [ player ] : psDestroyedObj ;
2007-06-28 10:47:08 -07:00
/* Now go all buildings for that player */
2011-12-28 05:42:41 -08:00
for ( ; list ! = NULL ; list = list - > psNext )
2007-06-28 10:47:08 -07:00
{
/* Worth rendering the structure? */
2013-03-01 12:15:59 -08:00
if ( list - > type ! = OBJ_STRUCTURE
| | ( list - > died ! = 0 & & list - > died < graphicsTime )
| | ! clipXY ( list - > pos . x , list - > pos . y ) )
2007-06-28 10:47:08 -07:00
{
2013-03-01 12:15:59 -08:00
continue ;
}
STRUCTURE * psStructure = castStructure ( list ) ;
2007-04-05 08:24:03 -07:00
if ( psStructure - > pStructureType - > type = = REF_RESOURCE_EXTRACTOR & &
psStructure - > psCurAnim = = NULL & &
( psStructure - > currentBuildPts > ( SDWORD ) psStructure - > pStructureType - > buildPoints ) )
{
psStructure - > psCurAnim = animObj_Add ( psStructure , ID_ANIM_DERIK , 0 , 0 ) ;
}
if ( psStructure - > psCurAnim = = NULL | |
2008-03-24 09:51:17 -07:00
psStructure - > psCurAnim - > bVisible = = false | |
2007-04-05 08:24:03 -07:00
( psAnimObj = animObj_Find ( psStructure ,
psStructure - > psCurAnim - > uwID ) ) = = NULL )
2007-06-28 10:47:08 -07:00
{
renderStructure ( psStructure ) ;
}
2013-03-01 12:15:59 -08:00
else if ( psStructure - > visible [ selectedPlayer ] )
2007-06-28 10:47:08 -07:00
{
2007-04-05 08:24:03 -07:00
//check not a resource extractors
2013-02-09 12:30:21 -08:00
if ( psStructure - > pStructureType - > type ! = REF_RESOURCE_EXTRACTOR )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
displayAnimation ( psAnimObj , false ) ;
2007-04-05 08:24:03 -07:00
}
/*check the building is active*/
2013-05-26 23:11:19 -07:00
else if ( psStructure - > pFunctionality - > resourceExtractor . psPowerGen ! = nullptr )
2007-04-05 08:24:03 -07:00
{
2008-03-24 09:51:17 -07:00
displayAnimation ( psAnimObj , false ) ;
2007-04-05 08:24:03 -07:00
if ( selectedPlayer = = psStructure - > player )
2007-06-28 10:47:08 -07:00
{
2010-12-22 14:34:57 -08:00
audio_PlayObjStaticTrack ( psStructure , ID_SOUND_OIL_PUMP_2 ) ;
2007-06-28 10:47:08 -07:00
}
}
2007-04-05 08:24:03 -07:00
else
{
/* hold anim on first frame */
2008-03-24 09:51:17 -07:00
displayAnimation ( psAnimObj , true ) ;
2010-12-22 14:34:57 -08:00
audio_StopObjTrack ( psStructure , ID_SOUND_OIL_PUMP_2 ) ;
2007-04-05 08:24:03 -07:00
}
2007-06-28 10:47:08 -07:00
}
}
}
2007-04-05 08:24:03 -07:00
pie_SetDepthOffset ( 0.0f ) ;
2007-06-28 10:47:08 -07:00
}
2012-01-02 11:35:21 -08:00
static bool tileHasIncompatibleStructure ( MAPTILE const * tile , STRUCTURE_STATS const * stats , int moduleIndex )
2011-11-18 08:23:55 -08:00
{
STRUCTURE * psStruct = castStructure ( tile - > psObject ) ;
2011-11-18 10:27:46 -08:00
if ( psStruct = = NULL )
{
return false ;
}
2012-01-02 11:35:21 -08:00
if ( psStruct - > status = = SS_BEING_BUILT & & nextModuleToBuild ( psStruct , - 1 ) > = moduleIndex )
2011-11-18 10:27:46 -08:00
{
return true ;
}
if ( isWall ( psStruct - > pStructureType - > type ) & & isBuildableOnWalls ( stats - > type ) )
{
return false ;
}
if ( IsStatExpansionModule ( stats ) )
{
return false ;
}
return true ;
2011-11-18 08:23:55 -08:00
}
2011-11-18 10:27:46 -08:00
static void drawLineBuild ( STRUCTURE_STATS const * psStats , int left , int right , int up , int down , uint16_t direction , STRUCT_STATES state )
2009-03-11 15:55:41 -07:00
{
if ( left ! = right & & up ! = down )
{
// not a line, so don't draw
return ;
}
2011-11-17 03:27:01 -08:00
for ( int i = left ; i < = right ; + + i )
2009-03-11 15:55:41 -07:00
{
2011-11-17 03:27:01 -08:00
for ( int j = up ; j < = down ; + + j )
2009-03-11 15:55:41 -07:00
{
2012-01-02 11:35:21 -08:00
if ( tileHasIncompatibleStructure ( mapTile ( i , j ) , psStats , 0 ) )
2009-03-11 15:55:41 -07:00
{
continue ; // construction has started
}
2011-11-17 03:27:01 -08:00
Vector2i pos ( world_coord ( i ) + world_coord ( 1 ) / 2 , world_coord ( j ) + world_coord ( 1 ) / 2 ) ;
2012-01-02 11:35:21 -08:00
Blueprint blueprint ( psStats , pos , direction , 0 , state ) ;
2011-11-17 03:27:01 -08:00
blueprints . push_back ( blueprint ) ;
2009-03-11 15:55:41 -07:00
}
}
}
2012-01-02 11:35:21 -08:00
static void renderBuildOrder ( DroidOrder const & order , STRUCT_STATES state )
2010-10-29 23:15:00 -07:00
{
2011-12-30 08:43:49 -08:00
STRUCTURE_STATS const * stats ;
Vector2i pos = order . pos ;
if ( order . type = = DORDER_BUILDMODULE )
2011-11-18 10:27:46 -08:00
{
2011-12-30 08:43:49 -08:00
STRUCTURE const * structure = castStructure ( order . psObj ) ;
if ( structure = = NULL )
{
return ;
}
2011-11-18 10:27:46 -08:00
stats = getModuleStat ( structure ) ;
2011-12-30 08:43:49 -08:00
pos = removeZ ( structure - > pos ) ;
}
else
{
stats = order . psStats ;
}
if ( stats = = NULL )
{
return ;
2011-11-18 10:27:46 -08:00
}
2011-11-18 08:23:55 -08:00
2010-10-29 23:15:00 -07:00
//draw the current build site if its a line of structures
2011-12-30 08:43:49 -08:00
if ( order . type = = DORDER_LINEBUILD )
2010-10-29 23:15:00 -07:00
{
int left , right , up , down ;
// a wall (or something like that)
2011-12-30 08:43:49 -08:00
left = MIN ( map_coord ( pos . x ) , map_coord ( order . pos2 . x ) ) ;
right = MAX ( map_coord ( pos . x ) , map_coord ( order . pos2 . x ) ) ;
up = MIN ( map_coord ( pos . y ) , map_coord ( order . pos2 . y ) ) ;
down = MAX ( map_coord ( pos . y ) , map_coord ( order . pos2 . y ) ) ;
2010-10-29 23:15:00 -07:00
2011-12-30 08:43:49 -08:00
drawLineBuild ( stats , left , right , up , down , order . direction , state ) ;
2010-10-29 23:15:00 -07:00
}
2012-01-02 11:35:21 -08:00
if ( ( order . type = = DORDER_BUILD | | order . type = = DORDER_BUILDMODULE ) & & ! tileHasIncompatibleStructure ( mapTile ( map_coord ( pos ) ) , stats , order . index ) )
2010-10-29 23:15:00 -07:00
{
2012-01-02 11:35:21 -08:00
Blueprint blueprint ( stats , pos , order . direction , order . index , state ) ;
2011-11-17 03:27:01 -08:00
blueprints . push_back ( blueprint ) ;
2010-10-29 23:15:00 -07:00
}
}
2009-03-11 15:55:41 -07:00
void displayBlueprints ( void )
{
2011-11-17 03:27:01 -08:00
blueprints . clear ( ) ; // Delete old blueprints and draw new ones.
2009-03-11 15:55:41 -07:00
if ( ( buildState = = BUILD3D_VALID | | buildState = = BUILD3D_POS ) & &
sBuildDetails . x > 0 & & sBuildDetails . x < mapWidth & &
sBuildDetails . y > 0 & & sBuildDetails . y < mapHeight )
{
2011-11-17 03:27:01 -08:00
STRUCT_STATES state ;
2009-03-11 15:55:41 -07:00
if ( buildState = = BUILD3D_VALID )
{
state = SS_BLUEPRINT_VALID ;
}
else
{
state = SS_BLUEPRINT_INVALID ;
}
// we are placing a building or a delivery point
if ( sBuildDetails . psStats - > ref > = REF_STRUCTURE_START
& & sBuildDetails . psStats - > ref < ( REF_STRUCTURE_START + REF_RANGE ) )
{
// it's a building
if ( wallDrag . status = = DRAG_PLACING | | wallDrag . status = = DRAG_DRAGGING )
{
int left , right , up , down ;
// a wall (or something like that)
left = MIN ( wallDrag . x1 , wallDrag . x2 ) ;
right = MAX ( wallDrag . x1 , wallDrag . x2 ) ;
up = MIN ( wallDrag . y1 , wallDrag . y2 ) ;
down = MAX ( wallDrag . y1 , wallDrag . y2 ) ;
2011-11-17 03:27:01 -08:00
drawLineBuild ( ( STRUCTURE_STATS * ) sBuildDetails . psStats , left , right , up , down , ( player . r . y + 0x2000 ) & 0xC000 , state ) ;
2009-03-11 15:55:41 -07:00
}
else
{
2010-09-01 16:14:10 -07:00
unsigned width , height ;
if ( ( ( player . r . y + 0x2000 ) & 0x4000 ) = = 0 )
{
width = sBuildDetails . width ;
height = sBuildDetails . height ;
}
else
{
// Rotated 90°, swap width and height
width = sBuildDetails . height ;
height = sBuildDetails . width ;
}
2009-03-11 15:55:41 -07:00
// a single building
2011-11-17 03:27:01 -08:00
Vector2i pos ( world_coord ( sBuildDetails . x ) + world_coord ( width ) / 2 , world_coord ( sBuildDetails . y ) + world_coord ( height ) / 2 ) ;
2012-01-02 11:35:21 -08:00
Blueprint blueprint ( ( STRUCTURE_STATS * ) sBuildDetails . psStats , pos , ( player . r . y + 0x2000 ) & 0xC000 , 0 , state ) ;
2011-11-17 03:27:01 -08:00
blueprints . push_back ( blueprint ) ;
2009-03-11 15:55:41 -07:00
}
}
}
// now we draw the blueprints for all ordered buildings
2011-09-02 03:13:44 -07:00
for ( int player = 0 ; player < MAX_PLAYERS ; + + player )
2009-03-11 15:55:41 -07:00
{
2011-09-02 03:13:44 -07:00
if ( ! hasSharedVision ( selectedPlayer , player ) )
2009-03-11 15:55:41 -07:00
{
2011-09-02 03:13:44 -07:00
continue ;
}
STRUCT_STATES state = player = = selectedPlayer ? SS_BLUEPRINT_PLANNED : SS_BLUEPRINT_PLANNED_BY_ALLY ;
2011-11-17 03:27:01 -08:00
for ( DROID * psDroid = apsDroidLists [ player ] ; psDroid ; psDroid = psDroid - > psNext )
2011-09-02 03:13:44 -07:00
{
if ( psDroid - > droidType = = DROID_CONSTRUCT | | psDroid - > droidType = = DROID_CYBORG_CONSTRUCT )
2009-03-11 15:55:41 -07:00
{
2011-12-30 08:43:49 -08:00
renderBuildOrder ( psDroid - > order , state ) ;
2011-09-02 03:13:44 -07:00
//now look thru' the list of orders to see if more building sites
2011-11-17 03:27:01 -08:00
for ( int order = psDroid - > listPendingBegin ; order < ( int ) psDroid - > asOrderList . size ( ) ; order + + )
2011-09-02 03:13:44 -07:00
{
2011-12-30 08:43:49 -08:00
renderBuildOrder ( psDroid - > asOrderList [ order ] , state ) ;
2011-09-02 03:13:44 -07:00
}
2009-03-11 15:55:41 -07:00
}
}
}
2011-11-17 03:27:01 -08:00
// Erase duplicate blueprints.
std : : sort ( blueprints . begin ( ) , blueprints . end ( ) ) ;
blueprints . erase ( std : : unique ( blueprints . begin ( ) , blueprints . end ( ) ) , blueprints . end ( ) ) ;
// Actually render everything.
for ( std : : vector < Blueprint > : : iterator blueprint = blueprints . begin ( ) ; blueprint ! = blueprints . end ( ) ; + + blueprint )
{
blueprint - > renderBlueprint ( ) ;
}
2012-06-21 15:34:04 -07:00
renderDeliveryRepos ( ) ;
2009-03-11 15:55:41 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draw Factory Delivery Points
2013-10-05 04:37:53 -07:00
static void displayDelivPoints ( )
2007-06-28 10:47:08 -07:00
{
2013-02-09 12:30:21 -08:00
for ( FLAG_POSITION * psDelivPoint = apsFlagPosLists [ selectedPlayer ] ; psDelivPoint ! = NULL ; psDelivPoint = psDelivPoint - > psNext )
2007-06-28 10:47:08 -07:00
{
if ( clipXY ( psDelivPoint - > coords . x , psDelivPoint - > coords . y ) )
{
2009-03-11 15:55:41 -07:00
renderDeliveryPoint ( psDelivPoint , false ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2008-11-10 14:50:08 -08:00
/// Draw the features
2013-10-05 04:37:53 -07:00
static void displayFeatures ( )
2007-06-28 10:47:08 -07:00
{
2011-12-28 05:42:41 -08:00
// player can only be 0 for the features.
for ( unsigned player = 0 ; player < = 1 ; + + player )
{
BASE_OBJECT * list = player < 1 ? apsFeatureLists [ player ] : psDestroyedObj ;
2007-06-28 10:47:08 -07:00
/* Go through all the features */
2011-12-28 05:42:41 -08:00
for ( ; list ! = NULL ; list = list - > psNext )
2007-06-28 10:47:08 -07:00
{
2013-03-01 12:15:59 -08:00
if ( list - > type = = OBJ_FEATURE
& & ( list - > died = = 0 | | list - > died > graphicsTime )
& & clipXY ( list - > pos . x , list - > pos . y ) )
2007-06-28 10:47:08 -07:00
{
2013-03-01 12:15:59 -08:00
FEATURE * psFeature = castFeature ( list ) ;
2007-04-05 08:24:03 -07:00
renderFeature ( psFeature ) ;
2007-04-15 13:45:09 -07:00
}
2007-06-28 10:47:08 -07:00
}
2011-12-28 05:42:41 -08:00
}
2007-04-15 13:45:09 -07:00
}
2007-06-28 10:47:08 -07:00
2008-11-10 14:50:08 -08:00
/// Draw the Proximity messages for the *SELECTED PLAYER ONLY*
2013-10-05 04:37:53 -07:00
static void displayProximityMsgs ( )
2007-06-28 10:47:08 -07:00
{
PROXIMITY_DISPLAY * psProxDisp ;
VIEW_PROXIMITY * pViewProximity ;
UDWORD x , y ;
/* Go through all the proximity Displays*/
2013-10-05 04:37:53 -07:00
for ( psProxDisp = apsProxDisp [ selectedPlayer ] ; psProxDisp ! = NULL ; psProxDisp = psProxDisp - > psNext )
2007-06-28 10:47:08 -07:00
{
2007-04-15 13:45:09 -07:00
if ( ! ( psProxDisp - > psMessage - > read ) )
2007-06-28 10:47:08 -07:00
{
if ( psProxDisp - > type = = POS_PROXDATA )
{
pViewProximity = ( VIEW_PROXIMITY * ) ( ( VIEWDATA * ) psProxDisp - > psMessage - >
pViewData ) - > pData ;
x = pViewProximity - > x ;
y = pViewProximity - > y ;
}
else
{
2011-05-01 02:24:24 -07:00
if ( ! psProxDisp - > psMessage - > pViewData ) continue ; // sanity check
2007-12-15 07:39:29 -08:00
x = ( ( BASE_OBJECT * ) psProxDisp - > psMessage - > pViewData ) - > pos . x ;
y = ( ( BASE_OBJECT * ) psProxDisp - > psMessage - > pViewData ) - > pos . y ;
2007-06-28 10:47:08 -07:00
}
/* Is the Message worth rendering? */
if ( clipXY ( x , y ) )
{
2007-04-05 08:24:03 -07:00
renderProximityMsg ( psProxDisp ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
2008-11-10 14:50:08 -08:00
/// Display an animation
2011-03-12 17:32:15 -08:00
static void displayAnimation ( ANIM_OBJECT * psAnimObj , bool bHoldOnFirstFrame )
2007-06-28 10:47:08 -07:00
{
2007-06-02 16:01:29 -07:00
UWORD i , uwFrame ;
Vector3i vecPos , vecRot , vecScale ;
COMPONENT_OBJECT * psComp ;
2007-06-28 10:47:08 -07:00
2007-06-02 16:01:29 -07:00
for ( i = 0 ; i < psAnimObj - > psAnim - > uwObj ; i + + )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
if ( bHoldOnFirstFrame = = true )
2007-06-28 10:47:08 -07:00
{
uwFrame = 0 ;
vecPos . x = vecPos . y = vecPos . z = 0 ;
vecRot . x = vecRot . y = vecRot . z = 0 ;
vecScale . x = vecScale . y = vecScale . z = 0 ;
}
else
{
2010-02-06 09:07:52 -08:00
uwFrame = anim_GetFrame3D ( psAnimObj - > psAnim , i , graphicsTime , psAnimObj - > udwStartTime , psAnimObj - > udwStartDelay , & vecPos , & vecRot , & vecScale ) ;
2007-06-28 10:47:08 -07:00
}
if ( uwFrame ! = ANIM_DELAYED )
{
if ( psAnimObj - > psAnim - > animType = = ANIM_3D_TRANS )
{
psComp = & psAnimObj - > apComponents [ i ] ;
}
else
{
psComp = & psAnimObj - > apComponents [ uwFrame ] ;
}
psComp - > position . x = vecPos . x ;
psComp - > position . y = vecPos . y ;
psComp - > position . z = vecPos . z ;
psComp - > orientation . x = vecRot . x ;
psComp - > orientation . y = vecRot . y ;
psComp - > orientation . z = vecRot . z ;
2007-07-23 04:30:26 -07:00
bucketAddTypeToList ( RENDER_ANIMATION , psComp ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2008-11-10 14:50:08 -08:00
/// Draw the droids
2013-10-05 04:37:53 -07:00
static void displayDynamicObjects ( )
2007-06-28 10:47:08 -07:00
{
ANIM_OBJECT * psAnimObj ;
/* Need to go through all the droid lists */
2011-12-28 05:42:41 -08:00
for ( unsigned player = 0 ; player < = MAX_PLAYERS ; + + player )
2007-06-28 10:47:08 -07:00
{
2011-12-28 05:42:41 -08:00
BASE_OBJECT * list = player < MAX_PLAYERS ? apsDroidLists [ player ] : psDestroyedObj ;
for ( ; list ! = NULL ; list = list - > psNext )
2007-06-28 10:47:08 -07:00
{
2013-03-01 12:15:59 -08:00
if ( list - > type ! = OBJ_DROID
| | ( list - > died ! = 0 & & list - > died < graphicsTime )
| | ! clipXY ( list - > pos . x , list - > pos . y ) )
{
continue ;
}
2011-12-28 05:42:41 -08:00
DROID * psDroid = castDroid ( list ) ;
2013-03-01 12:15:59 -08:00
/* No point in adding it if you can't see it? */
if ( psDroid - > visible [ selectedPlayer ] )
{
2007-04-15 13:45:09 -07:00
psDroid - > sDisplay . frameNumber = currentGameFrame ;
2008-05-09 11:24:20 -07:00
// NOTE! : anything that has multiple (anim) frames *must* use the bucket to render
// In this case, AFAICT only DROID_CYBORG_SUPER had the issue. (Same issue as oil pump anim)
if ( psDroid - > droidType ! = DROID_CYBORG_SUPER )
{
2013-10-05 04:37:53 -07:00
displayComponentObject ( psDroid ) ;
2008-05-09 11:24:20 -07:00
}
else
2008-06-12 13:11:36 -07:00
{
2008-05-09 11:24:20 -07:00
bucketAddTypeToList ( RENDER_DROID , psDroid ) ;
}
2007-04-05 08:24:03 -07:00
/* draw anim if visible */
if ( psDroid - > psCurAnim ! = NULL & &
2008-03-24 09:51:17 -07:00
psDroid - > psCurAnim - > bVisible = = true & &
2007-04-15 13:45:09 -07:00
( psAnimObj = animObj_Find ( psDroid ,
psDroid - > psCurAnim - > uwID ) ) ! = NULL )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
displayAnimation ( psAnimObj , false ) ;
2007-06-28 10:47:08 -07:00
}
2013-03-01 12:15:59 -08:00
}
2007-06-28 10:47:08 -07:00
} // end for
} // end for clan
} // end Fn
2008-11-10 14:50:08 -08:00
/// Sets the player's position and view angle - defaults player rotations as well
2011-03-12 17:32:15 -08:00
void setViewPos ( UDWORD x , UDWORD y , WZ_DECL_UNUSED bool Pan )
2007-06-28 10:47:08 -07:00
{
2011-04-30 09:41:50 -07:00
player . p . x = world_coord ( x ) ;
player . p . z = world_coord ( y ) ;
2007-06-28 10:47:08 -07:00
player . r . z = 0 ;
if ( getWarCamStatus ( ) )
{
camToggleStatus ( ) ;
}
scroll ( ) ;
}
2008-11-10 14:50:08 -08:00
/// Get the player position
2011-01-04 06:48:00 -08:00
Vector2i getPlayerPos ( )
2007-06-28 10:47:08 -07:00
{
2011-04-30 09:41:50 -07:00
return removeZ ( swapYZ ( player . p ) ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Set the player position
2007-06-28 10:47:08 -07:00
void setPlayerPos ( SDWORD x , SDWORD y )
{
2013-10-05 04:37:53 -07:00
ASSERT ( x > = 0 & & x < world_coord ( mapWidth ) & & y > = 0 & & y < world_coord ( mapHeight ) , " Position off map " ) ;
2011-04-30 09:41:50 -07:00
player . p . x = x ;
player . p . z = y ;
2007-06-28 10:47:08 -07:00
player . r . z = 0 ;
}
2008-11-10 14:50:08 -08:00
/// Get the distance at which the player views the world
2012-12-09 12:16:51 -08:00
float getViewDistance ( void )
2007-06-28 10:47:08 -07:00
{
return distance ;
}
2008-11-10 14:50:08 -08:00
/// Set the distance at which the player views the world
2012-12-09 12:16:51 -08:00
void setViewDistance ( float dist )
2007-06-28 10:47:08 -07:00
{
2011-01-07 06:29:45 -08:00
distance = dist ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draw a feature (tree/rock/etc.)
2007-06-28 10:47:08 -07:00
void renderFeature ( FEATURE * psFeature )
{
2011-04-25 03:29:26 -07:00
SDWORD rotation ;
2013-10-05 04:37:53 -07:00
PIELIGHT brightness = pal_SetBrightness ( 200 ) ;
2007-03-24 15:53:18 -07:00
Vector3i dv ;
2013-10-05 04:37:53 -07:00
bool bForceDraw = ( getRevealStatus ( ) & & psFeature - > psStats - > visibleAtStart ) ;
int pieFlags = 0 ;
2007-06-28 10:47:08 -07:00
2012-11-16 05:16:59 -08:00
if ( ! psFeature - > visible [ selectedPlayer ] & & ! bForceDraw )
2007-06-28 10:47:08 -07:00
{
2008-06-30 10:07:41 -07:00
return ;
}
2007-06-28 10:47:08 -07:00
2008-06-30 10:07:41 -07:00
/* Mark it as having been drawn */
psFeature - > sDisplay . frameNumber = currentGameFrame ;
2007-06-28 10:47:08 -07:00
2013-10-05 04:37:53 -07:00
/* Daft hack to get around the oil derrick issue */
2010-12-21 12:51:29 -08:00
if ( ! TileHasFeature ( mapTile ( map_coord ( removeZ ( psFeature - > pos ) ) ) ) )
2008-06-30 10:07:41 -07:00
{
return ;
}
2007-06-28 10:47:08 -07:00
2010-12-21 12:51:29 -08:00
dv = Vector3i (
2011-04-30 09:41:50 -07:00
psFeature - > pos . x - player . p . x ,
2010-12-21 12:51:29 -08:00
psFeature - > pos . z , // features sits at the height of the tile it's centre is on
2011-04-30 09:41:50 -07:00
- ( psFeature - > pos . y - player . p . z )
2008-06-30 10:07:41 -07:00
) ;
2007-06-28 10:47:08 -07:00
2008-06-30 10:07:41 -07:00
/* Push the indentity matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2007-06-28 10:47:08 -07:00
2008-06-30 10:07:41 -07:00
/* Translate the feature - N.B. We can also do rotations here should we require
buildings to face different ways - Don ' t know if this is necessary - should be IMO */
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
2010-02-28 15:14:52 -08:00
rotation = psFeature - > rot . direction ;
2007-06-28 10:47:08 -07:00
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - rotation ) ;
2007-12-09 08:09:23 -08:00
2008-06-30 10:07:41 -07:00
if ( psFeature - > psStats - > subType = = FEAT_SKYSCRAPER )
{
objectShimmy ( ( BASE_OBJECT * ) psFeature ) ;
}
2007-05-21 07:06:31 -07:00
2013-10-05 04:37:53 -07:00
if ( ! getRevealStatus ( ) )
2008-06-30 10:07:41 -07:00
{
brightness = pal_SetBrightness ( avGetObjLightLevel ( ( BASE_OBJECT * ) psFeature , brightness . byte . r ) ) ;
}
2010-01-18 14:11:33 -08:00
if ( ! hasSensorOnTile ( mapTile ( map_coord ( psFeature - > pos . x ) , map_coord ( psFeature - > pos . y ) ) , selectedPlayer ) )
2010-01-18 08:52:33 -08:00
{
brightness . byte . r / = 2 ;
brightness . byte . g / = 2 ;
brightness . byte . b / = 2 ;
}
2007-05-21 07:06:31 -07:00
2008-06-30 10:07:41 -07:00
if ( psFeature - > psStats - > subType = = FEAT_BUILDING
| | psFeature - > psStats - > subType = = FEAT_SKYSCRAPER
| | psFeature - > psStats - > subType = = FEAT_OIL_DRUM )
{
/* these cast a shadow */
2013-10-05 04:37:53 -07:00
pieFlags = pie_STATIC_SHADOW ;
2008-06-30 10:07:41 -07:00
}
2007-06-28 10:47:08 -07:00
2013-10-05 04:37:53 -07:00
pie_Draw3DShape ( psFeature - > sDisplay . imd , 0 , 0 , brightness , pieFlags , 0 ) ;
2008-06-30 10:07:41 -07:00
2013-02-24 02:36:14 -08:00
setScreenDisp ( & psFeature - > sDisplay ) ;
2008-06-30 10:07:41 -07:00
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
void renderProximityMsg ( PROXIMITY_DISPLAY * psProxDisp )
{
UDWORD msgX = 0 , msgY = 0 ;
2010-12-21 12:51:29 -08:00
Vector3i dv ( 0 , 0 , 0 ) ;
2007-06-28 10:47:08 -07:00
VIEW_PROXIMITY * pViewProximity = NULL ;
2011-04-25 03:29:26 -07:00
SDWORD x , y , r ;
2007-06-28 10:47:08 -07:00
iIMDShape * proxImd = NULL ;
//store the frame number for when deciding what has been clicked on
psProxDisp - > frameNumber = currentGameFrame ;
/* Get it's x and y coordinates so we don't have to deref. struct later */
if ( psProxDisp - > type = = POS_PROXDATA )
{
pViewProximity = ( VIEW_PROXIMITY * ) ( ( VIEWDATA * ) psProxDisp - > psMessage - >
pViewData ) - > pData ;
if ( pViewProximity )
{
msgX = pViewProximity - > x ;
msgY = pViewProximity - > y ;
/* message sits at the height specified at input*/
dv . y = pViewProximity - > z + 64 ;
2006-08-30 10:02:58 -07:00
/* in case of a beacon message put above objects */
2008-04-24 13:02:02 -07:00
if ( ( ( VIEWDATA * ) psProxDisp - > psMessage - > pViewData ) - > type = = VIEW_BEACON )
2006-08-30 10:02:58 -07:00
{
* Turn macros TILE_OCCUPIED, TILE_HAS_STRUCTURE, TILE_HAS_FEATURE, TILE_HAS_WALL, TILE_HIGHLIGHT, TILE_HAS_TALLSTRUCTURE and TILE_HAS_SMALLSTRUCTURE into static inline functions TileIsOccupied, TileHasStructure, TileHasFeature, TileHasWall, TileIsHighlighted, TileHasTallStructure and TileHasSmallStructure respectively
* Move the definition of MAPTILE above these ^^ macros and functions to prevent declarations problems
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@4916 4a71c877-e1ca-e34f-864e-861f7616d084
2008-05-04 07:56:33 -07:00
if ( TileIsOccupied ( mapTile ( msgX / TILE_UNITS , msgY / TILE_UNITS ) ) )
2006-08-30 10:02:58 -07:00
dv . y = pViewProximity - > z + 150 ;
}
2007-06-28 10:47:08 -07:00
}
}
else if ( psProxDisp - > type = = POS_PROXOBJ )
{
2007-12-15 07:39:29 -08:00
msgX = ( ( BASE_OBJECT * ) psProxDisp - > psMessage - > pViewData ) - > pos . x ;
msgY = ( ( BASE_OBJECT * ) psProxDisp - > psMessage - > pViewData ) - > pos . y ;
2007-06-28 10:47:08 -07:00
/* message sits at the height specified at input*/
2007-12-15 07:39:29 -08:00
dv . y = ( ( BASE_OBJECT * ) psProxDisp - > psMessage - > pViewData ) - > pos . z + 64 ;
2007-06-28 10:47:08 -07:00
}
else
{
2007-06-14 13:59:04 -07:00
ASSERT ( ! " unknown proximity display message type " , " Buggered proximity message type " ) ;
2007-06-28 10:47:08 -07:00
}
2011-04-30 09:41:50 -07:00
dv . x = msgX - player . p . x ;
dv . z = - ( msgY - player . p . z ) ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
/* Push the indentity matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2007-06-28 10:47:08 -07:00
/* Translate the message */
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
//get the appropriate IMD
if ( pViewProximity )
{
switch ( pViewProximity - > proxType )
{
case PROX_ENEMY :
proxImd = getImdFromIndex ( MI_BLIP_ENEMY ) ;
break ;
case PROX_RESOURCE :
proxImd = getImdFromIndex ( MI_BLIP_RESOURCE ) ;
break ;
case PROX_ARTEFACT :
proxImd = getImdFromIndex ( MI_BLIP_ARTEFACT ) ;
break ;
default :
2007-06-14 13:59:04 -07:00
ASSERT ( ! " unknown proximity display message type " , " Buggered proximity message type " ) ;
2007-06-28 10:47:08 -07:00
break ;
}
}
else
{
//object Proximity displays are for oil resources and artefacts
2011-01-01 04:20:56 -08:00
ASSERT ( ( ( BASE_OBJECT * ) psProxDisp - > psMessage - > pViewData ) - > type = = OBJ_FEATURE , " Invalid object type for proximity display " ) ;
2007-06-28 10:47:08 -07:00
2011-01-01 04:20:56 -08:00
if ( ( ( FEATURE * ) psProxDisp - > psMessage - > pViewData ) - > psStats - > subType = = FEAT_OIL_RESOURCE )
2007-06-28 10:47:08 -07:00
{
//resource
proxImd = getImdFromIndex ( MI_BLIP_RESOURCE ) ;
}
else
{
//artefact
proxImd = getImdFromIndex ( MI_BLIP_ARTEFACT ) ;
}
}
2006-05-27 09:37:17 -07:00
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - player . r . y ) ;
pie_MatRotX ( - player . r . x ) ;
2007-06-28 10:47:08 -07:00
2012-06-09 10:25:01 -07:00
pie_Draw3DShape ( proxImd , getModularScaledGraphicsTime ( proxImd - > animInterval , proxImd - > numFrames ) , 0 , WZCOL_WHITE , pie_ADDITIVE , 192 ) ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
//get the screen coords for determining when clicked on
calcFlagPosScreenCoords ( & x , & y , & r ) ;
psProxDisp - > screenX = x ;
2007-02-21 14:38:52 -08:00
psProxDisp - > screenY = y ;
psProxDisp - > screenR = r ;
2007-06-28 10:47:08 -07:00
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
2009-03-11 15:55:41 -07:00
static PIELIGHT getBlueprintColour ( STRUCT_STATES state )
{
switch ( state )
{
case SS_BLUEPRINT_VALID :
return WZCOL_BLUEPRINT_VALID ;
case SS_BLUEPRINT_INVALID :
return WZCOL_BLUEPRINT_INVALID ;
case SS_BLUEPRINT_PLANNED :
return WZCOL_BLUEPRINT_PLANNED ;
2011-09-02 03:13:44 -07:00
case SS_BLUEPRINT_PLANNED_BY_ALLY :
return WZCOL_BLUEPRINT_PLANNED_BY_ALLY ;
2009-03-11 15:55:41 -07:00
default :
debug ( LOG_ERROR , " this is not a blueprint " ) ;
return WZCOL_WHITE ;
}
}
2010-12-05 07:17:26 -08:00
2008-11-10 14:50:08 -08:00
/// Draw the structures
2007-02-21 14:38:52 -08:00
void renderStructure ( STRUCTURE * psStructure )
2007-06-28 10:47:08 -07:00
{
2011-10-16 12:01:58 -07:00
int i , structX , structY , colour , rotation , frame , animFrame , pieFlag , pieFlagData , ecmFlag = 0 ;
2007-12-21 09:14:18 -08:00
PIELIGHT buildingBrightness ;
Vector3i dv ;
2011-03-12 17:32:15 -08:00
bool bHitByElectronic = false ;
bool defensive = false ;
2007-12-21 09:14:18 -08:00
iIMDShape * strImd = psStructure - > sDisplay . imd ;
2011-10-16 12:01:58 -07:00
MAPTILE * psTile = worldTile ( psStructure - > pos . x , psStructure - > pos . y ) ;
2007-02-21 14:38:52 -08:00
2010-02-18 11:35:37 -08:00
if ( psStructure - > pStructureType - > type = = REF_WALL | | psStructure - > pStructureType - > type = = REF_WALLCORNER
| | psStructure - > pStructureType - > type = = REF_GATE )
2007-02-21 14:38:52 -08:00
{
renderWallSection ( psStructure ) ;
return ;
}
2011-12-03 09:35:39 -08:00
// If the structure is not truly visible, but we know there is something there, we will instead draw a blip
2012-11-16 05:16:59 -08:00
if ( psStructure - > visible [ selectedPlayer ] < UBYTE_MAX & & psStructure - > visible [ selectedPlayer ] > 0 )
2011-10-16 12:01:58 -07:00
{
dv . x = psStructure - > pos . x - player . p . x ;
dv . z = - ( psStructure - > pos . y - player . p . z ) ;
dv . y = psStructure - > pos . z ;
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2011-10-16 12:01:58 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2011-12-26 19:04:42 -08:00
int frame = graphicsTime / BLIP_ANIM_DURATION + psStructure - > id % 8192 ; // de-sync the blip effect, but don't overflow the int
2011-10-16 12:01:58 -07:00
pie_Draw3DShape ( getImdFromIndex ( MI_BLIP ) , frame , 0 , WZCOL_WHITE , pie_ADDITIVE , psStructure - > visible [ selectedPlayer ] / 2 ) ;
pie_MatEnd ( ) ;
return ;
}
2012-11-16 05:16:59 -08:00
else if ( ! psStructure - > visible [ selectedPlayer ] )
2007-12-01 11:05:38 -08:00
{
return ;
}
else if ( psStructure - > pStructureType - > type = = REF_DEFENSE )
2007-02-21 14:38:52 -08:00
{
2008-03-24 09:51:17 -07:00
defensive = true ;
2007-02-21 14:38:52 -08:00
}
2006-05-27 09:37:17 -07:00
2011-10-16 12:01:58 -07:00
if ( psTile - > jammerBits & alliancebits [ psStructure - > player ] )
{
ecmFlag = pie_ECM ;
}
2010-02-04 01:26:25 -08:00
colour = getPlayerColour ( psStructure - > player ) ;
animFrame = 0 ;
2007-02-21 14:38:52 -08:00
2012-06-02 13:37:21 -07:00
if ( strImd - > numFrames > 0 )
2007-12-01 11:05:38 -08:00
{
2010-02-04 01:26:25 -08:00
// Calculate an animation frame
2012-06-09 10:25:01 -07:00
animFrame = getModularScaledGraphicsTime ( strImd - > animInterval , strImd - > numFrames ) ;
2007-02-21 14:38:52 -08:00
}
2007-04-15 13:45:09 -07:00
// -------------------------------------------------------------------------------
2007-02-21 14:38:52 -08:00
2007-12-01 11:05:38 -08:00
/* Mark it as having been drawn */
psStructure - > sDisplay . frameNumber = currentGameFrame ;
2007-02-21 14:38:52 -08:00
2007-12-01 11:05:38 -08:00
/* Get it's x and y coordinates so we don't have to deref. struct later */
2007-12-15 07:39:29 -08:00
structX = psStructure - > pos . x ;
structY = psStructure - > pos . y ;
2007-02-21 14:38:52 -08:00
2011-04-30 09:41:50 -07:00
dv . x = structX - player . p . x ;
dv . z = - ( structY - player . p . z ) ;
2012-03-13 08:21:28 -07:00
dv . y = psStructure - > pos . z ;
2007-12-01 11:05:38 -08:00
/* Push the indentity matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2007-06-28 10:47:08 -07:00
2007-12-01 11:05:38 -08:00
/* Translate the building - N.B. We can also do rotations here should we require
buildings to face different ways - Don ' t know if this is necessary - should be IMO */
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-12-01 09:49:45 -08:00
2007-12-01 11:05:38 -08:00
/* OK - here is where we establish which IMD to draw for the building - luckily static objects,
* buildings in other words are NOT made up of components - much quicker ! */
2007-02-21 14:38:52 -08:00
2010-02-28 15:14:52 -08:00
rotation = psStructure - > rot . direction ;
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - rotation ) ;
2007-12-01 11:05:38 -08:00
if ( ! defensive
2011-12-26 19:04:42 -08:00
& & graphicsTime - psStructure - > timeLastHit < ELEC_DAMAGE_DURATION
2007-12-01 11:05:38 -08:00
& & psStructure - > lastHitWeapon = = WSC_ELECTRONIC )
{
2008-03-24 09:51:17 -07:00
bHitByElectronic = true ;
2007-12-01 11:05:38 -08:00
}
2006-05-27 09:37:17 -07:00
2010-01-28 06:50:18 -08:00
buildingBrightness = structureBrightness ( psStructure ) ;
2007-02-21 14:38:52 -08:00
2007-12-01 11:05:38 -08:00
if ( ! defensive )
{
/* Draw the building's base first */
2007-12-21 09:14:18 -08:00
if ( psStructure - > pStructureType - > pBaseIMD ! = NULL )
2007-12-01 11:05:38 -08:00
{
2009-03-11 15:55:41 -07:00
if ( structureIsBlueprint ( psStructure ) )
{
pieFlag = pie_TRANSLUCENT ;
2009-09-28 11:19:55 -07:00
pieFlagData = BLUEPRINT_OPACITY ;
2009-03-11 15:55:41 -07:00
}
else
{
2013-01-19 13:24:49 -08:00
pieFlag = pie_TRANSLUCENT | pie_FORCE_FOG | ecmFlag ;
2009-04-07 02:43:32 -07:00
pieFlagData = 255 ;
2009-03-11 15:55:41 -07:00
}
2011-02-25 13:49:02 -08:00
pie_Draw3DShape ( psStructure - > pStructureType - > pBaseIMD , 0 , colour , buildingBrightness , pieFlag , pieFlagData ) ;
2007-12-01 11:05:38 -08:00
}
2007-04-15 13:45:09 -07:00
2007-12-01 11:05:38 -08:00
// override
if ( bHitByElectronic )
{
2007-12-08 16:33:03 -08:00
buildingBrightness = pal_SetBrightness ( 150 ) ;
2007-12-01 11:05:38 -08:00
}
2008-01-10 14:18:20 -08:00
}
2007-04-15 13:45:09 -07:00
2008-01-10 14:18:20 -08:00
if ( bHitByElectronic )
{
objectShimmy ( ( BASE_OBJECT * ) psStructure ) ;
2007-12-01 11:05:38 -08:00
}
2007-06-28 10:47:08 -07:00
2007-12-01 11:05:38 -08:00
//first check if partially built - ANOTHER HACK!
2012-03-16 10:24:35 -07:00
if ( psStructure - > status = = SS_BEING_BUILT )
2007-12-01 11:05:38 -08:00
{
2011-12-01 04:33:31 -08:00
if ( psStructure - > prebuiltImd ! = NULL )
{
// strImd is a module, so render the already-built part at full height.
pie_Draw3DShape ( psStructure - > prebuiltImd , 0 , colour , buildingBrightness , pie_SHADOW , 0 ) ;
}
2011-02-25 13:49:02 -08:00
pie_Draw3DShape ( strImd , 0 , colour , buildingBrightness , pie_HEIGHT_SCALED | pie_SHADOW , structHeightScale ( psStructure ) * pie_RAISE_SCALE ) ;
2013-02-24 02:36:14 -08:00
setScreenDisp ( & psStructure - > sDisplay ) ;
pie_MatEnd ( ) ;
return ;
2007-12-01 11:05:38 -08:00
}
2013-02-24 02:36:14 -08:00
2009-03-11 15:55:41 -07:00
if ( structureIsBlueprint ( psStructure ) )
{
pieFlag = pie_TRANSLUCENT ;
pieFlagData = BLUEPRINT_OPACITY ;
}
else
{
2011-10-16 12:01:58 -07:00
pieFlag = pie_STATIC_SHADOW | ecmFlag ;
2009-03-11 15:55:41 -07:00
pieFlagData = 0 ;
}
2010-12-29 01:57:38 -08:00
if ( defensive & & ! structureIsBlueprint ( psStructure ) & & ! ( strImd - > flags & iV_IMD_NOSTRETCH ) )
2007-12-01 11:05:38 -08:00
{
2010-12-05 07:17:26 -08:00
pie_SetShaderStretchDepth ( psStructure - > pos . z - psStructure - > foundationDepth ) ;
2007-12-01 11:05:38 -08:00
}
2011-02-25 13:49:02 -08:00
pie_Draw3DShape ( strImd , animFrame , colour , buildingBrightness , pieFlag , pieFlagData ) ;
2010-12-05 07:17:26 -08:00
pie_SetShaderStretchDepth ( 0 ) ;
2007-12-01 11:05:38 -08:00
2013-03-01 12:15:59 -08:00
// If no weapons, we are done
if ( psStructure - > sDisplay . imd - > nconnectors = = 0 )
2007-12-01 11:05:38 -08:00
{
2013-03-01 12:15:59 -08:00
setScreenDisp ( & psStructure - > sDisplay ) ;
pie_MatEnd ( ) ;
return ;
}
2007-12-01 11:05:38 -08:00
iIMDShape * mountImd [ STRUCT_MAXWEAPS ] ;
iIMDShape * weaponImd [ STRUCT_MAXWEAPS ] ;
iIMDShape * flashImd [ STRUCT_MAXWEAPS ] ;
2010-12-05 07:17:26 -08:00
2007-12-01 11:05:38 -08:00
for ( i = 0 ; i < STRUCT_MAXWEAPS ; i + + )
2007-04-29 05:38:21 -07:00
{
2007-12-01 11:05:38 -08:00
weaponImd [ i ] = NULL ; //weapon is gun ecm or sensor
mountImd [ i ] = NULL ;
flashImd [ i ] = NULL ;
2007-02-21 14:38:52 -08:00
}
2007-12-01 11:05:38 -08:00
//get an imd to draw on the connector priority is weapon, ECM, sensor
//check for weapon
2010-01-18 01:57:43 -08:00
for ( i = 0 ; i < MAX ( 1 , psStructure - > numWeaps ) ; i + + )
2007-06-28 10:47:08 -07:00
{
2010-01-18 01:57:43 -08:00
if ( psStructure - > asWeaps [ i ] . nStat > 0 )
2007-06-28 10:47:08 -07:00
{
2010-02-04 01:26:25 -08:00
const int nWeaponStat = psStructure - > asWeaps [ i ] . nStat ;
2010-01-18 01:57:43 -08:00
weaponImd [ i ] = asWeaponStats [ nWeaponStat ] . pIMD ;
mountImd [ i ] = asWeaponStats [ nWeaponStat ] . pMountGraphic ;
flashImd [ i ] = asWeaponStats [ nWeaponStat ] . pMuzzleGraphic ;
2007-06-28 10:47:08 -07:00
}
2007-12-01 11:05:38 -08:00
}
2007-06-28 10:47:08 -07:00
2010-01-18 01:57:43 -08:00
// check for ECM
if ( weaponImd [ 0 ] = = NULL & & psStructure - > pStructureType - > pECM ! = NULL )
2007-12-01 11:05:38 -08:00
{
2010-01-18 01:57:43 -08:00
weaponImd [ 0 ] = psStructure - > pStructureType - > pECM - > pIMD ;
mountImd [ 0 ] = psStructure - > pStructureType - > pECM - > pMountGraphic ;
flashImd [ 0 ] = NULL ;
2009-10-06 12:15:29 -07:00
}
2010-01-18 01:57:43 -08:00
// check for sensor (or repair center)
2011-12-27 02:27:30 -08:00
bool noRecoil = false ;
2010-01-18 01:57:43 -08:00
if ( weaponImd [ 0 ] = = NULL & & psStructure - > pStructureType - > pSensor ! = NULL )
2009-10-06 12:15:29 -07:00
{
2010-01-18 01:57:43 -08:00
weaponImd [ 0 ] = psStructure - > pStructureType - > pSensor - > pIMD ;
/* No recoil for sensors */
2011-12-27 02:27:30 -08:00
noRecoil = true ;
2010-01-18 01:57:43 -08:00
mountImd [ 0 ] = psStructure - > pStructureType - > pSensor - > pMountGraphic ;
flashImd [ 0 ] = NULL ;
2007-12-01 11:05:38 -08:00
}
2010-01-18 01:57:43 -08:00
2009-03-11 15:55:41 -07:00
// flags for drawing weapons
if ( structureIsBlueprint ( psStructure ) )
{
pieFlag = pie_TRANSLUCENT ;
pieFlagData = BLUEPRINT_OPACITY ;
}
else
{
2011-10-16 12:01:58 -07:00
pieFlag = pie_SHADOW | ecmFlag ;
2009-03-11 15:55:41 -07:00
pieFlagData = 0 ;
}
2007-06-28 10:47:08 -07:00
2007-12-01 11:05:38 -08:00
// draw Weapon / ECM / Sensor for structure
for ( i = 0 ; i < psStructure - > numWeaps | | i = = 0 ; i + + )
{
2010-02-28 15:14:52 -08:00
Rotation rot = structureGetInterpolatedWeaponRotation ( psStructure , i , graphicsTime ) ;
2007-12-01 11:05:38 -08:00
if ( weaponImd [ i ] ! = NULL )
2007-06-28 10:47:08 -07:00
{
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( strImd - > connectors [ i ] . x , strImd - > connectors [ i ] . z , strImd - > connectors [ i ] . y ) ;
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - rot . direction ) ;
2011-12-27 02:27:30 -08:00
int recoilValue = noRecoil ? 0 : getRecoil ( psStructure - > asWeaps [ i ] ) ;
2007-12-01 11:05:38 -08:00
if ( mountImd [ i ] ! = NULL )
{
2011-12-27 02:27:30 -08:00
pie_TRANSLATE ( 0 , 0 , recoilValue / 3 ) ;
2006-11-25 09:38:27 -08:00
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( mountImd [ i ] , animFrame , colour , buildingBrightness , pieFlag , pieFlagData ) ;
2007-12-01 11:05:38 -08:00
if ( mountImd [ i ] - > nconnectors )
{
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( mountImd [ i ] - > connectors - > x , mountImd [ i ] - > connectors - > z , mountImd [ i ] - > connectors - > y ) ;
2007-12-01 11:05:38 -08:00
}
}
2010-10-08 02:04:32 -07:00
pie_MatRotX ( rot . pitch ) ;
2011-12-27 02:27:30 -08:00
pie_TRANSLATE ( 0 , 0 , recoilValue ) ;
2006-11-25 09:38:27 -08:00
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( weaponImd [ i ] , 0 , colour , buildingBrightness , pieFlag , pieFlagData ) ;
2009-12-30 05:18:24 -08:00
if ( psStructure - > status = = SS_BUILT & & psStructure - > visible [ selectedPlayer ] > ( UBYTE_MAX / 2 ) )
2007-12-01 11:05:38 -08:00
{
2009-03-11 15:55:41 -07:00
if ( psStructure - > pStructureType - > type = = REF_REPAIR_FACILITY )
2007-12-01 11:05:38 -08:00
{
2009-03-11 15:55:41 -07:00
REPAIR_FACILITY * psRepairFac = & psStructure - > pFunctionality - > repairFacility ;
// draw repair flash if the Repair Facility has a target which it has started work on
if ( weaponImd [ i ] - > nconnectors & & psRepairFac - > psObj ! = NULL
2009-04-28 15:39:19 -07:00
& & psRepairFac - > psObj - > type = = OBJ_DROID )
2009-03-11 15:55:41 -07:00
{
2009-04-28 15:39:19 -07:00
DROID * psDroid = ( DROID * ) psRepairFac - > psObj ;
SDWORD xdiff , ydiff ;
xdiff = ( SDWORD ) psDroid - > pos . x - ( SDWORD ) psStructure - > pos . x ;
ydiff = ( SDWORD ) psDroid - > pos . y - ( SDWORD ) psStructure - > pos . y ;
if ( xdiff * xdiff + ydiff * ydiff < = ( TILE_UNITS * 5 / 2 ) * ( TILE_UNITS * 5 / 2 ) )
{
iIMDShape * pRepImd ;
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( weaponImd [ i ] - > connectors - > x , weaponImd [ i ] - > connectors - > z - 12 , weaponImd [ i ] - > connectors - > y ) ;
2009-04-28 15:39:19 -07:00
pRepImd = getImdFromIndex ( MI_FLAME ) ;
2010-10-08 02:04:32 -07:00
pie_MatRotY ( rot . direction ) ;
2009-04-28 15:39:19 -07:00
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - player . r . y ) ;
pie_MatRotX ( - player . r . x ) ;
2012-06-09 10:25:01 -07:00
pie_Draw3DShape ( pRepImd , getModularScaledGraphicsTime ( pRepImd - > animInterval , pRepImd - > numFrames ) , colour , buildingBrightness , pie_ADDITIVE , 192 ) ;
2009-04-28 15:39:19 -07:00
2010-10-08 02:04:32 -07:00
pie_MatRotX ( player . r . x ) ;
pie_MatRotY ( player . r . y ) ;
pie_MatRotY ( rot . direction ) ;
2009-04-28 15:39:19 -07:00
}
2009-03-11 15:55:41 -07:00
}
2007-12-01 11:05:38 -08:00
}
2013-10-20 02:45:49 -07:00
else // we have a weapon so we draw a muzzle flash
2007-12-01 11:05:38 -08:00
{
2013-10-20 02:45:49 -07:00
drawMuzzleFlash ( psStructure - > asWeaps [ i ] , weaponImd [ i ] , flashImd [ i ] , buildingBrightness , pieFlag , pieFlagData , colour ) ;
2007-06-28 10:47:08 -07:00
}
2007-12-01 11:05:38 -08:00
}
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
2007-12-01 11:05:38 -08:00
// no IMD, its a baba machine gun, bunker, etc.
else if ( psStructure - > asWeaps [ i ] . nStat > 0 )
2007-06-28 10:47:08 -07:00
{
2009-03-11 15:55:41 -07:00
if ( psStructure - > status = = SS_BUILT )
2007-06-28 10:47:08 -07:00
{
2010-02-04 01:26:25 -08:00
const int nWeaponStat = psStructure - > asWeaps [ i ] . nStat ;
2009-03-11 15:55:41 -07:00
// get an imd to draw on the connector priority is weapon, ECM, sensor
// check for weapon
flashImd [ i ] = asWeaponStats [ nWeaponStat ] . pMuzzleGraphic ;
// draw Weapon/ECM/Sensor for structure
if ( flashImd [ i ] ! = NULL )
2007-06-28 10:47:08 -07:00
{
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2009-03-11 15:55:41 -07:00
// horrendous hack
if ( strImd - > max . y > 80 ) // babatower
2007-06-28 10:47:08 -07:00
{
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( 0 , 80 , 0 ) ;
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - rot . direction ) ;
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( 0 , 0 , - 20 ) ;
2007-06-28 10:47:08 -07:00
}
2009-03-11 15:55:41 -07:00
else //baba bunker
{
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( 0 , 10 , 0 ) ;
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - rot . direction ) ;
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( 0 , 0 , - 40 ) ;
2009-03-11 15:55:41 -07:00
}
2010-10-08 02:04:32 -07:00
pie_MatRotX ( rot . pitch ) ;
2009-12-30 05:18:24 -08:00
// draw the muzzle flash?
2011-05-16 23:05:15 -07:00
if ( psStructure - > visible [ selectedPlayer ] > UBYTE_MAX / 2 )
2007-06-28 10:47:08 -07:00
{
2009-12-30 05:18:24 -08:00
// animate for the duration of the flash only
// assume no clan colours for muzzle effects
if ( flashImd [ i ] - > numFrames = = 0 | | flashImd [ i ] - > animInterval < = 0 )
2009-03-11 15:55:41 -07:00
{
2009-12-30 05:18:24 -08:00
// no anim so display one frame for a fixed time
2011-12-26 19:04:42 -08:00
if ( graphicsTime > = psStructure - > asWeaps [ i ] . lastFired & & graphicsTime < psStructure - > asWeaps [ i ] . lastFired + BASE_MUZZLE_FLASH_DURATION )
2009-12-30 05:18:24 -08:00
{
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( flashImd [ i ] , 0 , colour , buildingBrightness , 0 , 0 ) ; //muzzle flash
2009-12-30 05:18:24 -08:00
}
2009-03-11 15:55:41 -07:00
}
2009-12-30 05:18:24 -08:00
else
2009-03-11 15:55:41 -07:00
{
2010-02-06 09:07:52 -08:00
frame = ( graphicsTime - psStructure - > asWeaps [ i ] . lastFired ) / flashImd [ i ] - > animInterval ;
2010-12-05 07:17:26 -08:00
if ( frame < flashImd [ i ] - > numFrames & & frame > = 0 )
2009-12-30 05:18:24 -08:00
{
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( flashImd [ i ] , 0 , colour , buildingBrightness , 0 , 0 ) ; //muzzle flash
2009-12-30 05:18:24 -08:00
}
2009-03-11 15:55:41 -07:00
}
}
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-12-01 12:24:10 -08:00
// if there is an unused connector, but not the first connector, add a light to it
else if ( psStructure - > sDisplay . imd - > nconnectors > 1 )
2007-12-01 11:05:38 -08:00
{
for ( i = 0 ; i < psStructure - > sDisplay . imd - > nconnectors ; i + + )
{
2007-12-21 09:14:18 -08:00
iIMDShape * lImd ;
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( psStructure - > sDisplay . imd - > connectors - > x , psStructure - > sDisplay . imd - > connectors - > z ,
2007-12-01 11:05:38 -08:00
psStructure - > sDisplay . imd - > connectors - > y ) ;
lImd = getImdFromIndex ( MI_LANDING ) ;
2012-06-09 10:25:01 -07:00
pie_Draw3DShape ( lImd , getModularScaledGraphicsTime ( lImd - > animInterval , lImd - > numFrames ) , colour , buildingBrightness , 0 , 0 ) ;
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-12-01 11:05:38 -08:00
}
}
2007-06-28 10:47:08 -07:00
}
2007-12-01 11:05:38 -08:00
2013-02-24 02:36:14 -08:00
setScreenDisp ( & psStructure - > sDisplay ) ;
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// draw the delivery points
2011-03-12 17:32:15 -08:00
void renderDeliveryPoint ( FLAG_POSITION * psPosition , bool blueprint )
2007-06-28 10:47:08 -07:00
{
2011-04-25 03:29:26 -07:00
Vector3i dv ;
SDWORD x , y , r ;
2009-03-11 15:55:41 -07:00
int pieFlag , pieFlagData ;
PIELIGHT colour ;
2013-01-11 12:49:05 -08:00
2007-06-28 10:47:08 -07:00
//store the frame number for when deciding what has been clicked on
psPosition - > frameNumber = currentGameFrame ;
2011-04-30 09:41:50 -07:00
dv . x = psPosition - > coords . x - player . p . x ;
dv . z = - ( psPosition - > coords . y - player . p . z ) ;
2006-05-27 09:37:17 -07:00
dv . y = psPosition - > coords . z ;
2007-06-28 10:47:08 -07:00
/* Push the indentity matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2007-06-28 10:47:08 -07:00
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
//quick check for invalid data
2011-12-02 12:04:02 -08:00
ASSERT_OR_RETURN ( , psPosition - > factoryType < NUM_FLAG_TYPES & & psPosition - > factoryInc < MAX_FACTORY_FLAG_IMDS , " Invalid assembly point " ) ;
2007-06-28 10:47:08 -07:00
2010-09-19 13:12:40 -07:00
pie_MatScale ( .5f ) ; // they are all big now so make this one smaller too
2007-06-28 10:47:08 -07:00
2010-03-20 20:13:48 -07:00
pieFlag = pie_TRANSLUCENT ;
pieFlagData = BLUEPRINT_OPACITY ;
2009-03-11 15:55:41 -07:00
if ( blueprint )
{
2012-06-21 15:34:04 -07:00
colour = deliveryReposValid ( ) ? WZCOL_BLUEPRINT_VALID : WZCOL_BLUEPRINT_INVALID ;
2009-03-11 15:55:41 -07:00
}
else
{
2010-03-20 20:13:48 -07:00
pieFlag | = pie_FORCE_FOG ;
2009-03-11 15:55:41 -07:00
colour = WZCOL_WHITE ;
}
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( pAssemblyPointIMDs [ psPosition - > factoryType ] [ psPosition - > factoryInc ] , 0 , 0 , colour , pieFlag , pieFlagData ) ;
2007-06-28 10:47:08 -07:00
//get the screen coords for the DP
calcFlagPosScreenCoords ( & x , & y , & r ) ;
psPosition - > screenX = x ;
psPosition - > screenY = y ;
psPosition - > screenR = r ;
2013-02-18 11:00:25 -08:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draw a piece of wall
2011-03-12 17:32:15 -08:00
static bool renderWallSection ( STRUCTURE * psStructure )
2007-06-28 10:47:08 -07:00
{
2012-05-02 11:43:44 -07:00
int structX , structY , ecmFlag = 0 ;
2011-01-01 03:58:14 -08:00
PIELIGHT brightness ;
2007-06-28 10:47:08 -07:00
SDWORD rotation ;
2007-03-16 09:20:16 -07:00
Vector3i dv ;
2009-03-11 15:55:41 -07:00
int pieFlag , pieFlagData ;
2011-10-16 12:01:58 -07:00
MAPTILE * psTile = worldTile ( psStructure - > pos . x , psStructure - > pos . y ) ;
2007-06-28 10:47:08 -07:00
2013-02-24 02:36:14 -08:00
if ( ! psStructure - > visible [ selectedPlayer ] )
2007-06-28 10:47:08 -07:00
{
2013-02-24 02:36:14 -08:00
return false ;
}
2011-10-16 12:01:58 -07:00
if ( psTile - > jammerBits & alliancebits [ psStructure - > player ] )
{
ecmFlag = pie_ECM ;
}
2007-06-28 10:47:08 -07:00
psStructure - > sDisplay . frameNumber = currentGameFrame ;
/* Get it's x and y coordinates so we don't have to deref. struct later */
2007-12-15 07:39:29 -08:00
structX = psStructure - > pos . x ;
structY = psStructure - > pos . y ;
2007-06-28 10:47:08 -07:00
2010-01-28 06:50:18 -08:00
brightness = structureBrightness ( psStructure ) ;
2011-09-25 20:35:55 -07:00
pie_SetShaderStretchDepth ( psStructure - > pos . z - psStructure - > foundationDepth ) ;
2007-06-28 10:47:08 -07:00
/* Establish where it is in the world */
2011-04-30 09:41:50 -07:00
dv . x = structX - player . p . x ;
dv . z = - ( structY - player . p . z ) ;
2012-03-13 08:21:28 -07:00
dv . y = psStructure - > pos . z ;
2007-06-28 10:47:08 -07:00
2012-05-02 05:20:56 -07:00
dv . y - = gateCurrentOpenHeight ( psStructure , graphicsTime , 1 ) ; // Make gate stick out by 1 unit, so that the tops of ┼ gates can safely have heights differing by 1 unit.
2010-02-18 11:35:37 -08:00
2007-06-28 10:47:08 -07:00
/* Push the indentity matrix */
2013-02-18 11:00:25 -08:00
pie_MatBegin ( true ) ;
2007-06-28 10:47:08 -07:00
/* Translate */
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
2010-02-28 15:14:52 -08:00
rotation = psStructure - > rot . direction ;
2010-10-08 02:04:32 -07:00
pie_MatRotY ( - rotation ) ;
2007-05-21 11:57:11 -07:00
2007-06-28 10:47:08 -07:00
/* Actually render it */
2012-03-16 10:24:35 -07:00
if ( psStructure - > status = = SS_BEING_BUILT )
2007-06-28 10:47:08 -07:00
{
2007-12-08 16:33:03 -08:00
pie_Draw3DShape ( psStructure - > sDisplay . imd , 0 , getPlayerColour ( psStructure - > player ) ,
2011-10-16 12:01:58 -07:00
brightness , pie_HEIGHT_SCALED | pie_SHADOW | ecmFlag , structHeightScale ( psStructure ) * pie_RAISE_SCALE ) ;
2007-06-28 10:47:08 -07:00
}
2009-03-11 15:55:41 -07:00
else
2007-06-28 10:47:08 -07:00
{
2009-03-11 15:55:41 -07:00
if ( structureIsBlueprint ( psStructure ) )
2008-01-23 09:03:50 -08:00
{
2009-03-11 15:55:41 -07:00
pieFlag = pie_TRANSLUCENT ;
pieFlagData = BLUEPRINT_OPACITY ;
2008-01-23 09:03:50 -08:00
}
else
{
2010-02-18 11:35:37 -08:00
if ( psStructure - > pStructureType - > type = = REF_WALL | | psStructure - > pStructureType - > type = = REF_GATE )
2009-03-11 15:55:41 -07:00
{
// walls can be rotated, so use a dynamic shadow for them
pieFlag = pie_SHADOW ;
}
else
{
pieFlag = pie_STATIC_SHADOW ;
}
pieFlagData = 0 ;
2008-01-23 09:03:50 -08:00
}
2011-10-16 12:01:58 -07:00
pie_Draw3DShape ( psStructure - > sDisplay . imd , 0 , getPlayerColour ( psStructure - > player ) , brightness , pieFlag | ecmFlag , pieFlagData ) ;
2007-06-28 10:47:08 -07:00
}
2007-03-24 15:53:18 -07:00
2013-02-24 02:36:14 -08:00
setScreenDisp ( & psStructure - > sDisplay ) ;
2007-05-21 07:06:31 -07:00
2011-09-25 20:35:55 -07:00
pie_SetShaderStretchDepth ( 0 ) ;
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
2013-02-24 02:36:14 -08:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draws a shadow under a droid
2007-06-28 10:47:08 -07:00
void renderShadow ( DROID * psDroid , iIMDShape * psShadowIMD )
{
2010-12-29 03:44:18 -08:00
Vector3i dv ;
2007-06-28 10:47:08 -07:00
2011-04-30 09:41:50 -07:00
dv . x = psDroid - > pos . x - player . p . x ;
2012-02-25 16:21:29 -08:00
if ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
dv . x - = bobTransporterHeight ( ) / 2 ;
}
2011-04-30 09:41:50 -07:00
dv . z = - ( psDroid - > pos . y - player . p . z ) ;
2007-12-15 07:39:29 -08:00
dv . y = map_Height ( psDroid - > pos . x , psDroid - > pos . y ) ;
2007-06-28 10:47:08 -07:00
/* Push the indentity matrix */
2010-10-08 02:19:57 -07:00
pie_MatBegin ( ) ;
2007-06-28 10:47:08 -07:00
2010-10-08 02:19:57 -07:00
pie_TRANSLATE ( dv . x , dv . y , dv . z ) ;
2007-06-28 10:47:08 -07:00
2010-12-29 03:44:18 -08:00
pie_MatRotY ( - psDroid - > rot . direction ) ;
pie_MatRotX ( psDroid - > rot . pitch ) ;
pie_MatRotZ ( psDroid - > rot . roll ) ;
2006-05-27 09:37:17 -07:00
2011-01-01 03:58:14 -08:00
pie_Draw3DShape ( psShadowIMD , 0 , 0 , WZCOL_WHITE , pie_TRANSLUCENT , 128 ) ;
2007-06-28 10:47:08 -07:00
2010-10-08 02:19:57 -07:00
pie_MatEnd ( ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draws the strobing 3D drag box that is used for multiple selection
2007-03-16 15:45:30 -07:00
static void drawDragBox ( void )
2007-06-28 10:47:08 -07:00
{
2007-01-07 05:16:02 -08:00
int minX , maxX ; // SHURCOOL: These 4 ints will hold the corners of the selection box
int minY , maxY ;
2007-02-10 08:39:39 -08:00
if ( dragBox3D . status = = DRAG_DRAGGING & & buildState = = BUILD3D_NONE )
2007-06-28 10:47:08 -07:00
{
2010-02-06 09:07:52 -08:00
if ( graphicsTime - dragBox3D . lastTime > BOX_PULSE_SPEED )
2007-06-28 10:47:08 -07:00
{
2007-12-09 08:09:23 -08:00
dragBox3D . pulse + + ;
if ( dragBox3D . pulse > = BOX_PULSE_SIZE )
2007-06-28 10:47:08 -07:00
{
2007-12-09 08:09:23 -08:00
dragBox3D . pulse = 0 ;
2007-06-28 10:47:08 -07:00
}
2010-02-06 09:07:52 -08:00
dragBox3D . lastTime = graphicsTime ;
2007-06-28 10:47:08 -07:00
}
2007-01-07 05:16:02 -08:00
// SHURCOOL: Determine the 4 corners of the selection box, and use them for consistent selection box rendering
2010-03-10 04:31:27 -08:00
minX = MIN ( dragBox3D . x1 , mouseX ( ) ) ;
maxX = MAX ( dragBox3D . x1 , mouseX ( ) ) ;
minY = MIN ( dragBox3D . y1 , mouseY ( ) ) ;
maxY = MAX ( dragBox3D . y1 , mouseY ( ) ) ;
2007-01-07 05:16:02 -08:00
// SHURCOOL: Reduce the box in size to produce a (consistent) pulsing inward effect
2007-12-09 08:09:23 -08:00
minX + = dragBox3D . pulse / 2 ;
maxX - = dragBox3D . pulse / 2 ;
minY + = dragBox3D . pulse / 2 ;
maxY - = dragBox3D . pulse / 2 ;
2007-01-07 05:16:02 -08:00
2007-06-28 10:47:08 -07:00
pie_SetDepthBufferStatus ( DEPTH_CMP_ALWAYS_WRT_OFF ) ;
2007-12-09 08:09:23 -08:00
iV_Box ( minX , minY , maxX , maxY , WZCOL_UNIT_SELECT_BORDER ) ;
2010-01-28 08:27:29 -08:00
pie_UniTransBoxFill ( minX + 1 , minY , maxX , maxY - 1 , WZCOL_UNIT_SELECT_BOX ) ;
2007-06-28 10:47:08 -07:00
pie_SetDepthBufferStatus ( DEPTH_CMP_LEQ_WRT_ON ) ;
}
}
2008-11-10 14:50:08 -08:00
/// Display reload bars for structures and droids
2006-11-04 14:56:28 -08:00
static void drawWeaponReloadBar ( BASE_OBJECT * psObj , WEAPON * psWeap , int weapon_slot )
2007-06-28 10:47:08 -07:00
{
SDWORD scrX , scrY , scrR , scale ;
STRUCTURE * psStruct ;
2007-11-27 13:30:28 -08:00
float mulH ; // display unit resistance instead of reload!
DROID * psDroid ;
2013-01-27 08:50:29 -08:00
int armed , firingStage ;
2007-06-28 10:47:08 -07:00
if ( ctrlShiftDown ( ) & & ( psObj - > type = = OBJ_DROID ) )
2007-04-15 13:45:09 -07:00
{
2007-06-28 10:47:08 -07:00
psDroid = ( DROID * ) psObj ;
scrX = psObj - > sDisplay . screenX ;
scrY = psObj - > sDisplay . screenY ;
scrR = psObj - > sDisplay . screenR ;
scrY + = scrR + 2 ;
2009-11-17 17:45:55 -08:00
if ( weapon_slot ! = 0 ) // only rendering resistance in the first slot
{
return ;
}
2007-06-28 10:47:08 -07:00
if ( psDroid - > resistance )
2007-04-15 13:45:09 -07:00
{
2007-12-22 15:13:05 -08:00
mulH = ( float ) psDroid - > resistance / ( float ) droidResistance ( psDroid ) ;
2007-04-15 13:45:09 -07:00
}
else
{
2007-12-24 05:57:19 -08:00
mulH = 100.f ;
2007-04-15 13:45:09 -07:00
}
2007-12-24 05:57:19 -08:00
firingStage = mulH ;
2006-05-27 09:37:17 -07:00
firingStage = ( ( ( ( 2 * scrR ) * 10000 ) / 100 ) * firingStage ) / 10000 ;
2007-06-28 10:47:08 -07:00
if ( firingStage > = ( UDWORD ) ( 2 * scrR ) )
{
2009-11-17 17:45:55 -08:00
firingStage = ( 2 * scrR ) ;
2007-06-28 10:47:08 -07:00
}
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR - 1 , 3 + scrY + 0 + ( weapon_slot * 2 ) , scrX - scrR + ( 2 * scrR ) + 1 , 3 + scrY + 3 + ( weapon_slot * 2 ) , WZCOL_RELOAD_BACKGROUND ) ;
pie_BoxFill ( scrX - scrR , 3 + scrY + 1 + ( weapon_slot * 2 ) , scrX - scrR + firingStage , 3 + scrY + 2 + ( weapon_slot * 2 ) , WZCOL_HEALTH_RESISTANCE ) ;
2007-06-28 10:47:08 -07:00
return ;
}
2013-01-27 08:50:29 -08:00
armed = droidReloadBar ( psObj , psWeap , weapon_slot ) ;
if ( armed > = 0 & & armed < 100 ) // no need to draw if full
2007-06-28 10:47:08 -07:00
{
scrX = psObj - > sDisplay . screenX ;
scrY = psObj - > sDisplay . screenY ;
scrR = psObj - > sDisplay . screenR ;
switch ( psObj - > type )
{
case OBJ_DROID :
scrY + = scrR + 2 ;
break ;
case OBJ_STRUCTURE :
psStruct = ( STRUCTURE * ) psObj ;
2007-06-19 10:09:30 -07:00
scale = MAX ( psStruct - > pStructureType - > baseWidth , psStruct - > pStructureType - > baseBreadth ) ;
2009-11-17 17:45:55 -08:00
scrY + = scale * 10 ;
2007-06-28 10:47:08 -07:00
scrR = scale * 20 ;
break ;
default :
break ;
}
2013-01-27 08:50:29 -08:00
/* Scale it into an appropriate range */
firingStage = ( ( ( ( 2 * scrR ) * 10000 ) / 100 ) * armed ) / 10000 ;
if ( firingStage > = 2 * scrR )
2007-06-28 10:47:08 -07:00
{
2013-01-27 08:50:29 -08:00
firingStage = ( 2 * scrR ) ;
2007-06-28 10:47:08 -07:00
}
2013-01-27 08:50:29 -08:00
/* Power bars */
pie_BoxFill ( scrX - scrR - 1 , 3 + scrY + 0 + ( weapon_slot * 2 ) , scrX - scrR + ( 2 * scrR ) + 1 , 3 + scrY + 3 + ( weapon_slot * 2 ) , WZCOL_RELOAD_BACKGROUND ) ;
pie_BoxFill ( scrX - scrR , 3 + scrY + 1 + ( weapon_slot * 2 ) , scrX - scrR + firingStage , 3 + scrY + 2 + ( weapon_slot * 2 ) , WZCOL_RELOAD_BAR ) ;
2007-06-28 10:47:08 -07:00
}
}
2009-08-20 10:20:09 -07:00
/// draw target origin icon for the specified structure
2009-09-09 15:23:22 -07:00
static void drawStructureTargetOriginIcon ( STRUCTURE * psStruct , int weapon_slot )
2009-08-20 10:20:09 -07:00
{
SDWORD scrX , scrY , scrR ;
UDWORD scale ;
// Process main weapon only for now
2009-09-09 15:23:22 -07:00
if ( ! tuiTargetOrigin | | weapon_slot | | ! ( ( psStruct - > asWeaps [ weapon_slot ] ) . nStat ) )
2009-08-20 10:20:09 -07:00
{
return ;
}
scale = MAX ( psStruct - > pStructureType - > baseWidth , psStruct - > pStructureType - > baseBreadth ) ;
scrX = psStruct - > sDisplay . screenX ;
scrY = psStruct - > sDisplay . screenY + ( scale * 10 ) ;
scrR = scale * 20 ;
/* Render target origin graphics */
switch ( psStruct - > targetOrigin [ weapon_slot ] )
{
case ORIGIN_VISUAL :
iV_DrawImage ( IntImages , IMAGE_ORIGIN_VISUAL , scrX + scrR + 5 , scrY - 1 ) ;
break ;
case ORIGIN_COMMANDER :
iV_DrawImage ( IntImages , IMAGE_ORIGIN_COMMANDER , scrX + scrR + 5 , scrY - 1 ) ;
break ;
case ORIGIN_SENSOR :
iV_DrawImage ( IntImages , IMAGE_ORIGIN_SENSOR_STANDARD , scrX + scrR + 5 , scrY - 1 ) ;
break ;
case ORIGIN_CB_SENSOR :
iV_DrawImage ( IntImages , IMAGE_ORIGIN_SENSOR_CB , scrX + scrR + 5 , scrY - 1 ) ;
break ;
case ORIGIN_AIRDEF_SENSOR :
iV_DrawImage ( IntImages , IMAGE_ORIGIN_SENSOR_AIRDEF , scrX + scrR + 5 , scrY - 1 ) ;
break ;
case ORIGIN_RADAR_DETECTOR :
iV_DrawImage ( IntImages , IMAGE_ORIGIN_RADAR_DETECTOR , scrX + scrR + 5 , scrY - 1 ) ;
break ;
case ORIGIN_UNKNOWN :
// Do nothing
break ;
default :
debug ( LOG_WARNING , " Unexpected target origin in structure(%d)! " , psStruct - > id ) ;
}
}
2008-12-04 12:56:16 -08:00
/// draw the health bar for the specified structure
static void drawStructureHealth ( STRUCTURE * psStruct )
2007-06-28 10:47:08 -07:00
{
2007-11-27 13:30:28 -08:00
SDWORD scrX , scrY , scrR ;
2009-11-17 17:45:55 -08:00
PIELIGHT powerCol = WZCOL_BLACK , powerColShadow = WZCOL_BLACK ;
2007-11-27 13:30:28 -08:00
UDWORD health , width ;
UDWORD scale ;
2008-12-04 12:56:16 -08:00
scale = MAX ( psStruct - > pStructureType - > baseWidth , psStruct - > pStructureType - > baseBreadth ) ;
width = scale * 20 ;
scrX = psStruct - > sDisplay . screenX ;
scrY = psStruct - > sDisplay . screenY + ( scale * 10 ) ;
scrR = width ;
//health = PERCENT(psStruct->body, psStruct->baseBodyPoints);
if ( ctrlShiftDown ( ) )
{
//show resistance values if CTRL/SHIFT depressed
UDWORD resistance = structureResistance (
psStruct - > pStructureType , psStruct - > player ) ;
if ( resistance )
{
2009-04-15 01:57:09 -07:00
health = PERCENT ( MAX ( 0 , psStruct - > resistance ) , resistance ) ;
2008-12-04 12:56:16 -08:00
}
else
{
health = 100 ;
}
}
else
{
//show body points
2010-11-16 05:48:06 -08:00
health = ( 1. - getStructureDamage ( psStruct ) / 65536.f ) * 100 ;
2011-11-16 07:48:30 -08:00
// If structure is incomplete, make bar correspondingly thinner.
int maxBody = structureBody ( psStruct ) ;
int maxBodyBuilt = structureBodyBuilt ( psStruct ) ;
width = ( uint64_t ) width * maxBodyBuilt / maxBody ;
2008-12-04 12:56:16 -08:00
}
if ( health > REPAIRLEV_HIGH )
{
powerCol = WZCOL_HEALTH_HIGH ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_HIGH_SHADOW ;
2008-12-04 12:56:16 -08:00
}
else if ( health > REPAIRLEV_LOW )
{
powerCol = WZCOL_HEALTH_MEDIUM ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_MEDIUM_SHADOW ;
2008-12-04 12:56:16 -08:00
}
else
{
powerCol = WZCOL_HEALTH_LOW ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_LOW_SHADOW ;
2008-12-04 12:56:16 -08:00
}
health = ( ( ( width * 10000 ) / 100 ) * health ) / 10000 ;
health * = 2 ;
2011-11-16 07:48:30 -08:00
pie_BoxFill ( scrX - scrR - 1 , scrY - 1 , scrX - scrR + 2 * width + 1 , scrY + 3 , WZCOL_RELOAD_BACKGROUND ) ;
2008-12-04 12:56:16 -08:00
pie_BoxFill ( scrX - scrR , scrY , scrX - scrR + health , scrY + 1 , powerCol ) ;
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR , scrY + 1 , scrX - scrR + health , scrY + 2 , powerColShadow ) ;
2008-12-04 12:56:16 -08:00
}
/// draw the construction bar for the specified structure
static void drawStructureBuildProgress ( STRUCTURE * psStruct )
{
SDWORD scrX , scrY , scrR ;
UDWORD health , width ;
UDWORD scale ;
scale = MAX ( psStruct - > pStructureType - > baseWidth , psStruct - > pStructureType - > baseBreadth ) ;
width = scale * 20 ;
scrX = psStruct - > sDisplay . screenX ;
scrY = psStruct - > sDisplay . screenY + ( scale * 10 ) ;
scrR = width ;
health = PERCENT ( psStruct - > currentBuildPts , psStruct - > pStructureType - > buildPoints ) ;
health = ( ( ( width * 10000 ) / 100 ) * health ) / 10000 ;
health * = 2 ;
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR - 1 , scrY - 1 + 5 , scrX + scrR + 1 , scrY + 3 + 5 , WZCOL_RELOAD_BACKGROUND ) ;
2010-01-12 12:05:32 -08:00
pie_BoxFill ( scrX - scrR , scrY + 5 , scrX - scrR + health , scrY + 1 + 5 , WZCOL_HEALTH_MEDIUM_SHADOW ) ;
pie_BoxFill ( scrX - scrR , scrY + 1 + 5 , scrX - scrR + health , scrY + 2 + 5 , WZCOL_HEALTH_MEDIUM ) ;
2008-12-04 12:56:16 -08:00
}
/// Draw the health of structures and show enemy structures being targetted
static void drawStructureSelections ( void )
{
STRUCTURE * psStruct ;
SDWORD scrX , scrY ;
2007-11-27 13:30:28 -08:00
UDWORD i ;
BASE_OBJECT * psClickedOn ;
2011-03-12 17:32:15 -08:00
bool bMouseOverStructure = false ;
bool bMouseOverOwnStructure = false ;
2007-06-28 10:47:08 -07:00
psClickedOn = mouseTarget ( ) ;
2007-02-10 08:39:39 -08:00
if ( psClickedOn ! = NULL & & psClickedOn - > type = = OBJ_STRUCTURE )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bMouseOverStructure = true ;
2007-06-28 10:47:08 -07:00
if ( psClickedOn - > player = = selectedPlayer )
{
2008-03-24 09:51:17 -07:00
bMouseOverOwnStructure = true ;
2007-06-28 10:47:08 -07:00
}
}
pie_SetDepthBufferStatus ( DEPTH_CMP_ALWAYS_WRT_ON ) ;
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( false ) ;
2007-11-27 13:30:28 -08:00
2007-06-28 10:47:08 -07:00
/* Go thru' all the buildings */
for ( psStruct = apsStructLists [ selectedPlayer ] ; psStruct ; psStruct = psStruct - > psNext )
{
2010-12-19 18:35:10 -08:00
if ( clipXY ( psStruct - > pos . x , psStruct - > pos . y ) & & psStruct - > sDisplay . frameNumber = = currentGameFrame )
2007-06-28 10:47:08 -07:00
{
/* If it's selected */
2010-12-19 18:35:10 -08:00
if ( psStruct - > selected | |
( barMode = = BAR_DROIDS_AND_STRUCTURES & & psStruct - > pStructureType - > type ! = REF_WALL & & psStruct - > pStructureType - > type ! = REF_WALLCORNER ) | |
( bMouseOverOwnStructure & & psStruct = = ( STRUCTURE * ) psClickedOn )
)
2007-06-28 10:47:08 -07:00
{
2008-12-04 12:56:16 -08:00
drawStructureHealth ( psStruct ) ;
2007-12-09 06:25:54 -08:00
for ( i = 0 ; i < psStruct - > numWeaps ; i + + )
2007-11-27 13:29:50 -08:00
{
2007-12-09 06:25:54 -08:00
drawWeaponReloadBar ( ( BASE_OBJECT * ) psStruct , & psStruct - > asWeaps [ i ] , i ) ;
2009-09-09 15:23:22 -07:00
drawStructureTargetOriginIcon ( psStruct , i ) ;
2007-11-27 13:29:50 -08:00
}
2007-06-28 10:47:08 -07:00
}
2009-04-03 13:37:36 -07:00
2010-12-19 18:35:10 -08:00
if ( psStruct - > status = = SS_BEING_BUILT )
2007-06-28 10:47:08 -07:00
{
2009-04-03 13:37:36 -07:00
drawStructureBuildProgress ( psStruct ) ;
2007-06-28 10:47:08 -07:00
}
2007-11-26 13:48:36 -08:00
}
2007-06-28 10:47:08 -07:00
}
2010-02-18 13:24:17 -08:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2007-06-28 10:47:08 -07:00
{
2010-02-18 13:24:17 -08:00
if ( i = = selectedPlayer )
2007-06-28 10:47:08 -07:00
{
2010-02-18 13:24:17 -08:00
continue ; // not interesting in our own buildings
}
for ( psStruct = apsStructLists [ i ] ; psStruct ; psStruct = psStruct - > psNext )
{
/* If it's targetted and on-screen */
if ( clipXY ( psStruct - > pos . x , psStruct - > pos . y )
2013-05-21 14:11:28 -07:00
& & ( psStruct - > flags & BASEFLAG_TARGETED )
2010-02-18 13:24:17 -08:00
& & psStruct - > sDisplay . frameNumber = = currentGameFrame )
2007-06-28 10:47:08 -07:00
{
2010-02-18 13:24:17 -08:00
scrX = psStruct - > sDisplay . screenX ;
scrY = psStruct - > sDisplay . screenY - ( psStruct - > sDisplay . imd - > max . y / 4 ) ;
iV_DrawImage ( IntImages , getTargettingGfx ( ) , scrX , scrY ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2009-05-13 16:12:56 -07:00
if ( bMouseOverStructure & & ! bMouseOverOwnStructure )
2007-06-28 10:47:08 -07:00
{
2009-03-12 02:25:29 -07:00
if ( mouseDown ( getRightClickOrders ( ) ? MOUSE_LMB : MOUSE_RMB ) )
2007-06-28 10:47:08 -07:00
{
psStruct = ( STRUCTURE * ) psClickedOn ;
2012-03-16 09:53:17 -07:00
drawStructureHealth ( psStruct ) ;
if ( psStruct - > status = = SS_BEING_BUILT )
2009-05-13 16:12:56 -07:00
{
drawStructureBuildProgress ( psStruct ) ;
}
2007-06-28 10:47:08 -07:00
}
}
pie_SetDepthBufferStatus ( DEPTH_CMP_LEQ_WRT_ON ) ;
}
2007-03-16 15:45:30 -07:00
static UDWORD getTargettingGfx ( void )
2007-06-28 10:47:08 -07:00
{
UDWORD index ;
2010-02-06 09:09:56 -08:00
index = getModularScaledRealTime ( 1000 , 10 ) ;
2007-06-28 10:47:08 -07:00
switch ( index )
{
case 0 :
case 1 :
case 2 :
return ( IMAGE_TARGET1 + index ) ;
break ;
default :
if ( index & 0x01 )
{
return ( IMAGE_TARGET4 ) ;
}
else
{
return ( IMAGE_TARGET5 ) ;
}
break ;
}
}
2008-11-10 14:50:08 -08:00
/// Is the droid, its commander or its sensor tower selected?
2011-03-12 17:32:15 -08:00
bool eitherSelected ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2011-03-12 17:32:15 -08:00
bool retVal ;
2007-06-28 10:47:08 -07:00
BASE_OBJECT * psObj ;
2008-03-24 09:51:17 -07:00
retVal = false ;
2007-06-28 10:47:08 -07:00
if ( psDroid - > selected )
{
2008-03-24 09:51:17 -07:00
retVal = true ;
2007-06-28 10:47:08 -07:00
}
if ( psDroid - > psGroup )
{
if ( psDroid - > psGroup - > psCommander )
{
if ( psDroid - > psGroup - > psCommander - > selected )
{
2008-03-24 09:51:17 -07:00
retVal = true ;
2007-06-28 10:47:08 -07:00
}
}
}
2008-03-11 07:44:03 -07:00
psObj = orderStateObj ( psDroid , DORDER_FIRESUPPORT ) ;
if ( psObj
& & psObj - > selected )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
retVal = true ;
2007-06-28 10:47:08 -07:00
}
2008-03-11 07:44:03 -07:00
return retVal ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draw the selection graphics for selected droids
2007-03-16 15:45:30 -07:00
static void drawDroidSelections ( void )
2007-06-28 10:47:08 -07:00
{
2007-03-16 09:20:16 -07:00
UDWORD scrX , scrY , scrR ;
DROID * psDroid ;
UDWORD damage ;
2009-11-17 17:45:55 -08:00
PIELIGHT powerCol = WZCOL_BLACK , powerColShadow = WZCOL_BLACK ;
2007-11-26 13:48:36 -08:00
PIELIGHT boxCol ;
2007-03-16 09:20:16 -07:00
BASE_OBJECT * psClickedOn ;
2011-03-12 17:32:15 -08:00
bool bMouseOverDroid = false ;
bool bMouseOverOwnDroid = false ;
2007-03-16 09:20:16 -07:00
UDWORD i , index ;
FEATURE * psFeature ;
2007-05-19 14:32:19 -07:00
float mulH ;
2007-06-28 10:47:08 -07:00
psClickedOn = mouseTarget ( ) ;
2007-02-10 08:39:39 -08:00
if ( psClickedOn ! = NULL & & psClickedOn - > type = = OBJ_DROID )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bMouseOverDroid = true ;
2007-02-10 08:39:39 -08:00
if ( psClickedOn - > player = = selectedPlayer & & ! psClickedOn - > selected )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bMouseOverOwnDroid = true ;
2007-06-28 10:47:08 -07:00
}
}
2006-05-27 09:37:17 -07:00
pie_SetDepthBufferStatus ( DEPTH_CMP_ALWAYS_WRT_ON ) ;
2008-03-24 09:51:17 -07:00
pie_SetFogStatus ( false ) ;
2007-06-28 10:47:08 -07:00
for ( psDroid = apsDroidLists [ selectedPlayer ] ; psDroid ; psDroid = psDroid - > psNext )
{
2010-12-19 18:35:10 -08:00
if ( psDroid - > sDisplay . frameNumber ! = currentGameFrame | | ! clipXY ( psDroid - > pos . x , psDroid - > pos . y ) )
{
continue ; // Not visible, anyway. Don't bother with health bars.
}
2013-02-24 02:36:14 -08:00
/* If it's selected and on screen or it's the one the mouse is over */
2010-12-19 18:35:10 -08:00
if ( eitherSelected ( psDroid ) | |
( bMouseOverOwnDroid & & psDroid = = ( DROID * ) psClickedOn ) | |
droidUnderRepair ( psDroid ) | |
barMode = = BAR_DROIDS | | barMode = = BAR_DROIDS_AND_STRUCTURES
)
2007-06-28 10:47:08 -07:00
{
2007-11-26 13:48:36 -08:00
damage = PERCENT ( psDroid - > body , psDroid - > originalBody ) ;
if ( damage > REPAIRLEV_HIGH )
{
powerCol = WZCOL_HEALTH_HIGH ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_HIGH_SHADOW ;
2007-11-26 13:48:36 -08:00
}
else if ( damage > REPAIRLEV_LOW )
{
powerCol = WZCOL_HEALTH_MEDIUM ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_MEDIUM_SHADOW ;
2007-11-26 13:48:36 -08:00
}
else
{
powerCol = WZCOL_HEALTH_LOW ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_LOW_SHADOW ;
2007-11-26 13:48:36 -08:00
}
2007-12-22 15:13:05 -08:00
mulH = ( float ) psDroid - > body / ( float ) psDroid - > originalBody ;
2007-12-24 05:57:19 -08:00
damage = mulH * ( float ) psDroid - > sDisplay . screenR ; // (((psDroid->sDisplay.screenR*10000)/100)*damage)/10000;
2012-06-14 09:30:20 -07:00
if ( damage > psDroid - > sDisplay . screenR )
2013-02-24 02:36:14 -08:00
{
2012-06-14 09:30:20 -07:00
damage = psDroid - > sDisplay . screenR ;
2013-02-24 02:36:14 -08:00
}
2007-06-28 10:47:08 -07:00
damage * = 2 ;
scrX = psDroid - > sDisplay . screenX ;
scrY = psDroid - > sDisplay . screenY ;
scrR = psDroid - > sDisplay . screenR ;
2013-02-24 02:36:14 -08:00
if ( ! driveModeActive ( ) | | driveIsDriven ( psDroid ) ) {
2007-11-26 13:48:36 -08:00
boxCol = WZCOL_WHITE ;
2007-06-28 10:47:08 -07:00
} else {
2007-11-26 13:48:36 -08:00
boxCol = WZCOL_GREEN ;
2007-06-28 10:47:08 -07:00
}
2007-12-09 06:25:54 -08:00
if ( psDroid - > selected )
2007-06-28 10:47:08 -07:00
{
2007-12-09 06:25:54 -08:00
pie_BoxFill ( scrX - scrR , scrY + scrR - 7 , scrX - scrR + 1 , scrY + scrR , boxCol ) ;
pie_BoxFill ( scrX - scrR , scrY + scrR , scrX - scrR + 7 , scrY + scrR + 1 , boxCol ) ;
pie_BoxFill ( scrX + scrR - 7 , scrY + scrR , scrX + scrR , scrY + scrR + 1 , boxCol ) ;
pie_BoxFill ( scrX + scrR , scrY + scrR - 7 , scrX + scrR + 1 , scrY + scrR + 1 , boxCol ) ;
2007-06-28 10:47:08 -07:00
}
2007-12-24 05:57:19 -08:00
2007-12-09 06:25:54 -08:00
/* Power bars */
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR - 1 , scrY + scrR + 2 , scrX + scrR + 1 , scrY + scrR + 6 , WZCOL_RELOAD_BACKGROUND ) ;
2007-12-09 06:25:54 -08:00
pie_BoxFill ( scrX - scrR , scrY + scrR + 3 , scrX - scrR + damage , scrY + scrR + 4 , powerCol ) ;
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR , scrY + scrR + 4 , scrX - scrR + damage , scrY + scrR + 5 , powerColShadow ) ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
/* Write the droid rank out */
2012-06-14 09:30:20 -07:00
if ( ( scrX + scrR ) > 0
& & ( scrX - scrR ) < pie_GetVideoBufferWidth ( )
& & ( scrY + scrR ) > 0
& & ( scrY - scrR ) < pie_GetVideoBufferHeight ( ) )
2007-06-28 10:47:08 -07:00
{
drawDroidRank ( psDroid ) ;
drawDroidSensorLock ( psDroid ) ;
2012-06-14 09:30:20 -07:00
drawDroidCmndNo ( psDroid ) ;
drawDroidGroupNumber ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
2007-12-09 06:25:54 -08:00
for ( i = 0 ; i < psDroid - > numWeaps ; i + + )
2007-06-28 10:47:08 -07:00
{
2007-12-09 06:25:54 -08:00
drawWeaponReloadBar ( ( BASE_OBJECT * ) psDroid , & psDroid - > asWeaps [ i ] , i ) ;
2007-06-28 10:47:08 -07:00
}
}
}
/* Are we over an enemy droid */
2009-05-13 16:12:56 -07:00
if ( bMouseOverDroid & & ! bMouseOverOwnDroid )
2007-06-28 10:47:08 -07:00
{
2009-03-12 02:25:29 -07:00
if ( mouseDown ( getRightClickOrders ( ) ? MOUSE_LMB : MOUSE_RMB ) )
2007-06-28 10:47:08 -07:00
{
2007-02-10 08:39:39 -08:00
if ( psClickedOn - > player ! = selectedPlayer & & psClickedOn - > sDisplay . frameNumber = = currentGameFrame )
2007-06-28 10:47:08 -07:00
{
2009-05-13 16:12:56 -07:00
psDroid = ( DROID * ) psClickedOn ;
//show resistance values if CTRL/SHIFT depressed
if ( ctrlShiftDown ( ) )
{
if ( psDroid - > resistance )
{
damage = PERCENT ( psDroid - > resistance , droidResistance ( psDroid ) ) ;
}
else
{
damage = 100 ;
}
}
else
{
damage = PERCENT ( psDroid - > body , psDroid - > originalBody ) ;
}
if ( damage > REPAIRLEV_HIGH )
{
powerCol = WZCOL_HEALTH_HIGH ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_HIGH_SHADOW ;
2009-05-13 16:12:56 -07:00
}
else if ( damage > REPAIRLEV_LOW )
{
powerCol = WZCOL_HEALTH_MEDIUM ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_MEDIUM_SHADOW ;
2009-05-13 16:12:56 -07:00
}
else
{
powerCol = WZCOL_HEALTH_LOW ;
2009-11-17 17:45:55 -08:00
powerColShadow = WZCOL_HEALTH_LOW_SHADOW ;
2009-05-13 16:12:56 -07:00
}
//show resistance values if CTRL/SHIFT depressed
if ( ctrlShiftDown ( ) )
{
if ( psDroid - > resistance )
{
mulH = ( float ) psDroid - > resistance / ( float ) droidResistance ( psDroid ) ;
}
else
{
mulH = 100.f ;
}
}
else
{
mulH = ( float ) psDroid - > body / ( float ) psDroid - > originalBody ;
}
damage = mulH * ( float ) psDroid - > sDisplay . screenR ; // (((psDroid->sDisplay.screenR*10000)/100)*damage)/10000;
2012-06-14 09:30:20 -07:00
if ( damage > psDroid - > sDisplay . screenR )
damage = psDroid - > sDisplay . screenR ;
2009-05-13 16:12:56 -07:00
damage * = 2 ;
scrX = psDroid - > sDisplay . screenX ;
scrY = psDroid - > sDisplay . screenY ;
scrR = psDroid - > sDisplay . screenR ;
/* Three DFX clips properly right now - not sure if software does */
2012-06-14 09:30:20 -07:00
if ( ( scrX + scrR ) > 0
& & ( scrX - scrR ) < pie_GetVideoBufferWidth ( )
& & ( scrY + scrR ) > 0
& & ( scrY - scrR ) < pie_GetVideoBufferHeight ( ) )
2009-05-13 16:12:56 -07:00
{
if ( ! driveModeActive ( ) | | driveIsDriven ( psDroid ) ) {
boxCol = WZCOL_WHITE ;
} else {
boxCol = WZCOL_GREEN ;
}
/* Power bars */
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR - 1 , scrY + scrR + 2 , scrX + scrR + 1 , scrY + scrR + 6 , WZCOL_RELOAD_BACKGROUND ) ;
2009-05-13 16:12:56 -07:00
pie_BoxFill ( scrX - scrR , scrY + scrR + 3 , scrX - scrR + damage , scrY + scrR + 4 , powerCol ) ;
2009-11-17 17:45:55 -08:00
pie_BoxFill ( scrX - scrR , scrY + scrR + 4 , scrX - scrR + damage , scrY + scrR + 5 , powerColShadow ) ;
2009-05-13 16:12:56 -07:00
}
2007-06-28 10:47:08 -07:00
}
}
}
2009-05-13 16:12:56 -07:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2007-06-28 10:47:08 -07:00
{
/* Go thru' all the droidss */
2009-05-13 16:12:56 -07:00
for ( psDroid = apsDroidLists [ i ] ; psDroid ; psDroid = psDroid - > psNext )
2007-06-28 10:47:08 -07:00
{
2009-05-13 16:12:56 -07:00
if ( i ! = selectedPlayer & & ! psDroid - > died & & psDroid - > sDisplay . frameNumber = = currentGameFrame )
2007-06-28 10:47:08 -07:00
{
2009-05-13 16:12:56 -07:00
/* If it's selected */
2013-05-21 14:11:28 -07:00
if ( ( psDroid - > flags & BASEFLAG_TARGETED ) & & psDroid - > visible [ selectedPlayer ] = = UBYTE_MAX )
2007-06-28 10:47:08 -07:00
{
2009-05-13 16:12:56 -07:00
scrX = psDroid - > sDisplay . screenX ;
2012-06-14 09:30:20 -07:00
scrY = psDroid - > sDisplay . screenY ;
2010-02-06 09:09:56 -08:00
index = IMAGE_BLUE1 + getModularScaledRealTime ( 1020 , 5 ) ;
2009-05-13 16:12:56 -07:00
iV_DrawImage ( IntImages , index , scrX , scrY ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
for ( psFeature = apsFeatureLists [ 0 ] ; psFeature ; psFeature = psFeature - > psNext )
{
2007-02-10 08:39:39 -08:00
if ( ! psFeature - > died & & psFeature - > sDisplay . frameNumber = = currentGameFrame )
2007-06-28 10:47:08 -07:00
{
2013-05-21 14:11:28 -07:00
if ( psFeature - > flags & BASEFLAG_TARGETED )
2007-06-28 10:47:08 -07:00
{
scrX = psFeature - > sDisplay . screenX ;
2012-06-14 09:30:20 -07:00
scrY = psFeature - > sDisplay . screenY ;
2007-06-18 07:25:06 -07:00
iV_DrawImage ( IntImages , getTargettingGfx ( ) , scrX , scrY ) ;
2007-06-28 10:47:08 -07:00
}
}
}
pie_SetDepthBufferStatus ( DEPTH_CMP_LEQ_WRT_ON ) ;
}
2007-11-24 11:38:17 -08:00
2007-06-28 10:47:08 -07:00
/* ---------------------------------------------------------------------------- */
2008-11-10 14:50:08 -08:00
/// X offset to display the group number at
2012-06-14 09:30:20 -07:00
# define GN_X_OFFSET (8)
2008-11-10 14:50:08 -08:00
/// Draw the number of the group the droid is in next to the droid
2007-03-16 15:45:30 -07:00
static void drawDroidGroupNumber ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2012-06-14 09:30:20 -07:00
UWORD id = UWORD_MAX ;
2007-06-28 10:47:08 -07:00
2012-06-14 09:30:20 -07:00
switch ( psDroid - > group )
2007-06-28 10:47:08 -07:00
{
2012-06-14 09:30:20 -07:00
case 0 :
id = IMAGE_GN_0 ;
break ;
case 1 :
id = IMAGE_GN_1 ;
break ;
case 2 :
id = IMAGE_GN_2 ;
break ;
case 3 :
id = IMAGE_GN_3 ;
break ;
case 4 :
id = IMAGE_GN_4 ;
break ;
case 5 :
id = IMAGE_GN_5 ;
break ;
case 6 :
id = IMAGE_GN_6 ;
break ;
case 7 :
id = IMAGE_GN_7 ;
break ;
case 8 :
id = IMAGE_GN_8 ;
break ;
case 9 :
id = IMAGE_GN_9 ;
break ;
default :
break ;
2007-06-28 10:47:08 -07:00
}
2012-06-14 09:30:20 -07:00
if ( id ! = UWORD_MAX )
2007-06-28 10:47:08 -07:00
{
2012-06-14 09:30:20 -07:00
int xShift = psDroid - > sDisplay . screenR + GN_X_OFFSET ;
int yShift = psDroid - > sDisplay . screenR ;
2007-06-18 07:25:06 -07:00
iV_DrawImage ( IntImages , id , psDroid - > sDisplay . screenX - xShift , psDroid - > sDisplay . screenY + yShift ) ;
2007-06-28 10:47:08 -07:00
}
}
2007-11-24 11:38:17 -08:00
2012-06-14 09:30:20 -07:00
/// X offset to display the group number at
# define CMND_STAR_X_OFFSET (6)
# define CMND_GN_Y_OFFSET (8)
2008-11-10 14:50:08 -08:00
/// Draw the number of the commander the droid is assigned to
2007-03-17 08:30:34 -07:00
static void drawDroidCmndNo ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2012-06-14 09:30:20 -07:00
SDWORD xShift , yShift , index ;
UDWORD id2 ;
UWORD id ;
bool bDraw = true ;
2007-06-28 10:47:08 -07:00
2012-06-14 09:30:20 -07:00
id = UWORD_MAX ;
2007-06-28 10:47:08 -07:00
id2 = IMAGE_GN_STAR ;
index = SDWORD_MAX ;
if ( psDroid - > droidType = = DROID_COMMAND )
{
index = cmdDroidGetIndex ( psDroid ) ;
}
2008-04-15 08:15:19 -07:00
else if ( hasCommander ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
index = cmdDroidGetIndex ( psDroid - > psGroup - > psCommander ) ;
}
switch ( index )
{
case 1 :
id = IMAGE_GN_1 ;
break ;
case 2 :
id = IMAGE_GN_2 ;
break ;
case 3 :
id = IMAGE_GN_3 ;
break ;
case 4 :
id = IMAGE_GN_4 ;
break ;
case 5 :
id = IMAGE_GN_5 ;
break ;
case 6 :
id = IMAGE_GN_6 ;
break ;
case 7 :
id = IMAGE_GN_7 ;
break ;
case 8 :
id = IMAGE_GN_8 ;
break ;
case 9 :
id = IMAGE_GN_9 ;
break ;
default :
2008-03-24 09:51:17 -07:00
bDraw = false ;
2007-06-28 10:47:08 -07:00
break ;
}
if ( bDraw )
{
2012-06-14 09:30:20 -07:00
xShift = psDroid - > sDisplay . screenR + GN_X_OFFSET ;
yShift = psDroid - > sDisplay . screenR - CMND_GN_Y_OFFSET ;
iV_DrawImage ( IntImages , id2 , psDroid - > sDisplay . screenX - xShift - CMND_STAR_X_OFFSET , psDroid - > sDisplay . screenY + yShift ) ;
2007-06-18 07:25:06 -07:00
iV_DrawImage ( IntImages , id , psDroid - > sDisplay . screenX - xShift , psDroid - > sDisplay . screenY + yShift ) ;
2007-06-28 10:47:08 -07:00
}
}
/* ---------------------------------------------------------------------------- */
2008-11-10 14:50:08 -08:00
/** Get the onscreen coordinates of a droid so we can draw a bounding box
* This need to be severely speeded up and the accuracy increased to allow variable size bouding boxes
2012-06-14 09:30:20 -07:00
* @ todo Remove all magic numbers and hacks
2008-11-10 14:50:08 -08:00
*/
2007-06-02 16:01:29 -07:00
void calcScreenCoords ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2007-05-21 07:06:31 -07:00
/* Get it's absolute dimensions */
2013-05-09 04:24:19 -07:00
const BODY_STATS * psBStats = asBodyStats + psDroid - > asBits [ COMP_BODY ] ;
2012-06-14 09:30:20 -07:00
Vector3i origin ;
Vector2i center ;
int wsRadius = 22 ; // World space radius, 22 = magic minimum
float radius ;
2010-10-09 09:58:17 -07:00
2012-06-14 09:30:20 -07:00
// NOTE: This only takes into account body, but seems "good enough"
if ( psBStats & & psBStats - > pIMD )
2007-06-28 10:47:08 -07:00
{
2012-06-14 09:30:20 -07:00
wsRadius = MAX ( wsRadius , psBStats - > pIMD - > radius ) ;
2007-06-28 10:47:08 -07:00
}
2012-06-14 09:30:20 -07:00
origin = Vector3i ( 0 , wsRadius , 0 ) ; // take the center of the object
/* get the screen coordinates */
// FP12_SHIFT-STRETCHED_Z_SHIFT is the shift of the scaling on the depth returned
const float cZ = pie_RotateProject ( & origin , & center ) / ( float ) ( 1 < < ( FP12_SHIFT - STRETCHED_Z_SHIFT ) ) ;
2006-11-04 14:56:28 -08:00
//Watermelon:added a crash protection hack...
2012-06-14 09:30:20 -07:00
if ( cZ > = 0 )
{
// 330 is the near plane depth from pie_PerspectiveBegin
// not sure where magic comes from, could be another 1<<FP12_SHIFT-STRETCHED_Z_SHIFT
const int magic = 4 ;
radius = ( wsRadius * 330 * magic ) / cZ ;
}
else
2006-11-04 14:56:28 -08:00
{
2012-06-14 09:30:20 -07:00
radius = 1 ; // 1 just in case some other code assumes radius != 0
2006-11-04 14:56:28 -08:00
}
2007-06-28 10:47:08 -07:00
/* Deselect all the droids if we've released the drag box */
if ( dragBox3D . status = = DRAG_RELEASED )
{
2007-06-02 16:01:29 -07:00
if ( inQuad ( & center , & dragQuad ) & & psDroid - > player = = selectedPlayer )
2006-05-27 09:37:17 -07:00
{
2007-06-28 10:47:08 -07:00
//don't allow Transporter Droids to be selected here
2007-04-15 13:45:09 -07:00
//unless we're in multiPlayer mode!!!!
2012-02-25 16:21:29 -08:00
if ( ( psDroid - > droidType ! = DROID_TRANSPORTER & & psDroid - > droidType ! = DROID_SUPERTRANSPORTER ) | | bMultiPlayer )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
dealWithDroidSelect ( psDroid , true ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-06-02 16:01:29 -07:00
2007-06-28 10:47:08 -07:00
/* Store away the screen coordinates so we can select the droids without doing a trasform */
2007-06-02 16:01:29 -07:00
psDroid - > sDisplay . screenX = center . x ;
psDroid - > sDisplay . screenY = center . y ;
2007-06-28 10:47:08 -07:00
psDroid - > sDisplay . screenR = radius ;
}
2008-11-10 14:50:08 -08:00
/**
2007-05-29 19:44:38 -07:00
* Find the tile the mouse is currently over
2008-11-10 14:50:08 -08:00
* \ todo This is slow - speed it up
2007-05-29 19:44:38 -07:00
*/
2007-05-29 19:06:46 -07:00
static void locateMouse ( void )
2007-06-28 10:47:08 -07:00
{
2010-12-21 12:51:29 -08:00
const Vector2i pt ( mouseX ( ) , mouseY ( ) ) ;
2011-04-30 09:41:50 -07:00
int i , j ;
unsigned idx , jdx ;
2007-06-04 02:37:28 -07:00
int nearestZ = INT_MAX ;
2007-06-28 10:47:08 -07:00
2011-04-30 09:41:50 -07:00
// Intentionally not the same range as in drawTiles()
for ( i = - visibleTiles . y / 2 , idx = 0 ; i < visibleTiles . y / 2 ; i + + , + + idx )
2007-06-28 10:47:08 -07:00
{
2011-04-30 09:41:50 -07:00
for ( j = - visibleTiles . x / 2 , jdx = 0 ; j < visibleTiles . x / 2 ; j + + , + + jdx )
2007-06-28 10:47:08 -07:00
{
2013-03-30 19:09:19 -07:00
int tileZ = tileScreenInfo [ idx ] [ jdx ] . z ;
2007-06-28 10:47:08 -07:00
2013-03-30 19:09:19 -07:00
if ( tileZ < = nearestZ )
2007-06-28 10:47:08 -07:00
{
2007-05-30 00:20:50 -07:00
QUAD quad ;
2013-03-30 19:09:19 -07:00
quad . coords [ 0 ] . x = tileScreenInfo [ idx + 0 ] [ jdx + 0 ] . x ;
quad . coords [ 0 ] . y = tileScreenInfo [ idx + 0 ] [ jdx + 0 ] . y ;
quad . coords [ 1 ] . x = tileScreenInfo [ idx + 0 ] [ jdx + 1 ] . x ;
quad . coords [ 1 ] . y = tileScreenInfo [ idx + 0 ] [ jdx + 1 ] . y ;
quad . coords [ 2 ] . x = tileScreenInfo [ idx + 1 ] [ jdx + 1 ] . x ;
quad . coords [ 2 ] . y = tileScreenInfo [ idx + 1 ] [ jdx + 1 ] . y ;
quad . coords [ 3 ] . x = tileScreenInfo [ idx + 1 ] [ jdx + 0 ] . x ;
quad . coords [ 3 ] . y = tileScreenInfo [ idx + 1 ] [ jdx + 0 ] . y ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
/* We've got a match for our mouse coords */
2007-05-29 19:06:46 -07:00
if ( inQuad ( & pt , & quad ) )
2007-06-28 10:47:08 -07:00
{
2011-04-30 09:41:50 -07:00
mousePos . x = player . p . x + world_coord ( j ) ;
mousePos . y = player . p . z + world_coord ( i ) ;
mousePos + = positionInQuad ( pt , quad ) ;
if ( mousePos . x < 0 )
mousePos . x = 0 ;
else if ( mousePos . x > world_coord ( mapWidth - 1 ) )
mousePos . x = world_coord ( mapWidth - 1 ) ;
if ( mousePos . y < 0 )
mousePos . y = 0 ;
else if ( mousePos . y > world_coord ( mapHeight - 1 ) )
mousePos . y = world_coord ( mapHeight - 1 ) ;
mouseTileX = map_coord ( mousePos . x ) ;
mouseTileY = map_coord ( mousePos . y ) ;
2011-03-03 14:15:40 -08:00
2007-06-28 10:47:08 -07:00
/* Store away z value */
2013-03-30 19:09:19 -07:00
nearestZ = tileZ ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
}
2007-06-28 10:47:08 -07:00
}
}
}
2008-11-10 14:50:08 -08:00
/// Render the sky and surroundings
2007-03-30 10:38:35 -07:00
static void renderSurroundings ( void )
2007-06-28 10:47:08 -07:00
{
2011-04-25 03:29:26 -07:00
// Push current matrix onto stack
2007-03-30 10:38:35 -07:00
pie_MatBegin ( ) ;
2011-04-25 03:29:26 -07:00
// Render skybox relative to ground (i.e. undo player y translation)
// then move it somewhat below ground level for the blending effect
pie_TRANSLATE ( 0 , player . p . y - skybox_scale / 8 , 0 ) ;
2007-03-30 10:38:35 -07:00
// rotate it
2010-10-08 02:04:32 -07:00
pie_MatRotY ( DEG ( wind ) ) ;
2007-03-30 10:38:35 -07:00
2007-02-24 14:53:33 -08:00
if ( ! gamePaused ( ) )
2007-06-28 10:47:08 -07:00
{
2012-11-15 12:30:59 -08:00
wind = wrapf ( wind + graphicsTimeAdjustedIncrement ( windSpeed ) , 360.0f ) ;
2007-06-28 10:47:08 -07:00
}
2013-01-19 15:53:09 -08:00
pie_DrawSkybox ( skybox_scale ) ;
2007-03-30 10:38:35 -07:00
// Load Saved State
pie_MatEnd ( ) ;
}
2007-06-28 10:47:08 -07:00
2008-11-10 14:50:08 -08:00
/// Smoothly adjust player height to match the desired height
2007-06-19 16:18:44 -07:00
static void trackHeight ( float desiredHeight )
{
static float heightSpeed = 0.0f ;
2007-12-31 10:37:20 -08:00
float separation = desiredHeight - player . p . y ; // How far are we from desired height?
2007-06-19 16:18:44 -07:00
2010-12-01 04:33:44 -08:00
// d²/dt² player.p.y = -ACCEL_CONSTANT * (player.p.y - desiredHeight) - VELOCITY_CONSTANT * d/dt player.p.y
solveDifferential2ndOrder ( & separation , & heightSpeed , ACCEL_CONSTANT , VELOCITY_CONSTANT , realTimeAdjustedIncrement ( 1 ) ) ;
2007-06-19 16:18:44 -07:00
/* Adjust the height accordingly */
2010-12-01 04:33:44 -08:00
player . p . y = desiredHeight - separation ;
2007-06-28 10:47:08 -07:00
}
2007-06-19 16:18:44 -07:00
2008-11-10 14:50:08 -08:00
/// Select the next energy bar display mode
2009-04-09 03:00:22 -07:00
ENERGY_BAR toggleEnergyBars ( void )
2007-06-28 10:47:08 -07:00
{
2007-12-09 06:25:54 -08:00
if ( + + barMode = = BAR_LAST )
2007-06-28 10:47:08 -07:00
{
2007-12-09 06:25:54 -08:00
barMode = BAR_SELECTED ;
2007-06-28 10:47:08 -07:00
}
2010-12-05 08:25:43 -08:00
return ( ENERGY_BAR ) barMode ;
2007-06-28 10:47:08 -07:00
}
2006-08-08 11:48:06 -07:00
2008-11-10 14:50:08 -08:00
/// Set everything up for when the player assigns the sensor target
2007-06-28 10:47:08 -07:00
void assignSensorTarget ( BASE_OBJECT * psObj )
{
2008-03-24 09:51:17 -07:00
bSensorTargetting = true ;
2012-10-02 07:54:33 -07:00
lastTargetAssignation = realTime ;
2007-06-28 10:47:08 -07:00
psSensorObj = psObj ;
}
2008-11-10 14:50:08 -08:00
/// Set everything up for when the player selects the destination
2007-06-28 10:47:08 -07:00
void assignDestTarget ( void )
{
2008-03-24 09:51:17 -07:00
bDestTargetting = true ;
2012-10-02 07:54:33 -07:00
lastDestAssignation = realTime ;
2007-06-28 10:47:08 -07:00
destTargetX = mouseX ( ) ;
destTargetY = mouseY ( ) ;
destTileX = mouseTileX ;
destTileY = mouseTileY ;
}
2007-11-24 11:38:17 -08:00
2008-11-10 14:50:08 -08:00
/// Draw a graphical effect after selecting a sensor target
2007-03-16 15:45:30 -07:00
static void processSensorTarget ( void )
2007-06-28 10:47:08 -07:00
{
SWORD x , y ;
SWORD offset ;
SWORD x0 , y0 , x1 , y1 ;
UDWORD index ;
if ( bSensorTargetting )
{
2012-10-02 07:54:33 -07:00
if ( ( realTime - lastTargetAssignation ) < TARGET_TO_SENSOR_TIME )
2007-06-28 10:47:08 -07:00
{
2007-02-10 08:39:39 -08:00
if ( ! psSensorObj - > died & & psSensorObj - > sDisplay . frameNumber = = currentGameFrame )
2007-06-28 10:47:08 -07:00
{
x = /*mouseX();*/ ( SWORD ) psSensorObj - > sDisplay . screenX ;
y = ( SWORD ) psSensorObj - > sDisplay . screenY ;
if ( ! gamePaused ( ) )
{
2010-02-06 09:07:52 -08:00
index = IMAGE_BLUE1 + getModularScaledGraphicsTime ( 1020 , 5 ) ;
2007-06-28 10:47:08 -07:00
}
else
{
index = IMAGE_BLUE1 ;
}
2007-06-18 07:25:06 -07:00
iV_DrawImage ( IntImages , index , x , y ) ;
2007-06-28 10:47:08 -07:00
2012-10-02 07:54:33 -07:00
offset = ( SWORD ) ( 12 + ( ( TARGET_TO_SENSOR_TIME ) - ( realTime -
2007-06-28 10:47:08 -07:00
lastTargetAssignation ) ) / 2 ) ;
x0 = ( SWORD ) ( x - offset ) ;
y0 = ( SWORD ) ( y - offset ) ;
x1 = ( SWORD ) ( x + offset ) ;
y1 = ( SWORD ) ( y + offset ) ;
2007-12-09 08:09:23 -08:00
iV_Line ( x0 , y0 , x0 + 8 , y0 , WZCOL_WHITE ) ;
iV_Line ( x0 , y0 , x0 , y0 + 8 , WZCOL_WHITE ) ;
2007-06-28 10:47:08 -07:00
2007-12-09 08:09:23 -08:00
iV_Line ( x1 , y0 , x1 - 8 , y0 , WZCOL_WHITE ) ;
iV_Line ( x1 , y0 , x1 , y0 + 8 , WZCOL_WHITE ) ;
2007-06-28 10:47:08 -07:00
2007-12-09 08:09:23 -08:00
iV_Line ( x1 , y1 , x1 - 8 , y1 , WZCOL_WHITE ) ;
iV_Line ( x1 , y1 , x1 , y1 - 8 , WZCOL_WHITE ) ;
2007-06-28 10:47:08 -07:00
2007-12-09 08:09:23 -08:00
iV_Line ( x0 , y1 , x0 + 8 , y1 , WZCOL_WHITE ) ;
iV_Line ( x0 , y1 , x0 , y1 - 8 , WZCOL_WHITE ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2008-03-24 09:51:17 -07:00
bSensorTargetting = false ;
2007-06-28 10:47:08 -07:00
}
}
else
{
2008-03-24 09:51:17 -07:00
bSensorTargetting = false ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-11-19 12:58:36 -08:00
2008-11-10 14:50:08 -08:00
/// Draw a graphical effect after selecting a destination
2007-03-16 15:45:30 -07:00
static void processDestinationTarget ( void )
2007-06-28 10:47:08 -07:00
{
SWORD x , y ;
SWORD offset ;
SWORD x0 , y0 , x1 , y1 ;
if ( bDestTargetting )
{
2012-10-02 07:54:33 -07:00
if ( ( realTime - lastDestAssignation ) < DEST_TARGET_TIME )
2007-06-28 10:47:08 -07:00
{
x = ( SWORD ) destTargetX ;
y = ( SWORD ) destTargetY ;
2012-10-02 07:54:33 -07:00
offset = ( SWORD ) ( ( ( DEST_TARGET_TIME ) - ( realTime - lastDestAssignation ) ) / 2 ) ;
2007-06-28 10:47:08 -07:00
x0 = ( SWORD ) ( x - offset ) ;
y0 = ( SWORD ) ( y - offset ) ;
x1 = ( SWORD ) ( x + offset ) ;
y1 = ( SWORD ) ( y + offset ) ;
2007-11-26 14:59:21 -08:00
pie_BoxFill ( x0 , y0 , x0 + 2 , y0 + 2 , WZCOL_WHITE ) ;
pie_BoxFill ( x1 - 2 , y0 - 2 , x1 , y0 , WZCOL_WHITE ) ;
pie_BoxFill ( x1 - 2 , y1 - 2 , x1 , y1 , WZCOL_WHITE ) ;
pie_BoxFill ( x0 , y1 , x0 + 2 , y1 + 2 , WZCOL_WHITE ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2008-03-24 09:51:17 -07:00
bDestTargetting = false ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-11-19 12:58:36 -08:00
2008-11-10 14:50:08 -08:00
/// Set what tile is being used to draw the bottom of a body of water
2007-06-28 10:47:08 -07:00
void setUnderwaterTile ( UDWORD num )
{
underwaterTile = num ;
}
2008-11-10 14:50:08 -08:00
/// Set what tile is being used to show rubble
2007-06-28 10:47:08 -07:00
void setRubbleTile ( UDWORD num )
{
rubbleTile = num ;
}
2008-11-10 14:50:08 -08:00
/// Get the tile that is currently being used to draw underwater ground
2007-06-28 10:47:08 -07:00
UDWORD getWaterTileNum ( void )
{
return ( underwaterTile ) ;
}
2008-11-10 14:50:08 -08:00
/// Get the tile that is being used to show rubble
2007-06-28 10:47:08 -07:00
UDWORD getRubbleTileNum ( void )
{
return ( rubbleTile ) ;
}
2008-11-10 14:50:08 -08:00
/// Draw the spinning particles for power stations and re-arm pads for the specified player
2007-12-01 12:24:10 -08:00
static void structureEffectsPlayer ( UDWORD player )
2007-06-28 10:47:08 -07:00
{
SDWORD radius ;
STRUCTURE * psStructure ;
SDWORD xDif , yDif ;
2007-03-16 09:20:16 -07:00
Vector3i pos ;
2007-06-28 10:47:08 -07:00
UDWORD numConnected ;
DROID * psDroid ;
UDWORD gameDiv ;
UDWORD i ;
BASE_OBJECT * psChosenObj = NULL ;
UWORD bFXSize ;
2011-02-12 13:53:06 -08:00
const int effectsPerSecond = 12 ; // Effects per second. Will add effects up to once time per frame, so won't add as many effects if the framerate is low, but will be consistent, otherwise.
unsigned effectTime = graphicsTime / ( GAME_TICKS_PER_SEC / effectsPerSecond ) * ( GAME_TICKS_PER_SEC / effectsPerSecond ) ;
if ( effectTime < = graphicsTime - deltaGraphicsTime )
{
return ; // Don't add effects this frame.
}
2007-06-28 10:47:08 -07:00
for ( psStructure = apsStructLists [ player ] ; psStructure ; psStructure = psStructure - > psNext )
{
2013-03-01 12:15:59 -08:00
if ( psStructure - > status ! = SS_BUILT )
2007-06-28 10:47:08 -07:00
{
2013-03-01 12:15:59 -08:00
continue ;
}
2007-02-10 08:39:39 -08:00
if ( psStructure - > pStructureType - > type = = REF_POWER_GEN & & psStructure - > visible [ selectedPlayer ] )
2007-06-28 10:47:08 -07:00
{
2007-07-08 15:47:13 -07:00
POWER_GEN * psPowerGen = & psStructure - > pFunctionality - > powerGenerator ;
2007-06-28 10:47:08 -07:00
numConnected = 0 ;
for ( i = 0 ; i < NUM_POWER_MODULES ; i + + )
{
if ( psPowerGen - > apResExtractors [ i ] )
{
numConnected + + ;
}
}
2007-04-15 13:45:09 -07:00
/* No effect if nothing connected */
2007-06-28 10:47:08 -07:00
if ( ! numConnected )
{
2007-04-15 13:45:09 -07:00
//keep looking for another!
continue ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
else switch ( numConnected )
2006-05-27 09:37:17 -07:00
{
2007-06-28 10:47:08 -07:00
case 1 :
case 2 :
gameDiv = 1440 ;
break ;
case 3 :
case 4 :
default :
2010-03-03 02:16:53 -08:00
gameDiv = 1080 ; // really fast!!!
2007-06-28 10:47:08 -07:00
break ;
}
/* New addition - it shows how many are connected... */
for ( i = 0 ; i < numConnected ; i + + )
{
2007-04-15 13:45:09 -07:00
radius = 32 - ( i * 2 ) ; // around the spire
2011-02-12 13:53:06 -08:00
xDif = iSinSR ( effectTime , gameDiv , radius ) ;
yDif = iCosSR ( effectTime , gameDiv , radius ) ;
2007-06-28 10:47:08 -07:00
2007-12-15 07:39:29 -08:00
pos . x = psStructure - > pos . x + xDif ;
pos . z = psStructure - > pos . y + yDif ;
2007-06-28 10:47:08 -07:00
pos . y = map_Height ( pos . x , pos . z ) + 64 + ( i * 20 ) ; // 64 up to get to base of spire
effectGiveAuxVar ( 50 ) ; // half normal plasma size...
2008-03-24 09:51:17 -07:00
addEffect ( & pos , EFFECT_EXPLOSION , EXPLOSION_TYPE_LASER , false , NULL , 0 ) ;
2007-06-28 10:47:08 -07:00
2007-12-15 07:39:29 -08:00
pos . x = psStructure - > pos . x - xDif ;
pos . z = psStructure - > pos . y - yDif ;
2007-06-28 10:47:08 -07:00
effectGiveAuxVar ( 50 ) ; // half normal plasma size...
2006-05-27 09:37:17 -07:00
2008-03-24 09:51:17 -07:00
addEffect ( & pos , EFFECT_EXPLOSION , EXPLOSION_TYPE_LASER , false , NULL , 0 ) ;
2007-06-28 10:47:08 -07:00
}
}
/* Might be a re-arm pad! */
2006-05-27 09:37:17 -07:00
else if ( psStructure - > pStructureType - > type = = REF_REARM_PAD
2007-02-10 08:39:39 -08:00
& & psStructure - > visible [ selectedPlayer ] )
2007-06-28 10:47:08 -07:00
{
2007-07-08 15:47:13 -07:00
REARM_PAD * psReArmPad = & psStructure - > pFunctionality - > rearmPad ;
2007-06-28 10:47:08 -07:00
psChosenObj = psReArmPad - > psObj ;
2013-03-01 12:15:59 -08:00
if ( psChosenObj ! = NULL & & ( ( ( DROID * ) psChosenObj ) - > visible [ selectedPlayer ] ) )
2007-06-28 10:47:08 -07:00
{
2007-04-15 13:45:09 -07:00
bFXSize = 0 ;
2007-06-28 10:47:08 -07:00
psDroid = ( DROID * ) psChosenObj ;
2007-02-10 08:39:39 -08:00
if ( ! psDroid - > died & & psDroid - > action = = DACTION_WAITDURINGREARM )
2007-06-28 10:47:08 -07:00
{
2007-04-15 13:45:09 -07:00
bFXSize = 30 ;
2007-06-28 10:47:08 -07:00
}
2007-04-15 13:45:09 -07:00
/* Then it's repairing...? */
2006-05-27 09:37:17 -07:00
radius = psStructure - > sDisplay . imd - > radius ;
2011-02-12 13:53:06 -08:00
xDif = iSinSR ( effectTime , 720 , radius ) ;
yDif = iCosSR ( effectTime , 720 , radius ) ;
2007-12-15 07:39:29 -08:00
pos . x = psStructure - > pos . x + xDif ;
pos . z = psStructure - > pos . y + yDif ;
2007-12-21 09:34:23 -08:00
pos . y = map_Height ( pos . x , pos . z ) + psStructure - > sDisplay . imd - > max . y ;
2007-06-28 10:47:08 -07:00
effectGiveAuxVar ( 30 + bFXSize ) ; // half normal plasma size...
2008-03-24 09:51:17 -07:00
addEffect ( & pos , EFFECT_EXPLOSION , EXPLOSION_TYPE_LASER , false , NULL , 0 ) ;
2007-12-15 07:39:29 -08:00
pos . x = psStructure - > pos . x - xDif ;
pos . z = psStructure - > pos . y - yDif ; // buildings are level!
2007-06-28 10:47:08 -07:00
effectGiveAuxVar ( 30 + bFXSize ) ; // half normal plasma size...
2008-03-24 09:51:17 -07:00
addEffect ( & pos , EFFECT_EXPLOSION , EXPLOSION_TYPE_LASER , false , NULL , 0 ) ;
2006-05-27 09:37:17 -07:00
}
2007-06-28 10:47:08 -07:00
}
}
}
2008-11-10 14:50:08 -08:00
/// Draw the effects for all players and buildings
2007-12-01 12:24:10 -08:00
static void structureEffects ( )
2007-06-28 10:47:08 -07:00
{
UDWORD i ;
2010-08-28 04:08:01 -07:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
{
if ( apsStructLists [ i ] )
2007-06-28 10:47:08 -07:00
{
2010-08-28 04:08:01 -07:00
structureEffectsPlayer ( i ) ;
2007-06-28 10:47:08 -07:00
}
2010-08-28 04:08:01 -07:00
}
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Show the sensor ranges of selected droids and buildings
2007-03-16 15:45:30 -07:00
static void showDroidSensorRanges ( void )
2007-06-28 10:47:08 -07:00
{
DROID * psDroid ;
STRUCTURE * psStruct ;
if ( rangeOnScreen ) // note, we still have to decide what to do with multiple units selected, since it will draw it for all of them! -Q 5-10-05
{
for ( psDroid = apsDroidLists [ selectedPlayer ] ; psDroid ; psDroid = psDroid - > psNext )
{
if ( psDroid - > selected )
{
showSensorRange2 ( ( BASE_OBJECT * ) psDroid ) ;
}
}
for ( psStruct = apsStructLists [ selectedPlayer ] ; psStruct ; psStruct = psStruct - > psNext )
{
if ( psStruct - > selected )
{
showSensorRange2 ( ( BASE_OBJECT * ) psStruct ) ;
}
}
} //end if we want to display...
}
2010-03-03 02:16:53 -08:00
static void showEffectCircle ( Position centre , int32_t radius , uint32_t auxVar , EFFECT_GROUP group , EFFECT_TYPE type )
{
int32_t circumference = radius * 2 * 355 / 113 / TILE_UNITS ; // 2πr in tiles.
int32_t i ;
for ( i = 0 ; i < circumference ; + + i )
{
Vector3i pos ;
pos . x = centre . x - iSinSR ( i , circumference , radius ) ;
pos . z = centre . y - iCosSR ( i , circumference , radius ) ; // [sic] y -> z
// Check if it's actually on map
if ( worldOnMap ( pos . x , pos . z ) )
{
pos . y = map_Height ( pos . x , pos . z ) + 16 ;
effectGiveAuxVar ( auxVar ) ;
addEffect ( & pos , group , type , false , NULL , 0 ) ;
}
}
}
2009-01-30 22:20:22 -08:00
// Shows the weapon (long) range of the object in question.
// Note, it only does it for the first weapon slot!
static void showWeaponRange ( BASE_OBJECT * psObj )
{
2010-03-03 02:16:53 -08:00
uint32_t weaponRange ;
2012-03-04 07:00:26 -08:00
uint32_t minRange ;
2013-05-05 04:34:59 -07:00
WEAPON_STATS * psStats ;
2009-01-30 22:20:22 -08:00
2009-11-24 16:43:44 -08:00
if ( psObj - > type = = OBJ_DROID )
2009-01-30 22:20:22 -08:00
{
2010-03-03 02:16:53 -08:00
DROID * psDroid = ( DROID * ) psObj ;
2013-05-05 04:34:59 -07:00
const int compIndex = psDroid - > asWeaps [ 0 ] . nStat ; // weapon_slot
2010-06-27 12:12:18 -07:00
ASSERT_OR_RETURN ( , compIndex < numWeaponStats , " Invalid range referenced for numWeaponStats, %d > %d " , compIndex , numWeaponStats ) ;
psStats = asWeaponStats + compIndex ;
2009-01-30 22:20:22 -08:00
}
else
{
2010-03-03 02:16:53 -08:00
STRUCTURE * psStruct = ( STRUCTURE * ) psObj ;
2013-05-05 04:34:59 -07:00
if ( psStruct - > pStructureType - > numWeaps = = 0 ) return ;
psStats = psStruct - > pStructureType - > psWeapStat [ 0 ] ;
2009-01-30 22:20:22 -08:00
}
2013-05-05 04:34:59 -07:00
weaponRange = psStats - > upgrade [ psObj - > player ] . maxRange ;
minRange = psStats - > upgrade [ psObj - > player ] . minRange ;
2010-03-03 02:16:53 -08:00
showEffectCircle ( psObj - > pos , weaponRange , 40 , EFFECT_EXPLOSION , EXPLOSION_TYPE_SMALL ) ;
2012-03-04 07:00:26 -08:00
if ( minRange > 0 )
{
showEffectCircle ( psObj - > pos , minRange , 40 , EFFECT_EXPLOSION , EXPLOSION_TYPE_TESLA ) ;
}
2009-01-30 22:20:22 -08:00
}
2010-03-03 02:16:53 -08:00
static void showSensorRange2 ( BASE_OBJECT * psObj )
2007-06-28 10:47:08 -07:00
{
2013-05-05 04:34:59 -07:00
showEffectCircle ( psObj - > pos , objSensorRange ( psObj ) , 80 , EFFECT_EXPLOSION , EXPLOSION_TYPE_LASER ) ;
2009-01-30 22:20:22 -08:00
showWeaponRange ( psObj ) ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/// Draw a circle on the map (to show the range of something)
2010-03-03 02:16:53 -08:00
static void drawRangeAtPos ( SDWORD centerX , SDWORD centerY , SDWORD radius )
2006-10-08 01:06:46 -07:00
{
2010-12-21 12:51:29 -08:00
Position pos ( centerX , centerY , 0 ) ; // .z ignored.
2010-03-03 02:16:53 -08:00
showEffectCircle ( pos , radius , 80 , EFFECT_EXPLOSION , EXPLOSION_TYPE_SMALL ) ;
2006-10-08 01:06:46 -07:00
}
2008-11-10 14:50:08 -08:00
/** Turn on drawing some effects at certain position to visualize the radius.
* \ note Pass a negative radius to turn this off
*/
2006-10-08 01:06:46 -07:00
void showRangeAtPos ( SDWORD centerX , SDWORD centerY , SDWORD radius )
{
rangeCenterX = centerX ;
rangeCenterY = centerY ;
rangeRadius = radius ;
2008-03-24 09:51:17 -07:00
bRangeDisplay = true ;
2006-10-08 01:06:46 -07:00
if ( radius < = 0 )
2008-03-24 09:51:17 -07:00
bRangeDisplay = false ;
2006-10-08 01:06:46 -07:00
}
2008-11-10 14:50:08 -08:00
/// Get the graphic ID for a droid rank
2007-06-28 10:47:08 -07:00
UDWORD getDroidRankGraphic ( DROID * psDroid )
{
2007-04-15 13:45:09 -07:00
UDWORD gfxId ;
2007-06-28 10:47:08 -07:00
/* Not found yet */
gfxId = UDWORD_MAX ;
/* Establish the numerical value of the droid's rank */
switch ( getDroidLevel ( psDroid ) )
{
case 0 :
break ;
case 1 :
gfxId = IMAGE_LEV_0 ;
break ;
case 2 :
gfxId = IMAGE_LEV_1 ;
break ;
case 3 :
gfxId = IMAGE_LEV_2 ;
break ;
case 4 :
gfxId = IMAGE_LEV_3 ;
break ;
case 5 :
gfxId = IMAGE_LEV_4 ;
break ;
case 6 :
gfxId = IMAGE_LEV_5 ;
break ;
case 7 :
gfxId = IMAGE_LEV_6 ;
break ;
case 8 :
gfxId = IMAGE_LEV_7 ;
break ;
default :
2007-06-14 13:59:04 -07:00
ASSERT ( ! " out of range droid rank " , " Weird droid level in drawDroidRank " ) ;
2007-06-28 10:47:08 -07:00
break ;
}
2007-04-15 13:45:09 -07:00
return gfxId ;
2007-06-28 10:47:08 -07:00
}
2008-11-10 14:50:08 -08:00
/** Will render a graphic depiction of the droid's present rank.
* \ note Assumes matrix context set and that z - buffer write is force enabled ( Always ) .
*/
2007-03-17 08:30:34 -07:00
static void drawDroidRank ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2007-11-24 11:38:17 -08:00
UDWORD gfxId = getDroidRankGraphic ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2007-04-15 13:45:09 -07:00
/* Did we get one? - We should have... */
2007-06-28 10:47:08 -07:00
if ( gfxId ! = UDWORD_MAX )
{
/* Render the rank graphic at the correct location */ // remove hardcoded numbers?!
2012-06-14 09:30:20 -07:00
iV_DrawImage ( IntImages , ( UWORD ) gfxId ,
psDroid - > sDisplay . screenX + psDroid - > sDisplay . screenR + 8 ,
psDroid - > sDisplay . screenY + psDroid - > sDisplay . screenR ) ;
2007-06-28 10:47:08 -07:00
}
}
2008-11-10 14:50:08 -08:00
/** Will render a sensor graphic for a droid locked to a sensor droid/structure
* \ note Assumes matrix context set and that z - buffer write is force enabled ( Always ) .
*/
2007-03-17 08:30:34 -07:00
static void drawDroidSensorLock ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
//if on fire support duty - must be locked to a Sensor Droid/Structure
if ( orderState ( psDroid , DORDER_FIRESUPPORT ) )
{
/* Render the sensor graphic at the correct location - which is what?!*/
2012-06-14 09:30:20 -07:00
iV_DrawImage ( IntImages , IMAGE_GN_STAR , psDroid - > sDisplay . screenX , psDroid - > sDisplay . screenY ) ;
2007-06-28 10:47:08 -07:00
}
}
2008-11-10 14:50:08 -08:00
/// Draw the construction lines for all construction droids
2007-06-28 10:47:08 -07:00
static void doConstructionLines ( void )
{
2010-03-18 19:04:57 -07:00
DROID * psDroid ;
UDWORD i ;
2007-06-28 10:47:08 -07:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
{
for ( psDroid = apsDroidLists [ i ] ; psDroid ; psDroid = psDroid - > psNext )
{
2013-03-01 12:15:59 -08:00
if ( clipXY ( psDroid - > pos . x , psDroid - > pos . y )
& & psDroid - > visible [ selectedPlayer ] = = UBYTE_MAX
& & psDroid - > sMove . Status ! = MOVESHUFFLE )
2007-06-28 10:47:08 -07:00
{
if ( psDroid - > action = = DACTION_BUILD )
{
2011-12-30 08:43:49 -08:00
if ( psDroid - > order . psObj )
2007-06-28 10:47:08 -07:00
{
2011-12-30 08:43:49 -08:00
if ( psDroid - > order . psObj - > type = = OBJ_STRUCTURE )
2007-06-28 10:47:08 -07:00
{
2011-12-30 08:43:49 -08:00
addConstructionLine ( psDroid , ( STRUCTURE * ) psDroid - > order . psObj ) ;
2007-06-28 10:47:08 -07:00
}
}
2006-05-27 09:37:17 -07:00
}
2007-02-10 08:39:39 -08:00
else if ( ( psDroid - > action = = DACTION_DEMOLISH ) | |
( psDroid - > action = = DACTION_REPAIR ) | |
2007-06-28 10:47:08 -07:00
( psDroid - > action = = DACTION_RESTORE ) )
{
2013-02-24 02:36:14 -08:00
if ( psDroid - > psActionTarget [ 0 ]
& & psDroid - > psActionTarget [ 0 ] - > type = = OBJ_STRUCTURE )
2007-06-28 10:47:08 -07:00
{
2013-02-24 02:36:14 -08:00
addConstructionLine ( psDroid , ( STRUCTURE * ) psDroid - > psActionTarget [ 0 ] ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
}
}
2008-11-10 14:50:08 -08:00
/// Draw the construction or demolish lines for one droid
2007-07-28 06:50:16 -07:00
static void addConstructionLine ( DROID * psDroid , STRUCTURE * psStructure )
2007-06-28 10:47:08 -07:00
{
2013-01-15 13:24:26 -08:00
Vector3f * point ;
Vector3f pts [ 3 ] ;
int pointIndex ;
2007-03-16 09:20:16 -07:00
Vector3i each ;
2007-12-13 10:08:37 -08:00
PIELIGHT colour ;
2007-06-28 10:47:08 -07:00
2013-01-15 13:24:26 -08:00
pts [ 0 ] = Vector3f ( psDroid - > pos . x - player . p . x , psDroid - > pos . z + 24 , - ( psDroid - > pos . y - player . p . z ) ) ;
2007-06-28 10:47:08 -07:00
2013-01-15 13:24:26 -08:00
pointIndex = rand ( ) % ( psStructure - > sDisplay . imd - > npoints - 1 ) ;
2007-06-28 10:47:08 -07:00
point = & ( psStructure - > sDisplay . imd - > points [ pointIndex ] ) ;
2007-12-15 07:39:29 -08:00
each . x = psStructure - > pos . x + point - > x ;
2013-01-15 13:24:26 -08:00
each . y = psStructure - > pos . z + ( structHeightScale ( psStructure ) * point - > y ) ;
2007-12-15 07:39:29 -08:00
each . z = psStructure - > pos . y - point - > z ;
2007-06-28 10:47:08 -07:00
2013-01-15 13:24:26 -08:00
if ( rand ( ) % 250 < deltaGraphicsTime )
2007-06-28 10:47:08 -07:00
{
effectSetSize ( 30 ) ;
2008-03-24 09:51:17 -07:00
addEffect ( & each , EFFECT_EXPLOSION , EXPLOSION_TYPE_SPECIFIED , true , getImdFromIndex ( MI_PLASMA ) , 0 ) ;
2007-06-28 10:47:08 -07:00
}
2013-01-15 13:24:26 -08:00
pts [ 1 ] = Vector3f ( each . x - player . p . x , each . y , - ( each . z - player . p . z ) ) ;
2007-06-28 10:47:08 -07:00
2013-01-15 13:24:26 -08:00
pointIndex = rand ( ) % ( psStructure - > sDisplay . imd - > npoints - 1 ) ;
2007-06-28 10:47:08 -07:00
point = & ( psStructure - > sDisplay . imd - > points [ pointIndex ] ) ;
2007-12-15 07:39:29 -08:00
each . x = psStructure - > pos . x + point - > x ;
2013-01-15 13:24:26 -08:00
each . y = psStructure - > pos . z + ( structHeightScale ( psStructure ) * point - > y ) ;
2007-12-15 07:39:29 -08:00
each . z = psStructure - > pos . y - point - > z ;
2007-06-28 10:47:08 -07:00
2013-01-15 13:24:26 -08:00
pts [ 2 ] = Vector3f ( each . x - player . p . x , each . y , - ( each . z - player . p . z ) ) ;
2007-06-28 10:47:08 -07:00
2013-01-15 13:24:26 -08:00
colour = ( psDroid - > action = = DACTION_DEMOLISH ) ? WZCOL_DEMOLISH_BEAM : WZCOL_CONSTRUCTOR_BEAM ;
2007-10-29 15:00:55 -07:00
pie_TransColouredTriangle ( pts , colour ) ;
2007-06-28 10:47:08 -07:00
}