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

6690 lines
125 KiB
C++

#include "game.h"
#include "aeng.h"
#include "poly.h"
#include "sprite.h"
#include "c:\fallen\headers\supermap.h"
#include "c:\fallen\headers\cam.h"
#include "fc.h"
#include <math.h>
#include "panel.h"
#include "drawxtra.h"
#include "statedef.h"
#include "font2d.h"
#include "eway.h"
#include "DDLib.h"
#include "c:\fallen\ddengine\headers\map.h"
#include "memory.h"
#include "mfx.h"
#include "xlat_str.h"
#include "sound_id.h"
#include "pcom.h"
#include "env.h"
#ifdef TARGET_DC
#include "target.h"
#endif
#ifdef TARGET_DC
// intrinsic maths
#include <shsgintr.h>
#endif
#define HEALTH_BAR_WIDTH 100
#define HEALTH_BAR_HEIGHT 10
#define HEALTH_BAR_VERT_GAP 2
#define HEALTH_BAR_HORIZ_GAP 2
#ifdef TARGET_DC
// Slightly shifts each line of text a bit closer than the last to get correct
// drawing behaviour on autosort cards (i.e. the DC).
// This might also be a good idea on the PC, you never know.
#define BODGE_MY_PANELS_PLEASE_BOB Yes please
#endif
#ifdef TARGET_DC
void PANEL_draw_VMU_ammo_counts ( void );
#endif
// Coords of the bottom-left corner.
#ifdef TARGET_DC
// Got to keep away from the edges.
int m_iPanelXPos = 32;
int m_iPanelYPos = 480 - 32;
#else
int m_iPanelXPos = 0;
int m_iPanelYPos = 480;
#endif
#ifdef BODGE_MY_PANELS_PLEASE_BOB
#define DEPTH_BODGE_START (0.95f)
#define DEPTH_BODGE_INC (0.00001f)
float PANEL_fDepthBodgeValue;
#endif
#ifdef BODGE_MY_PANELS_PLEASE_BOB
void PANEL_ResetDepthBodge ( void )
{
PANEL_fDepthBodgeValue = DEPTH_BODGE_START;
}
float PANEL_GetNextDepthBodge ( void )
{
PANEL_fDepthBodgeValue += DEPTH_BODGE_INC;
ASSERT ( PANEL_fDepthBodgeValue < 1.0f );
return ( PANEL_fDepthBodgeValue );
}
#else
// Just use 0.9 as a goodish value.
float PANEL_GetNextDepthBodge ( void )
{
return ( 0.9f );
}
void PANEL_ResetDepthBodge ( void )
{
// Do nothing.
}
#endif
UBYTE PANEL_scanner_poo=0;
void PANEL_draw_quad(
float left,
float top,
float right,
float bottom,
SLONG page,
ULONG colour,
float u1,
float v1,
float u2,
float v2)
{
POLY_Point pp [4];
POLY_Point *quad[4];
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = left;
pp[0].Y = top;
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].u = u1;
pp[0].v = v1;
pp[0].colour = colour;
pp[0].specular = 0xff000000;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].u = u2;
pp[1].v = v1;
pp[1].colour = colour;
pp[1].specular = 0xff000000;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].u = u1;
pp[2].v = v2;
pp[2].colour = colour;
pp[2].specular = 0xff000000;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].u = u2;
pp[3].v = v2;
pp[3].colour = colour;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, page, FALSE, TRUE);
}
void PANEL_crap_text ( int x, int y, char *string )
{
FONT2D_DrawString(
string,
x + 1,
y + 1,
0x000000,
256,
POLY_PAGE_FONT2D,
0);
FONT2D_DrawString(
string,
x,
y,
0xffffee,
256,
POLY_PAGE_FONT2D,
0);
}
void PANEL_draw_face(SLONG x,SLONG y,SLONG face,SLONG size)
{
float left;
float right;
float top;
float bottom;
left = (float) x;
top = (float) y;
right = left + (float) size;
bottom = top + (float) size;
SATURATE(face, 1, 6);
PANEL_draw_quad(
left,
top,
right,
bottom,
POLY_PAGE_FACE1+face-1);
}
#if 0
// No longer used!
void PANEL_draw_angelic_status(SLONG x, SLONG y, SLONG size, SLONG am_i_an_angel)
{
float left;
float right;
float top;
float bottom;
left = (float) x;
top = (float) y;
right = left + (float) size;
bottom = top + (float) size;
SLONG page;
page = (am_i_an_angel) ? POLY_PAGE_ANGEL : POLY_PAGE_DEVIL;
PANEL_draw_quad(
left,
top,
right,
bottom,
page);
}
void PANEL_draw_press_button(SLONG x, SLONG y, SLONG size, SLONG frame)
{
float left;
float right;
float top;
float bottom;
left = (float) x;
top = (float) y;
right = left + (float) size;
bottom = top + (float) size;
SLONG page;
page = (frame & 1) ? POLY_PAGE_PRESS1 : POLY_PAGE_PRESS2;
PANEL_draw_quad(
left,
top,
right,
bottom,
page);
}
#endif
#ifndef TARGET_DC
extern UBYTE sw_hack;
#endif
void PANEL_draw_health_bar(SLONG x,SLONG y,SLONG percentage)
{
#ifndef TARGET_DC
if (!sw_hack)
#endif
{
AENG_draw_rect(x,y,HEALTH_BAR_WIDTH,HEALTH_BAR_HEIGHT,0x000000,2,POLY_PAGE_COLOUR);
}
if(percentage<0)
{
percentage=0;
}
else
if(percentage>100)
{
percentage=100;
}
AENG_draw_rect(x+HEALTH_BAR_HORIZ_GAP,y+HEALTH_BAR_VERT_GAP,((HEALTH_BAR_WIDTH-HEALTH_BAR_HORIZ_GAP*2)*percentage)/100,6,0xff0000,1,POLY_PAGE_COLOUR);
}
#define B0 (1 << 0)
#define B1 (1 << 1)
#define B2 (1 << 2)
#define B3 (1 << 3)
#define B4 (1 << 4)
#define B5 (1 << 5)
#define B6 (1 << 6)
#define PANEL_SEG_L (16.0F)
#define PANEL_SEG_W ( 4.0F)
void PANEL_draw_number(float x, float y, UBYTE digit) // 0 <= digit <= 9... Not ASCII!
{
UBYTE number[10] =
{
B0|B1|B2|B4|B5|B6,
B2|B5,
B0|B2|B3|B4|B6,
B0|B2|B3|B5|B6,
B1|B2|B3|B5,
B0|B1|B3|B5|B6,
B0|B1|B3|B4|B5|B6,
B0|B2|B5,
B0|B1|B2|B3|B4|B5|B6,
B0|B1|B2|B3|B5
};
struct
{
UBYTE d1;
UBYTE d2;
float dx;
float dy;
} bit[7] =
{
{0,1,0.0F,PANEL_SEG_W/2.0F},
{0,2,PANEL_SEG_W/2.0F,0.0F},
{1,3,PANEL_SEG_W/2.0F,0.0F},
{2,3,0.0F,PANEL_SEG_W/2.0F},
{2,4,PANEL_SEG_W/2.0F,0.0F},
{3,5,PANEL_SEG_W/2.0F,0.0F},
{4,5,0.0F,PANEL_SEG_W/2.0F},
};
float x1;
float y1;
float x2;
float y2;
float dx;
float dy;
SLONG b;
ULONG colour;
POLY_Point pp[4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
ASSERT(WITHIN(digit, 0, 9));
for (b = 0; b < 7; b++)
{
//
// Work out the positions of the two points.
//
x1 = x + ((bit[b].d1 & 1) ? PANEL_SEG_L : 0.0F);
y1 = y + (bit[b].d1 >> 1) * PANEL_SEG_L;
x2 = x + ((bit[b].d2 & 1) ? PANEL_SEG_L : 0.0F);
y2 = y + (bit[b].d2 >> 1) * PANEL_SEG_L;
//
// What colour?
//
colour = (number[digit] & (1 << b)) ? 0xeeff0000 : 0x88110000;
//
// The offset vector to make a rect from a line.
//
dx = bit[b].dx;
dy = bit[b].dy;
//
// The four POLY_Points...
//
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = x1 + dx;
pp[0].Y = y1 + dy;
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = colour;
pp[0].specular = 0xff000000;
pp[1].X = x1 - dx;
pp[1].Y = y1 - dy;
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[1].colour = colour;
pp[1].specular = 0xff000000;
pp[2].X = x2 + dx;
pp[2].Y = y2 + dy;
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[2].colour = colour;
pp[2].specular = 0xff000000;
pp[3].X = x2 - dx;
pp[3].Y = y2 - dy;
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
pp[3].colour = colour;
pp[3].specular = 0xff000000;
POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE);
}
}
#ifndef TARGET_DC
typedef struct
{
float time;
float x;
float y;
} PANEL_Store;
#define PANEL_MAX_STORES 8
PANEL_Store PANEL_store[PANEL_MAX_STORES];
SLONG PANEL_store_upto;
#endif
/*
void PANEL_draw_timer_do(float time, float x, float y)
{
CBYTE countdown[32];
CBYTE *ch;
SLONG mins = 0;
ASSERT(time < 1000.0F);
while(time >= 60.0F)
{
mins += 1;
time -= 60.0F;
}
sprintf(countdown, "%02d %05.2f", mins, time);
for (ch = countdown; *ch; ch++)
{
if (WITHIN(*ch, '0', '9'))
{
x -= 11.0F;
}
else
{
x -= 6.0F;
}
}
float x_start = x;
for (ch = countdown; *ch; ch++)
{
if (WITHIN(*ch, '0', '9'))
{
PANEL_draw_number(x, y, *ch - '0');
x += 22.0F;
}
else
{
x += 12.0F;
}
}
//
// An alpha overlay over it all.
//
PANEL_draw_quad(
x_start - 4.0F,
y - 4.0F,
x + 4.0F,
y + 36.0F,
POLY_PAGE_ALPHA_OVERLAY,
0xaa000000);
}
*/
#ifndef TARGET_DC
void PANEL_draw_buffered()
{
SLONG i;
for (i = 0; i < PANEL_store_upto; i++)
{
/*
PANEL_draw_timer_do(
PANEL_store[i].time,
PANEL_store[i].x,
PANEL_store[i].y);
*/
float time = PANEL_store[i].time;
float x = PANEL_store[i].x;
float y = PANEL_store[i].y;
CBYTE countdown[32];
SLONG mins = 0;
ASSERT(time < 1000.0F);
while(time >= 60.0F)
{
mins += 1;
time -= 60.0F;
}
sprintf(countdown, "%02d:%02d", mins, SLONG(time));
if ((time<30)&&!mins)
{
static UWORD pulse=0;
SLONG colour;
pulse+=(TICK_RATIO*80)>>TICK_SHIFT;
colour=(SIN(pulse&2047)>>9)+128;
colour=colour|(colour<<8);
FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xff0000|colour, 256 + 64);
}
else
{
FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xffffff, 256 + 64);
}
}
PANEL_store_upto = 0;
}
#endif
#ifdef TARGET_DC
SLONG slPANEL_draw_timer_time = -1;
void PANEL_draw_timer(SLONG time, SLONG x, SLONG y)
{
slPANEL_draw_timer_time = time;
}
#else
void PANEL_draw_timer(SLONG time, SLONG x, SLONG y)
{
if (WITHIN(PANEL_store_upto, 0, PANEL_MAX_STORES - 1))
{
PANEL_store[PANEL_store_upto].time = float(time) * (1.0F / 100.0F);
PANEL_store[PANEL_store_upto].x = float(x);
PANEL_store[PANEL_store_upto].y = float(y);
PANEL_store_upto += 1;
}
}
#endif
extern void POLY_add_rect(POLY_Point *p1, SLONG width,SLONG height, SLONG page, UBYTE sort_to_front);
void PANEL_draw_local_health(SLONG mx,SLONG my,SLONG mz,SLONG percentage,SLONG radius=60)
{
POLY_Point p1;
float dx,dy,dz,len;
// ASSERT(percentage>=0 && percentage<=100);
dx=POLY_cam_x-(float)mx;
dy=POLY_cam_y-(float)my;
dz=POLY_cam_z-(float)mz;
#ifdef TARGET_DC
len=_InvSqrtA(dx*dx+dy*dy+dz*dz);
dx=(dx*((float)radius))*len;
dy=(dy*((float)radius))*len;
dz=(dz*((float)radius))*len;
#else
len=sqrt(dx*dx+dy*dy+dz*dz);
dx=(dx*((float)radius))/len;
dy=(dy*((float)radius))/len;
dz=(dz*((float)radius))/len;
#endif
//
// move towards the camera a bit so you sort infront of the person
//
POLY_transform(float(mx+dx), float(my+dy-10), float(mz+dz), &p1);
// Roper and others have >100% health - clamp it.
if ( percentage > 100 )
{
percentage = 100;
}
#ifdef TARGET_DC
p1.X-=27.0f;
// Drag it forwards, otherwise at distance it becomes hidden in the pavement.
p1.Z+=0.02F;
p1.colour=0xc0000000|0x0f;
p1.specular=0xff000000;
if(p1.IsValid())
{
POLY_add_rect(&p1, 54,8,POLY_PAGE_COLOUR,0);
}
else
{
return;
}
p1.X+=2.0f;
p1.colour=0x40000000|0xff0000;
p1.specular=0xff000000;
p1.Y+=2.0F;
// Only very slightly forwards - the DC is nice and accurate.
p1.Z+=0.00001F;
if(p1.IsValid())
{
POLY_add_rect(&p1,percentage>>1,4,POLY_PAGE_COLOUR,0);
// AENG_draw_rect(p1.X,p1.Y,percentage>>1,2,0xb0000000,3,POLY_PAGE_COLOUR);
// POLY_add_line(&p1, &p2, (float)2.0, 2.0, POLY_PAGE_COLOUR, 0);
}
#else
// PC version
p1.X-=27.0f;
p1.colour=0xc0000000|0x0f;
p1.specular=0xff000000;
if(p1.IsValid())
{
if (!sw_hack)
{
POLY_add_rect(&p1, 54,4,POLY_PAGE_COLOUR,0);
}
}
else
return;
p1.X+=2.0f;
p1.colour=0x40000000|0xff0000;
p1.specular=0xff000000;
p1.Y+=1.0F;
p1.Z+=0.01F;
if(p1.IsValid())
{
POLY_add_rect(&p1,percentage>>1,2,POLY_PAGE_COLOUR,0);
// AENG_draw_rect(p1.X,p1.Y,percentage>>1,2,0xb0000000,3,POLY_PAGE_COLOUR);
// POLY_add_line(&p1, &p2, (float)2.0, 2.0, POLY_PAGE_COLOUR, 0);
}
#endif
}
void PANEL_draw_gun_sight(SLONG mx,SLONG my,SLONG mz,SLONG accuracy,SLONG scale)
{
SLONG angle,cangle;
SLONG c0;
SLONG dx1,dy1,dx2,dy2;
POLY_Point p1,p2,pstart;
SLONG r_in,r_out;
ULONG col;
SLONG sat_acc;
#define RADIUS_OUT 164
#define RADIUS_IN 84
angle=accuracy;
POLY_transform(float(mx), float(my-36), float(mz), &pstart);
r_in = (POLY_world_length_to_screen(RADIUS_IN) * pstart.Z*scale)/256;
r_out = (POLY_world_length_to_screen(RADIUS_OUT) * pstart.Z*scale)/256;
sat_acc=accuracy;
SATURATE(sat_acc,0,255)
col = sat_acc<<8;
col |= (255-sat_acc)<<16;
for(c0=0;c0<4;c0++)
{
p2=p1=pstart;
switch(c0)
{
case 0:
cangle=+angle;
break;
case 1:
cangle=-angle;
break;
case 2:
cangle=1024+angle;
break;
case 3:
cangle=1024-angle;
break;
}
// cangle+=GAME_TURN<<5;
dx1=((COS(cangle&2047)*r_out)>>16);
dy1=((SIN(cangle&2047)*r_out)>>16);
dx2=((COS(cangle&2047)*r_in)>>16);
dy2=((SIN(cangle&2047)*r_in)>>16);
p1.X+=(float)dx1;
p1.Y+=(float)dy1;
p2.X+=(float)dx2;
p2.Y+=(float)dy2;
p1.colour=0x40000000|col;
p2.colour=0x40000000|col;
p1.specular=0xff000000;
p2.specular=0xff000000;
if(p1.IsValid() && p2.IsValid())
{
SLONG width;
width=(30*scale)>>8;
POLY_add_line(&p1, &p2, (float)width, 0.0F, POLY_PAGE_COLOUR_ALPHA, 0);
// POLY_add_line(&p1, &p2, 20.0F, 0.0F, POLY_PAGE_COLOUR_ALPHA, 0);
}
}
// r_out=(r_out*270)>>8;
// r_out*=(270+256-SATURATE(accuracy,0,256))>>3;
r_in=20+(sat_acc>>2);
r_in=(r_in*scale)>>8;
r_out=r_in+((80*scale)>>8);
r_in = POLY_world_length_to_screen(r_in) * pstart.Z;
r_out = POLY_world_length_to_screen(r_out) * pstart.Z;
for(c0=0;c0<4;c0++)
{
p2=p1=pstart;
switch(c0)
{
case 0:
cangle=512;
break;
case 1:
cangle=-512;
break;
case 2:
cangle=1024;
break;
case 3:
cangle=0;
break;
}
// cangle+=GAME_TURN<<5;
dx1=((COS(cangle&2047)*(r_out))>>16);
dy1=((SIN(cangle&2047)*(r_out))>>16);
dx2=((COS(cangle&2047)*(r_in))>>16);
dy2=((SIN(cangle&2047)*(r_in))>>16);
p1.X+=(float)dx1;
p1.Y+=(float)dy1;
p2.X+=(float)dx2;
p2.Y+=(float)dy2;
p1.colour=0x40000000|col;
p2.colour=0x40000000|col;
p1.specular=0xff000000;
p2.specular=0xff000000;
if(p1.IsValid() && p2.IsValid())
{
SLONG width;
width=(5*scale)>>8;
POLY_add_line(&p1, &p2, (float)width, (float)width,POLY_PAGE_COLOUR_ALPHA, 0);
}
// POLY_add_line(&p1, &p2, 5.0F, 5.0F, POLY_PAGE_COLOUR_ALPHA, 0);
}
}
#if 0
#define COMPASS_MID_X 600.0f
#define COMPASS_MID_Y 40.0f
#define COMPASS_RAD 40.0f
void PANEL_draw_compass_angle(float dx,float dy,ULONG col)
{
float x=0,y=1.0;
POLY_Point p1;
POLY_Point p2;
p1.X = COMPASS_MID_X;
p1.Y = COMPASS_MID_Y;
p1.z = 0.0F;
p1.Z = 1.0F;
p1.u = 1.0F;
p1.v = 1.0F;
p1.colour = col;
p1.specular = 0xff000000;
p2.X = COMPASS_MID_X+dx*COMPASS_RAD;
p2.Y = COMPASS_MID_Y+dy*COMPASS_RAD;
p2.z = 0.0F;
p2.Z = 1.0F;
p2.u = 1.0F;
p2.v = 1.0F;
p2.colour = 0xff0000;
p2.specular = col;
POLY_setclip(&p1);
POLY_setclip(&p2);
if (POLY_valid_line(&p1, &p2))
{
POLY_add_line(&p1, &p2, 1.0, 0.0, POLY_PAGE_COLOUR, 1);
}
/*
p2.X = COMPASS_MID_X+dx*(COMPASS_RAD-10.0);
p2.Y = COMPASS_MID_Y+dy*(COMPASS_RAD-10.0);
p1.z = 0.0F;
p1.Z = 1.0F;
p1.u = 1.0F;
p1.v = 1.0F;
p1.colour = 0xff0000;
p1.specular = 0xff000000;
p2.X = COMPASS_MID_X+dx*COMPASS_RAD;
p2.Y = COMPASS_MID_Y+dy*COMPASS_RAD;
p2.z = 0.0F;
p2.Z = 1.0F;
p2.u = 1.0F;
p2.v = 1.0F;
p2.colour = 0xff0000;
p2.specular = 0xff000000;
POLY_setclip(&p1);
POLY_setclip(&p2);
if (POLY_valid_line(&p1, &p2))
{
POLY_add_line(&p1, &p2, 3.0, 0.0, POLY_PAGE_COLOUR, 1);
}
*/
}
void PANEL_draw_compass_north(void)
{
float x=0,y=1.0;
float dx,dy;
float angle;
POLY_Point p1;
POLY_Point p2;
#ifdef OLD_CAM
angle=CAM_get_ryaw();
angle=PI+angle;
dx=x*cos(angle)-y*sin(angle);
dy=x*sin(angle)+y*cos(angle);
PANEL_draw_compass_angle(dx,dy,0xff0000);
#endif
}
void PANEL_draw_compass_to(SLONG dx,SLONG dy)
{
float fdx,fdy;
float dist;
fdx=dx;
fdy=dy;
dist=sqrt(fdx*fdx+fdy*fdy);
fdx=fdx/dist;
fdy=fdy/dist;
PANEL_draw_compass_angle(dx,dy,0xffff00);
}
#endif
//
// The positions of all the icons on the IC page.
//
#define PANEL_IC_BACKBOX 0 // These are on page 1
#define PANEL_IC_AK47 1
#define PANEL_IC_GRENADE 2
#define PANEL_IC_AK47_AMMO_ONE 3
#define PANEL_IC_AK47_AMMO_GROUP 4
#define PANEL_IC_PISTOL 5
#define PANEL_IC_DARCI_OUTLINE 6
#define PANEL_IC_ROPER_OUTLINE 7
#define PANEL_IC_DARCI 8
#define PANEL_IC_ROPER 9
#define PANEL_IC_SHOTGUN 10
#define PANEL_IC_ROPER_HAND 11
#define PANEL_IC_DARCI_HAND 12
#define PANEL_IC_KNIFE 13
#define PANEL_IC_SHOTGUN_AMMO_GROUP 14
#define PANEL_IC_SHOTGUN_AMMO_ONE 15
#define PANEL_IC_PISTOL_AMMO_GROUP 16
#define PANEL_IC_PISTOL_AMMO_ONE 17
#define PANEL_IC_BIG_AMMO_GROUP 18
#define PANEL_IC_BIG_AMMO_ONE 19
#define PANEL_IC_GRENADE_AMMO_GROUP 20
#define PANEL_IC_GRENADE_AMMO_ONE 21
#define PANEL_IC_DIGIT_0 22
#define PANEL_IC_DIGIT_1 23
#define PANEL_IC_DIGIT_2 24
#define PANEL_IC_DIGIT_3 25
#define PANEL_IC_DIGIT_4 26
#define PANEL_IC_DIGIT_5 27
#define PANEL_IC_DIGIT_6 28
#define PANEL_IC_DIGIT_7 29
#define PANEL_IC_DIGIT_8 30
#define PANEL_IC_DIGIT_9 31
#define PANEL_IC_BASEBALLBAT 32
#define PANEL_IC_EXPLOSIVES 33
#define PANEL_IC_GRIMREAPER 34
#define PANEL_IC_DANGERMETER 35
#define PANEL_IC_BUBBLE_START 36
#define PANEL_IC_BUBBLE_MIDDLE 37
#define PANEL_IC_BUBBLE_END 38
#define PANEL_IC_DOT 39
#define PANEL_IC_CLIP_PISTOL 40
#define PANEL_IC_CLIP_SHOTGUN 41
#define PANEL_IC_CLIP_AK47 42
#define PANEL_IC_GEAR_BOX 43
#define PANEL_IC_GEAR_LOW 44
#define PANEL_IC_GEAR_HIGH 45
#define PANEL_IC_NUMBER 46
typedef struct
{
float u1;
float v1;
float u2;
float v2;
SLONG page;
} PANEL_Ic;
#define PIC(uv) ((uv) / 256.0F)
PANEL_Ic PANEL_ic[PANEL_IC_NUMBER] =
{
{PIC( 0), PIC( 0), PIC( 99), PIC( 81), 0}, // Backbox
{PIC( 1), PIC( 83), PIC(191), PIC(137), 0}, // AK47
{PIC(100), PIC( 1), PIC(140), PIC( 64), 0}, // Grenade
{PIC(141), PIC( 1), PIC(146), PIC( 13), 0}, // Single ammo
{PIC(158), PIC( 1), PIC(208), PIC( 13), 0}, // 10 ammos
{PIC(142), PIC( 15), PIC(221), PIC( 75), 0}, // Pistol
{PIC( 0), PIC(144), PIC( 55), PIC(255), 0}, // Darci outline
{PIC( 55), PIC(144), PIC(109), PIC(256), 0}, // Roper outline
{PIC(110), PIC(149), PIC(160), PIC(255), 0}, // Darci
{PIC(160), PIC(148), PIC(210), PIC(255), 0}, // Roper
{PIC(210), PIC( 95), PIC(254), PIC(256), 0}, // Shotgun
//
// These are all on the second page.
//
#define PICALL1(a,b,c,d) {PIC(a),PIC(b),PIC(c),PIC(d),1}
PICALL1( 1, 1, 75, 50),
PICALL1( 75, 5, 151, 46),
PICALL1( 1, 55, 97, 70),
PICALL1( 5, 81, 45, 93),
PICALL1( 48, 81, 53, 93),
PICALL1( 16, 95, 66, 104),
PICALL1( 5, 95, 10, 104),
PICALL1( 15, 108, 39, 122),
PICALL1( 5, 108, 13, 122),
PICALL1( 18, 123, 54, 141),
PICALL1( 4, 123, 16, 141),
#define PICALL0(a,b,c,d) {PIC(a),PIC(b),PIC(c),PIC(d),0}
//
// These are all squeezed in on the first page.
//
PICALL0(241, 77, 255, 94), // Digit 0
PICALL0(225, 3, 240, 20), // 1
PICALL0(225, 21, 240, 38), // 2
PICALL0(225, 40, 240, 57), // 3
PICALL0(240, 3, 256, 20), // 4
PICALL0(241, 21, 255, 38), // 5
PICALL0(241, 40, 255, 57), // 6
PICALL0(226, 59, 240, 76), // 7
PICALL0(241, 59, 255, 76), // 8,
PICALL0(226, 77, 240, 94), // 9
//
// On the second page.
//
PICALL1( 3, 141, 170, 164), // Baseball bat
PICALL1( 11, 176, 44, 223), // The explosives
PICALL1(208, 187, 236, 214), // The grim reaper
PICALL1(190, 125, 221, 256), // The danger meter
PICALL1(224, 108, 242, 172), // Bubble start
PICALL1(242, 108, 243, 172), // Bubble middle
PICALL1(243, 108, 256, 172), // Bubble end
PICALL1(140, 197, 154, 211), // Dot
PICALL1( 79, 225, 100, 252), // Clips for pistol, shotgun and AK47
PICALL1(121, 227, 143, 252),
PICALL1(152, 225, 174, 250),
PICALL1(205, 215, 254, 256), // Gearbox
PICALL1(178, 225, 199, 249), // Low gear
PICALL1(240, 182, 254, 205), // High gear
};
#define PANEL_PAGE_NORMAL 0
#define PANEL_PAGE_ALPHA 1
#define PANEL_PAGE_ADDITIVE 2
#define PANEL_PAGE_ALPHA_END 3
#define PANEL_PAGE_NUMBER 4
UWORD PANEL_page[4][PANEL_PAGE_NUMBER] =
{
{
POLY_PAGE_IC_NORMAL,
POLY_PAGE_IC_ALPHA,
POLY_PAGE_IC_ADDITIVE,
POLY_PAGE_IC_ALPHA_END
},
{
POLY_PAGE_IC2_NORMAL,
POLY_PAGE_IC2_ALPHA,
POLY_PAGE_IC2_ADDITIVE,
POLY_PAGE_IC2_ALPHA_END
}
};
void PANEL_funky_quad(
SLONG which,
SLONG x,
SLONG y,
SLONG panel_page,
ULONG colour,
float width = -1.0F,
float height = -1.0F)
{
float left;
float top;
float right;
float bottom;
SLONG page;
ASSERT(WITHIN(which, 0, PANEL_IC_NUMBER - 1));
ASSERT(WITHIN(panel_page, 0, PANEL_PAGE_NUMBER - 1));
PANEL_Ic *pi = &PANEL_ic[which];
page = PANEL_page[pi->page][panel_page];
if (which == PANEL_IC_SHOTGUN)
{
//
// The shotgun is on its side.
//
left = float(x);
top = float(y);
if (width == -1.0F) {width = (pi->v2 - pi->v1) * 256.0F;}
if (height == -1.0F) {height = (pi->u2 - pi->u1) * 256.0F;}
right = left + width;
bottom = top + height;
POLY_Point pp [4];
POLY_Point *quad[4];
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = left;
pp[0].Y = top;
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].u = pi->u2;
pp[0].v = pi->v1;
pp[0].colour = colour;
pp[0].specular = 0xff000000;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].u = pi->u2;
pp[1].v = pi->v2;
pp[1].colour = colour;
pp[1].specular = 0xff000000;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].u = pi->u1;
pp[2].v = pi->v1;
pp[2].colour = colour;
pp[2].specular = 0xff000000;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].u = pi->u1;
pp[3].v = pi->v2;
pp[3].colour = colour;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, page, FALSE, TRUE);
}
else
{
left = float(x);
top = float(y);
if (width == -1.0F) {width = (pi->u2 - pi->u1) * 256.0F;}
if (height == -1.0F) {height = (pi->v2 - pi->v1) * 256.0F;}
right = left + width;
bottom = top + height;
PANEL_draw_quad(
left,
top,
right,
bottom,
page,
colour,
pi->u1,
pi->v1,
pi->u2,
pi->v2);
}
}
#ifdef PSX
//
// The global base of the funky panel (useful for splitscreen mode)
//
SLONG PANEL_funky_ybase;
//
// Where to draw bits of the panel.
//
#define PANEL_IC_BBX 30
#define PANEL_IC_BBY (PANEL_funky_ybase - 110)
#define PANEL_IC_PX 10
#define PANEL_IC_PY (PANEL_funky_ybase - 135)
#define PANEL_IC_GX 55
#define PANEL_IC_GY (PANEL_funky_ybase - 67)
#define PANEL_IC_AX 75
#define PANEL_IC_AY (PANEL_funky_ybase - 30)
#define PANEL_IC_MBX 50
#define PANEL_IC_MBY (PANEL_funky_ybase - 100)
#define PANEL_IC_SPLX 40
#define PANEL_IC_SPLY (PANEL_funky_ybase - 124)
#define PANEL_IC_DMX 600
#define PANEL_IC_DMY (PANEL_funky_ybase - 40)
#define PANEL_IC_MESX 140
#define PANEL_IC_MESY (PANEL_funky_ybase - 124)
#define PANEL_IC_CRX 320
#define PANEL_IC_CRY 60
#define PANEL_IC_SCANX (PANEL_IC_BBX + 64)
#define PANEL_IC_SCANY (PANEL_IC_BBY + 25)
#define PANEL_IC_BTX (PANEL_IC_BBX + 30)
#define PANEL_IC_BTY (PANEL_IC_BBY - 20)
#define PANEL_IC_CLIPX 120
#define PANEL_IC_CLIPY (PANEL_funky_ybase - 32)
#define PANEL_IC_GBX (130)
#define PANEL_IC_GBY (PANEL_funky_ybase - 50)
#endif
//
// The funky hearbeat. A circular buffer.
//
typedef struct
{
float x; // Normalised from 0 to 1
float y; // Normalised from -1 to 1
ULONG colour;
} PANEL_Beat;
#define PANEL_NUM_BEATS 32
PANEL_Beat PANEL_beat[2][PANEL_NUM_BEATS];
SLONG PANEL_beat_head[2];
ULONG PANEL_beat_tick[2];
SLONG PANEL_beat_last_ammo[2];
SLONG PANEL_beat_last_specialtype[2];
float PANEL_beat_x[2];
#if 0
//
// Processes and draws the heartbeat. Stamina goes from 0 to 1- where 1 means no
// stamina left... i.e. heart beating amazingly fast.
//
void PANEL_do_heartbeat(SLONG which, float stamina, SLONG death)
{
SLONG i;
SLONG b1;
SLONG b2;
float amp;
float phase;
ULONG beat_colour;
POLY_Point pp [4];
POLY_Point *quad[4];
PANEL_Beat *pb1;
PANEL_Beat *pb2;
SLONG r;
SLONG g;
SLONG c1;
SLONG c2;
SLONG mul;
//
// How fast the ticker sweeps across the display.
//
float dx = 0.02F + stamina * 0.03F;
//
// The amplitude of the two beats.
//
float amp1 = 0.6F + stamina * 0.3F;
float amp2 = 0.3F + stamina * 0.5F;
ULONG now = GetTickCount();
//
// Process the heatbeat 20 times a second. But no more than 4 times a
// gameturn.
//
if (PANEL_beat_tick[which] < now - (1000 / 20) * 4)
{
PANEL_beat_tick[which] = now - (1000 / 20) * 4;
}
//
// The colour fades from green to red depending on your health.
//
if (stamina < 0.5F)
{
beat_colour = 0x00ff00;
}
else
if (stamina < 0.75F)
{
r = SLONG((stamina - 0.5F) * 255.0F / 0.25F);
SATURATE(r, 0, 255);
beat_colour = 0x00ff00 | (r << 16);
}
else
{
g = 255 - SLONG((stamina - 0.75f) * 255.0F / 0.25F);
SATURATE(g, 0, 255);
beat_colour = 0xff0000 | (g << 8);
}
//
// Process the beats.
//
while(PANEL_beat_tick[which] < now)
{
PANEL_beat_tick[which] += 1000 / 20;
PANEL_beat_head[which] += 1;
PANEL_beat_head[which] &= PANEL_NUM_BEATS - 1;
PANEL_beat_x[which] += dx;
if (PANEL_beat_x[which] > 1.0F)
{
PANEL_beat_x[which] -= 1.0F;
}
if (death)
{
//
// The next beat is a dead beat. FLATLINE
//
PANEL_beat[which][PANEL_beat_head[which]].x = PANEL_beat_x[which];
PANEL_beat[which][PANEL_beat_head[which]].y = 0;
PANEL_beat[which][PANEL_beat_head[which]].colour = 0xff0000;
}
else
{
//
// What is the amplitude here?
//
if (WITHIN(PANEL_beat_x[which], 0.1F, 0.5F))
{
amp = 1.0F + (float)sin((-PI * 0.5F) + (PANEL_beat_x[which] - 0.1F) * (2.0F * PI / 0.4F));
amp *= 0.5F * amp1;
}
else
if (WITHIN(PANEL_beat_x[which], 0.6F, 0.9F))
{
amp = 1.0F + (float)sin((-PI * 0.5F) + (PANEL_beat_x[which] - 0.6F) * (2.0F * PI / 0.3F));
amp *= 0.5F * amp2;
}
else
{
amp = 0.00F;
}
//
// How about phase?
//
phase = PANEL_beat_x[which] * 30.0F;
//
// The next beat.
//
PANEL_beat[which][PANEL_beat_head[which]].x = PANEL_beat_x[which];
PANEL_beat[which][PANEL_beat_head[which]].y = sin(phase) * amp;
PANEL_beat[which][PANEL_beat_head[which]].colour = beat_colour;
}
}
//
// Set up the beat quad.
//
pp[0].z = 0.0F;
pp[0].Z = 1.0F;
pp[0].u = 214.0F / 256.0F;
pp[0].v = 2.0F / 256.0F;
pp[0].specular = 0xff000000;
pp[1].z = 0.0F;
pp[1].Z = 1.0F;
pp[1].u = 214.0F / 256.0F;
pp[1].v = 13.0F / 256.0F;
pp[1].specular = 0xff000000;
pp[2].z = 0.0F;
pp[2].Z = 1.0F;
pp[2].u = 220.0F / 256.0F;
pp[2].v = 2.0F / 256.0F;
pp[2].specular = 0xff000000;
pp[3].z = 0.0F;
pp[3].Z = 1.0F;
pp[3].u = 220.0F / 256.0F;
pp[3].v = 13.0F / 256.0F;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
//
// Draw the beats now.
//
b1 = PANEL_beat_head[which];
b2 = PANEL_beat_head[which] - 1;
b1 &= PANEL_NUM_BEATS - 1;
b2 &= PANEL_NUM_BEATS - 1;
//
// Mapping from beat space to screen space.
//
#define PANEL_BEAT_SX(x) (PANEL_IC_BBX + 35 + (x) * 55.0F)
#define PANEL_BEAT_SY(y) (PANEL_IC_BBY + 23 + (y) * 15.0F)
//#define PANEL_BEAT_SX(x) (PANEL_IC_BBX + 35 + (x) * 600.0F)
//#define PANEL_BEAT_SY(y) (PANEL_IC_BBY - 123 + (y) * 100.0F)
for (i = 0; i < PANEL_NUM_BEATS - 1; i++)
{
pb1 = &PANEL_beat[which][b1];
pb2 = &PANEL_beat[which][b2];
//
// Work out the colours of the beats... fading away.
//
r = (pb1->colour >> 16) & 0xff;
g = (pb1->colour >> 8) & 0xff;
mul = PANEL_NUM_BEATS - i;
r = r * mul >> 5;
g = g * mul >> 5;
c1 = (r << 16) | (g << 8);
r = (pb2->colour >> 16) & 0xff;
g = (pb2->colour >> 8) & 0xff;
mul = PANEL_NUM_BEATS - i - 1;
if (mul <= 0)
{
c2 = 0;
}
else
{
r = r * mul >> 5;
g = g * mul >> 5;
c2 = (r << 16) | (g << 8);
}
if (pb1->x > pb2->x)
{
pp[0].X = PANEL_BEAT_SX(pb1->x);
pp[0].Y = PANEL_BEAT_SY(pb1->y) - 5.5F;
pp[0].colour = c1;
pp[1].X = PANEL_BEAT_SX(pb1->x);
pp[1].Y = PANEL_BEAT_SY(pb1->y) + 5.5F;
pp[1].colour = c1;
pp[2].X = PANEL_BEAT_SX(pb2->x);
pp[2].Y = PANEL_BEAT_SY(pb2->y) - 5.5F;
pp[2].colour = c2;
pp[3].X = PANEL_BEAT_SX(pb2->x);
pp[3].Y = PANEL_BEAT_SY(pb2->y) + 5.5F;
pp[3].colour = c2;
POLY_add_quad(quad, POLY_PAGE_IC_ADDITIVE, FALSE, TRUE);
}
b1 -= 1;
b2 -= 1;
b1 &= PANEL_NUM_BEATS - 1;
b2 &= PANEL_NUM_BEATS - 1;
}
}
#endif
//
// The different types of ammo.
//
#define PANEL_AMMO_PISTOL 0
#define PANEL_AMMO_SHOTGUN 1
#define PANEL_AMMO_AK47 2
#define PANEL_AMMO_GRENADE 3
#define PANEL_AMMO_NUMBER 4
typedef struct
{
float width;
float height;
SLONG size_group;
SLONG page_group;
SLONG page_one;
} PANEL_Ammo;
PANEL_Ammo PANEL_ammo[PANEL_AMMO_NUMBER] =
{
{
5.0F,
9.0F,
10,
PANEL_IC_PISTOL_AMMO_GROUP,
PANEL_IC_PISTOL_AMMO_ONE
},
{
5.0F,
12.0F,
8,
PANEL_IC_SHOTGUN_AMMO_GROUP,
PANEL_IC_SHOTGUN_AMMO_ONE
},
{
5.0F,
12.0F,
10,
PANEL_IC_AK47_AMMO_GROUP,
PANEL_IC_AK47_AMMO_ONE,
},
{
12.0F,
18.0F,
3,
PANEL_IC_GRENADE_AMMO_GROUP,
PANEL_IC_GRENADE_AMMO_ONE
},
};
//
// Ammo that has been used up getting tossed off the screen.
//
typedef struct
{
UWORD used;
UWORD type;
float x;
float y;
float angle;
float dx;
float dy;
} PANEL_Toss;
#define PANEL_MAX_TOSSES 8
PANEL_Toss PANEL_toss[PANEL_MAX_TOSSES];
SLONG PANEL_toss_last;
ULONG PANEL_toss_tick;
//
// A floating point number between 0 and 1.0F
//
static inline float frand(void)
{
SLONG irand = rand();
float ans = float(irand) * (1.0F / float(RAND_MAX));
return ans;
}
//
// Creates a new toss.
//
void PANEL_new_toss(
SLONG type,
float sx,
float sy)
{
PANEL_Toss *pt;
PANEL_Ammo *pa;
ASSERT(WITHIN(type, 0, PANEL_AMMO_NUMBER - 1));
PANEL_toss_last += 1;
PANEL_toss_last &= PANEL_MAX_TOSSES - 1;
pt = &PANEL_toss[PANEL_toss_last];
pa = &PANEL_ammo[type];
pt->used = TRUE;
pt->type = type;
pt->x = sx + pa->width * 0.5F;
pt->y = sy + pa->height * 0.5F;
pt->dx = 3.5F + frand();
pt->dy = -5.0F - frand();
pt->angle = 0.0F;
}
//
// Processes and tosses and draws them.
//
void PANEL_do_tosses(void)
{
SLONG i;
POLY_Point pp [4];
POLY_Point *quad[4];
PANEL_Toss *pt;
ULONG now = GetTickCount();
//
// Process 20 times a second but no more than 4 times a frame.
//
if (PANEL_toss_tick < now - (1000 / 20) * 4)
{
PANEL_toss_tick = now - (1000 / 20) * 4;
}
while(PANEL_toss_tick < now)
{
PANEL_toss_tick += 1000 / 20;
for (i = 0; i < PANEL_MAX_TOSSES; i++)
{
pt = &PANEL_toss[i];
if (pt->used)
{
pt->x += pt->dx;
pt->y += pt->dy;
pt->angle += 0.8F;
pt->dx *= 0.9F;
pt->dy += 1.5F;
if (pt->y > 490.0F)
{
pt->used = FALSE;
}
}
}
}
//
// Set up the toss quad.
//
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].colour = 0xffffffff;
pp[0].specular = 0xff000000;
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].colour = 0xffffffff;
pp[1].specular = 0xff000000;
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].colour = 0xffffffff;
pp[2].specular = 0xff000000;
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].colour = 0xffffffff;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
//
// Draw them.
//
{
float ax;
float ay;
float bx;
float by;
SLONG page;
PANEL_Ammo *pa;
for (i = 0; i < PANEL_MAX_TOSSES; i++)
{
pt = &PANEL_toss[i];
if (pt->used)
{
ASSERT(WITHIN(pt->type, 0, PANEL_AMMO_NUMBER - 1));
pa = &PANEL_ammo[pt->type];
ax = (float)sin(pt->angle) * pa->height * 0.5F;
ay = (float)cos(pt->angle) * pa->height * 0.5F;
bx = (float)sin(pt->angle + PI * 0.5F) * pa->width * 0.5F;
by = (float)cos(pt->angle + PI * 0.5F) * pa->width * 0.5F;
pp[0].X = pt->x - bx - ax;
pp[0].Y = pt->y - by - ay;
pp[0].u = PANEL_ic[pa->page_one].u1;
pp[0].v = PANEL_ic[pa->page_one].v1;
pp[1].X = pt->x + bx - ax;
pp[1].Y = pt->y + by - ay;
pp[1].u = PANEL_ic[pa->page_one].u2;
pp[1].v = PANEL_ic[pa->page_one].v1;
pp[2].X = pt->x - bx + ax;
pp[2].Y = pt->y - by + ay;
pp[2].u = PANEL_ic[pa->page_one].u1;
pp[2].v = PANEL_ic[pa->page_one].v2;
pp[3].X = pt->x + bx + ax;
pp[3].Y = pt->y + by + ay;
pp[3].u = PANEL_ic[pa->page_one].u2;
pp[3].v = PANEL_ic[pa->page_one].v2;
page = PANEL_page[PANEL_ic[pa->page_one].page][PANEL_PAGE_ALPHA_END];
POLY_add_quad(quad, page, FALSE, TRUE);
}
}
}
}
extern UBYTE estate;
//
// Draws a face at (x,y). The face is given by the Thing. NULL => Radio message.
//
#define PANEL_FACE_LARGE 1
#define PANEL_FACE_SMALL 2
void PANEL_new_face(
Thing *who,
float x,
float y,
SLONG size)
{
SLONG face;
SLONG page;
float u;
float v;
float width;
float uvwidth;
#define PANEL_FACE_RADIO 0
#define PANEL_FACE_DARCI 1
#define PANEL_FACE_ROPER 2
#define PANEL_FACE_THUG_RASTA 3
#define PANEL_FACE_THUG_GREY 4
#define PANEL_FACE_THUG_RED 5
#define PANEL_FACE_CIV_1 6
#define PANEL_FACE_CIV_2 7
#define PANEL_FACE_CIV_3 8
#define PANEL_FACE_CIV_4 9
#define PANEL_FACE_SLAG 10
#define PANEL_FACE_FAT_SLAG 11
#define PANEL_FACE_HOSTAGE 12
#define PANEL_FACE_WORKMAN 13
#define PANEL_FACE_BOSS_GOATIE 14
#define PANEL_FACE_BOSS_SHAVEN 15
#define PANEL_FACE_COP 16
#define PANEL_FACE_COMMISSIONER 17
#define PANEL_FACE_MIB 18
#define PANEL_FACE_1920S_MAN 19
#define PANEL_FACE_1920S_GIRL 20
#define PANEL_FACE_TRAMP 21
#define PANEL_FACE_NUMBER 22
//
// The position of the faces on each page given in 32 pixel steps.
//
typedef struct
{
UBYTE page;
UBYTE u;
UBYTE v;
} PANEL_Face;
PANEL_Face face_large[PANEL_FACE_NUMBER] =
{
{0,4,4}, // Radio
{0,0,0}, // Darci
{0,2,0}, // Roper
{0,4,0}, // Thug rasta
{1,0,4}, // Thug grey
{0,4,2}, // Thug red
{0,6,2}, // Civ1
{0,6,4}, // Civ2
{0,4,6}, // Civ3
{0,6,6}, // Civ4
{0,0,6}, // Slag
{0,2,6}, // Fat ugly slag
{0,2,4}, // Hostage
{1,2,4}, // Workman,
{0,6,0}, // Boss with a goatie
{0,6,0}, // Boss with no goatie
{0,0,4}, // Cop
{0,6,0}, // Commissioner
{0,0,2}, // MIB
{1,2,6}, // 1920s man
{1,4,6}, // 1920s girl
{1,0,6}, // Tramp
};
PANEL_Face face_small[PANEL_FACE_NUMBER] =
{
{1,2,2}, // Radio
{1,0,0}, // Darci
{1,1,0}, // Roper
{1,2,0}, // Thug rasta
{1,4,0}, // Thug grey
{1,2,1}, // Thug red
{1,3,1}, // Civ1
{1,3,2}, // Civ2
{1,2,3}, // Civ3
{1,3,3}, // Civ4
{1,0,3}, // Slag
{1,1,3}, // Fat ugly slag
{1,1,2}, // Hostage
{1,5,0}, // Workman,
{1,3,0}, // Boss with a goatee
{1,3,0}, // Boss with no goatee
{1,0,2}, // Cop
{1,0,3}, // Commissioner
{1,0,1}, // MIB
{1,6,0}, // 1920s man
{1,7,0}, // 1920s girl
{1,4,1}, // Tramp
};
if (who == NULL || who->Class != CLASS_PERSON)
{
face = PANEL_FACE_RADIO;
}
else
{
switch(who->Genus.Person->PersonType)
{
case PERSON_DARCI:
face = PANEL_FACE_DARCI;
break;
case PERSON_ROPER:
face = PANEL_FACE_ROPER;
break;
case PERSON_COP:
face = PANEL_FACE_COP;
break;
case PERSON_CIV:
switch(who->Draw.Tweened->MeshID)
{
case 7:
//
// Normal (i.e. non-wandering) civs.
//
switch(who->Draw.Tweened->PersonID - 6)
{
case 0:
//
// Pinhead.
//
face = PANEL_FACE_CIV_3;
break;
case 2:
//
// Oriental chap.
//
face = PANEL_FACE_CIV_4;
break;
case 1:
case 3:
//
// Black bloke with moustache.
//
face = PANEL_FACE_CIV_1;
break;
default:
ASSERT(0);
break;
}
break;
case 8:
//
// Male fake wandering civ.
//
face = PANEL_FACE_1920S_MAN;
break;
case 9:
//
// Female fake wandering civ.
//
face = PANEL_FACE_1920S_GIRL;
break;
default:
ASSERT(0);
break;
}
break;
case PERSON_THUG_RASTA:
face = PANEL_FACE_THUG_RASTA;
break;
case PERSON_THUG_GREY:
face = PANEL_FACE_THUG_GREY;
break;
case PERSON_THUG_RED:
face = PANEL_FACE_THUG_RED;
break;
case PERSON_SLAG_TART:
face = PANEL_FACE_SLAG;
break;
case PERSON_SLAG_FATUGLY:
face = PANEL_FACE_FAT_SLAG;
break;
case PERSON_HOSTAGE:
face = PANEL_FACE_HOSTAGE;
break;
case PERSON_MECHANIC:
face = PANEL_FACE_WORKMAN;
break;
case PERSON_TRAMP:
if(estate)
{
face = PANEL_FACE_BOSS_GOATIE;
}
else
{
face = PANEL_FACE_TRAMP;
}
break;
case PERSON_MIB1:
case PERSON_MIB2:
case PERSON_MIB3:
face = PANEL_FACE_MIB; //I'm in disguise as a fat slag
break;
default:
ASSERT(0);
break;
}
}
ASSERT(WITHIN(face, 0, PANEL_FACE_NUMBER - 1));
PANEL_Face *pf;
switch(size)
{
case PANEL_FACE_LARGE:
pf = &face_large[face];
width = 64;
uvwidth = 64 / 256.0F;
break;
case PANEL_FACE_SMALL:
pf = &face_small[face];
width = 32;
uvwidth = 32 / 256.0F;
break;
default:
ASSERT(0);
break;
}
u = float(pf->u) * (32.0F / 256.0F);
v = float(pf->v) * (32.0F / 256.0F);
page = (pf->page) ? POLY_PAGE_FACE2 : POLY_PAGE_FACE1;
PANEL_draw_quad(
x,
y,
x + width,
y + width,
page,
0xffffffff,
u,
v,
u + uvwidth,
v + uvwidth);
}
//
// A circular queue of text messages.
//
// The French actually has a 257-character message. Grrrr.
#define PANEL_TEXT_MAX_LENGTH 300
typedef struct
{
Thing *who; // Who is saying the message. NULL => computer message
CBYTE text[PANEL_TEXT_MAX_LENGTH+2];
SLONG delay; // 0 => unused.
SLONG turns; // The number of turns this message has been alive for.
} PANEL_Text;
#define PANEL_MAX_TEXTS 8 // Power of 2 please!
PANEL_Text PANEL_text[PANEL_MAX_TEXTS];
SLONG PANEL_text_head; // Always acces PANEL_text[PANEL_text_head & (PANEL_MAX_TEXTS - 1)]
SLONG PANEL_text_tail; // Always acces PANEL_text[PANEL_text_tail & (PANEL_MAX_TEXTS - 1)]
ULONG PANEL_text_tick;
void PANEL_new_text_init(void)
{
memset(PANEL_text, 0, sizeof(PANEL_text));
PANEL_text_head = 0;
PANEL_text_tail = 0;
PANEL_text_tick = 0;
}
void PANEL_new_text(Thing *who, SLONG delay, CBYTE *fmt, ...)
{
CBYTE *ch;
PANEL_Text *pt;
//
// Early out on NULL strings or strings with just spaces in them.
//
if (fmt == NULL)
{
return;
}
for (ch = fmt; *ch; ch++)
{
if (!isspace(*ch))
{
goto found_non_white_space;
}
}
return;
found_non_white_space:;
//
// Work out the real message.
//
CBYTE message[1024];
va_list ap;
va_start(ap, fmt);
vsprintf(message, fmt, ap);
va_end (ap);
//
// Make sure the message isn't too long.
//
if (strlen(message) >= PANEL_TEXT_MAX_LENGTH)
{
ASSERT(0);
//
// strlen doesn't include the NULL byte.
//
return;
}
/*
//
// Convert to uppercase.
//
for (ch = message; *ch; *ch++ = toupper(*ch));
*/
//
// Do we already have this message?
//
SLONG i;
for (i = 0; i < PANEL_MAX_TEXTS; i++)
{
pt = &PANEL_text[i];
if (pt->delay)
{
if (pt->who == who)
{
if (strcmp(pt->text, message) == 0)
{
//
// Don't put up the same message twice.
//
pt->delay = delay;
return;
}
}
}
}
//
// Create a new message at the tail of the queue.
//
pt = &PANEL_text[PANEL_text_tail & (PANEL_MAX_TEXTS - 1)];
pt->who = who;
pt->delay = delay;
pt->turns = 0;
strcpy(pt->text, message);
//
// Process the message so we put in vertical '|'s
//
PANEL_text_tail += 1;
if (!who) MFX_play_ambient(0,S_RADIO_MESSAGE,0);
}
void PANEL_new_text_process()
{
SLONG i;
PANEL_Text *pt;
ULONG now = GetTickCount();
//
// Process 20 times a second but no more than 4 times a frame.
//
if (PANEL_text_tick < now - (1000 / 10) * 4)
{
PANEL_text_tick = (now - (1000 / 10) * 4);
}
while(PANEL_text_tick < now)
{
PANEL_text_tick += 1000 / 10;
for (i = 0; i < PANEL_MAX_TEXTS; i++)
{
pt = &PANEL_text[i];
if (pt->delay)
{
pt->delay -= 1000 / 10;
if (pt->delay < 0)
{
pt->delay = 0;
}
}
}
}
for (i = 0; i < PANEL_MAX_TEXTS; i++)
{
pt = &PANEL_text[i];
pt->turns += 1;
}
}
#ifdef PSX
void PANEL_new_text_draw()
{
SLONG i;
SLONG ybase;
SLONG y = PANEL_IC_MESY;
SLONG height;
PANEL_Text *pt;
for (i = PANEL_text_head; i < PANEL_text_tail; i++)
{
pt = &PANEL_text[i & (PANEL_MAX_TEXTS - 1)];
if (i == PANEL_text_head)
{
if (pt->delay == 0)
{
PANEL_text_head += 1;
}
}
if (pt->delay != 0)
{
//
// Draw this message. Start off with the face.
//
ybase = y;
PANEL_new_face(
pt->who,
PANEL_IC_MESX,
ybase - 3,
PANEL_FACE_SMALL);
/*
PANEL_funky_quad(
pt->face,
PANEL_IC_MESX,
ybase - 3,
PANEL_PAGE_NORMAL,
0xffffff);
*/
//
// The text....
//
height = FONT2D_DrawStringWrap(pt->text, PANEL_IC_MESX + 36 + 18, y, 0x00ff00) - y;
height += 25;
//
// The speech bubble.
//
PANEL_funky_quad(
PANEL_IC_BUBBLE_START,
PANEL_IC_MESX + 36,
ybase - 3,
PANEL_PAGE_ALPHA,
0xffffffff,
18.0F,
height);
PANEL_funky_quad(
PANEL_IC_BUBBLE_MIDDLE,
PANEL_IC_MESX + 36 + 18,
ybase - 3,
PANEL_PAGE_ALPHA,
0xffffffff,
float(FONT2D_rightmost_x) - (PANEL_IC_MESX + 36 + 18),
height);
PANEL_funky_quad(
PANEL_IC_BUBBLE_END,
float(FONT2D_rightmost_x),
ybase - 3,
PANEL_PAGE_ALPHA,
0xffffffff,
-1.0F,
height);
if (height < 34)
{
height = 34;
}
y += height;
}
}
}
#endif
//
// The help message.
//
CBYTE PANEL_help_message[256];
SLONG PANEL_help_timer;
void PANEL_new_help_message(CBYTE *fmt, ...)
{
//
// Work out the real message.
//
va_list ap;
va_start(ap, fmt);
vsprintf(PANEL_help_message, fmt, ap);
va_end (ap);
//
// How long the message lasts for.
//
PANEL_help_timer = 160 * 20 * 5; // 5 seconds....
}
void PANEL_help_message_do()
{
PANEL_help_timer -= 160 * TICK_RATIO >> TICK_SHIFT;
if (PANEL_help_timer <= 0)
{
PANEL_help_timer = 0;
}
else
{
//
// Draw the help text in a speech bubble at the top of the screen.
//
SLONG height;
#define PANEL_IC_HELPX 10
#define PANEL_IC_HELPY 10
height = FONT2D_DrawStringWrap(PANEL_help_message, PANEL_IC_HELPX + 18, PANEL_IC_HELPY, 0x00ff00) - PANEL_IC_HELPY;
height += 25;
//
// The speech bubble.
//
PANEL_funky_quad(
PANEL_IC_BUBBLE_START,
PANEL_IC_HELPX,
PANEL_IC_HELPY - 3,
PANEL_PAGE_ALPHA,
0xffffffff,
18.0F,
height);
PANEL_funky_quad(
PANEL_IC_BUBBLE_MIDDLE,
PANEL_IC_HELPX + 18,
PANEL_IC_HELPY - 3,
PANEL_PAGE_ALPHA,
0xffffffff,
float(FONT2D_rightmost_x) - (PANEL_IC_HELPX + 18),
height);
PANEL_funky_quad(
PANEL_IC_BUBBLE_END,
float(FONT2D_rightmost_x),
PANEL_IC_HELPY - 3,
PANEL_PAGE_ALPHA,
0xffffffff,
-1.0F,
height);
}
}
//
// The panel in widscreen cut-scene mode.
//
THING_INDEX PANEL_wide_top_person;
THING_INDEX PANEL_wide_bot_person;
SLONG PANEL_wide_top_is_talking; // TRUE/FALSE for who is talking now
CBYTE PANEL_wide_text[256];
void PANEL_new_widescreen()
{
//
// We have to stop the clipping getting rid of whatever we are doing!
//
extern float POLY_screen_clip_top;
extern float POLY_screen_clip_bottom;
POLY_screen_clip_top = 0.0F;
POLY_screen_clip_bottom = float(DisplayHeight);
//
// Clear the widescreen borders to black.
//
PANEL_draw_quad(
0.0F,
0.0F,
float(DisplayWidth),
80.0F,
POLY_PAGE_COLOUR,
0x00000000);
PANEL_draw_quad(
0.0F,
float(DisplayHeight) - 80.0F,
float(DisplayWidth),
float(DisplayHeight),
POLY_PAGE_COLOUR,
0x00000000);
//
// Who is talking?
//
if (EWAY_conversation_happening(
&PANEL_wide_top_person,
&PANEL_wide_bot_person))
{
//
// Sort in thing number order!
//
if (PANEL_wide_top_person > PANEL_wide_bot_person)
{
SWAP(PANEL_wide_top_person, PANEL_wide_bot_person);
}
}
//
// Steal new_text messages!
//
SLONG i;
PANEL_Text *pt;
for (i = 0; i < PANEL_MAX_TEXTS; i++)
{
pt = &PANEL_text[i];
if (pt->delay && pt->turns <= 1)
{
if (pt->who == NULL)
{
//
// This is a message that goes on the bottom.
//
strcpy(PANEL_wide_text, pt->text);
PANEL_wide_top_is_talking = FALSE;
pt->delay = 0;
}
else
{
if (THING_NUMBER(pt->who) == PANEL_wide_top_person)
{
//
// This is a message that goes on the top.
//
strcpy(PANEL_wide_text, pt->text);
PANEL_wide_top_is_talking = TRUE;
pt->delay = 0;
}
else
{
//
// This is a message that goes on the bottom.
//
strcpy(PANEL_wide_text, pt->text);
PANEL_wide_top_is_talking = FALSE;
PANEL_wide_bot_person = THING_NUMBER(pt->who);
pt->delay = 0;
}
}
}
}
//
// Draw the two faces.
//
if (PANEL_wide_top_person != NULL)
{
PANEL_new_face(
TO_THING(PANEL_wide_top_person),
float(DisplayWidth) - 72.0F,
8.0F,
PANEL_FACE_LARGE);
}
//
// Draw the text for who is speaking.
//
if (PANEL_wide_text[0])
{
PANEL_new_face(
(PANEL_wide_bot_person) ? TO_THING(PANEL_wide_bot_person) : NULL,
8.0F,
float(DisplayHeight) - 72.0F,
PANEL_FACE_LARGE);
if (PANEL_wide_top_is_talking)
{
// Need to move this down so the bottom line is on the bottom of the black bit.
// This keeps the first line out of the 32-pixel "danger zone" that may not be
// shown on crap TV.
SLONG iYpos = FONT2D_DrawStringRightJustify(
PANEL_wide_text,
DisplayWidth - 80,
0,
0xff0ffff,
256,
POLY_PAGE_FONT2D,
0,
TRUE);
iYpos = 75 - iYpos;
FONT2D_DrawStringRightJustify(
PANEL_wide_text,
DisplayWidth - 80,
iYpos,
0xff0ffff,
256,
POLY_PAGE_FONT2D,
0,
FALSE);
}
else
{
FONT2D_DrawStringWrap(
PANEL_wide_text,
80,
DisplayHeight - 80 + 5,
0xffffff);
}
}
}
#define PANEL_MAX_BEACON_COLOURS 12
ULONG PANEL_beacon_colour[PANEL_MAX_BEACON_COLOURS] =
{
0xffff00,
0xccff00,
0x4488ff,
0xff0000,
0x00ff00,
0x0000ff,
0xff4400,
0xffffff,
0xff00ff,
0xaaffaa,
0x00ffff,
0xff4488
};
#ifdef PSX
//
// Draws the map beacons...
//
void PANEL_draw_beacons(void)
{
SLONG i;
float dx;
float dz;
float dist;
float dangle;
float score;
float ax;
float ay;
float bx;
float by;
float cx;
float cy;
POLY_Point pp [3];
POLY_Point *tri[3];
MAP_Beacon *mb;
ULONG colour;
Thing *darci = NET_PERSON(0);
SLONG best_beacon = NULL;
float best_score = float(INFINITY);
for (i = 1; i < MAP_MAX_BEACONS; i++)
{
mb = &MAP_beacon[i];
if (!mb->used)
{
continue;
}
if (mb->track_thing)
{
Thing *p_track = TO_THING(mb->track_thing);
mb->wx = p_track->WorldPos.X >> 8;
mb->wz = p_track->WorldPos.Z >> 8;
extern SLONG is_person_dead(Thing *p_person);
if (p_track->Class == CLASS_PERSON && p_track->State == STATE_DEAD)
{
//
// Don't draw beacons to dead people.
//
if (p_track->SubState == SUB_STATE_DEAD_INJURED)
{
//
// Except if they're only injured...
//
}
else
{
continue;
}
}
}
colour = PANEL_beacon_colour[i % PANEL_MAX_BEACON_COLOURS] | (0xff000000);
//
// Work out the distance and relative angle of this beacon from darci.
//
dx = float(mb->wx - (darci->WorldPos.X >> 8));
dz = float(mb->wz - (darci->WorldPos.Z >> 8));
dist = fabs(dx) + fabs(dz);
if (dist < 256.0F * 4.0F)
{
score = dist * (1.0F / (256.0F * 4.0F));
score *= 2.0F * PI * 22.0F / 360.0F;
PANEL_funky_quad(
PANEL_IC_DOT,
PANEL_IC_SCANX - 7.0F,
PANEL_IC_SCANY - 7.0F,
PANEL_PAGE_ALPHA_END,
colour);
}
else
{
if (PANEL_scanner_poo)
dangle = (float)atan2(dx,dz) - float(darci->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F);
else
dangle = (float)atan2(dx,dz) - float(FC_cam[0].yaw>>8) * (2.0F * PI / 2048.0F);
score = (float)fmod(dangle, 2.0F * PI) - PI;
if (score > +PI) {score -= 2.0F * PI;}
if (score < -PI) {score += 2.0F * PI;}
//
// The arrow positions...
//
ax = (float)sin(dangle - 0.5F) * 33.0F * 1.5F;
ay = (float)cos(dangle - 0.5F) * 20.0F * 1.5F;
bx = (float)sin(dangle + 0.5F) * 33.0F * 1.5F;
by = (float)cos(dangle + 0.5F) * 20.0F * 1.5F;
cx = (float)sin(dangle) * 33.0F * -0.25F;
cy = (float)cos(dangle) * 20.0F * -0.25F;
//
// Draw an arrow in this direction.
//
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = PANEL_IC_SCANX + cx;
pp[0].Y = PANEL_IC_SCANY + cy;
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].u = 134.0F / 256.0F;
pp[0].v = 189.0F / 256.0F;
pp[0].colour = colour;
pp[0].specular = 0xff000000;
pp[1].X = PANEL_IC_SCANX + ax;
pp[1].Y = PANEL_IC_SCANY + ay;
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].u = 153.0F / 256.0F;
pp[1].v = 180.0F / 256.0F;
pp[1].colour = colour;
pp[1].specular = 0xff000000;
pp[2].X = PANEL_IC_SCANX + bx;
pp[2].Y = PANEL_IC_SCANY + by;
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].u = 153.0F / 256.0F;
pp[2].v = 198.0F / 256.0F;
pp[2].colour = colour;
pp[2].specular = 0xff000000;
tri[0] = &pp[0];
tri[1] = &pp[1];
tri[2] = &pp[2];
POLY_add_triangle(tri, POLY_PAGE_IC2_ALPHA_END, FALSE, TRUE);
}
if (fabs(score) < best_score)
{
best_score = fabs(score);
best_beacon = i;
}
}
if (best_beacon)
{
ASSERT(WITHIN(best_beacon, 1, MAP_MAX_BEACONS - 1));
mb = &MAP_beacon[best_beacon];
extern CBYTE *EWAY_get_mess(SLONG index);
FONT2D_DrawString(
EWAY_get_mess(mb->index),
PANEL_IC_BTX + 2,
PANEL_IC_BTY + 2,
0x00000000,
192);
FONT2D_DrawString(
EWAY_get_mess(mb->index),
PANEL_IC_BTX,
PANEL_IC_BTY,
PANEL_beacon_colour[best_beacon % PANEL_MAX_BEACON_COLOURS],
192);
}
}
#endif
#define PANEL_WHO_DARCI 0
#define PANEL_WHO_ROPER 1
#ifdef PSX
void PANEL_new_funky_do(SLONG which, SLONG where)
{
if (EWAY_stop_player_moving())
{
//
// There is a widescreen cutscene playing.
//
PANEL_new_widescreen();
return;
}
else
{
PANEL_wide_top_person = NULL;
PANEL_wide_bot_person = NULL;
PANEL_wide_top_is_talking = FALSE;
PANEL_wide_text[0] = '\000';
}
SLONG i;
ULONG health_colour;
SLONG which_gun;
SLONG which_ammo;
SLONG which_dx = 0;
SLONG which_dy = 0;
SLONG clip_which = 0;
SLONG clip_number = 0;
SLONG who; // One of PANEL_WHO_*
SLONG health; // From 0 to 256
SLONG stamina; // From 0 to 256
SLONG specialtype; // The gun in use or NULL if not using a special,
SLONG ammo; // The amount of ammo used by the gun
ASSERT(WITHIN(which, 0, 1));
Thing *darci = NET_PERSON(which);
Thing *player = NET_PLAYER(which);
Thing *p_special;
if (darci->Genus.Person->SpecialUse)
{
p_special = TO_THING(darci->Genus.Person->SpecialUse);
specialtype = p_special->Genus.Special->SpecialType;
ammo = p_special->Genus.Special->ammo;
}
else
{
specialtype = NULL;
ammo = 0;
}
if (darci->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
{
specialtype = SPECIAL_GUN;
ammo = darci->Genus.Person->Ammo;
}
who = (darci->Genus.Person->PersonType == PERSON_ROPER) ? PANEL_WHO_ROPER : PANEL_WHO_DARCI;
health = darci->Genus.Person->Health;
stamina = darci->Genus.Person->Stamina;
//
// Set where the bottom of the panel should be.
//
PANEL_funky_ybase = (where & 1) ? (DisplayHeight >> 1) : DisplayHeight;
//
// The background and the character.
//
PANEL_funky_quad(
PANEL_IC_BACKBOX,
PANEL_IC_BBX,
PANEL_IC_BBY,
PANEL_PAGE_NORMAL,
0xffffffff);
PANEL_funky_quad(
(who == PANEL_WHO_DARCI) ? PANEL_IC_DARCI : PANEL_IC_ROPER,
PANEL_IC_PX,
PANEL_IC_PY,
PANEL_PAGE_ALPHA,
0xffffffff);
//
// The colour we draw the health outline.
//
{
SLONG r = 0;
SLONG g = 0;
SLONG b = 0;
if (health > 133)
{
r = 255 - ((health - 133) * 255) / 67;
g = 255;
}
else
if (health < 66)
{
r = 100 + (health * 155) / 66;
g = 0;
}
else
{
r = 255;
g = ((health - 66) * 255) / 66;
}
SATURATE(r, 0, 255);
SATURATE(g, 0, 255);
health_colour = (r << 16) | (g << 8) | 0x10; // A little bit of blue...
}
PANEL_funky_quad(
(who == PANEL_WHO_DARCI) ? PANEL_IC_DARCI_OUTLINE : PANEL_IC_ROPER_OUTLINE,
PANEL_IC_PX - 6,
PANEL_IC_PY - 3,
PANEL_PAGE_ADDITIVE,
health_colour);
#if WEVE_REPLACED_THE_HEARTBEAT_WITH_A_SCANNER
//
// No heart beat any more :(
//
PANEL_do_heartbeat(which, 1.0F - float(stamina) * (1.0F / 256.0F), darci->State == STATE_DEAD);
#endif
//
// If the player is holding a grenade that has had its pin pulled then
// show how long the grenade has before it goes off.
//
{
Thing *p_special;
if (darci->Genus.Person->SpecialUse)
{
p_special = TO_THING(darci->Genus.Person->SpecialUse);
if (p_special->Genus.Special->SpecialType == SPECIAL_GRENADE &&
p_special->SubState == SPECIAL_SUBSTATE_ACTIVATED)
{
//
// Alert! The player is holding a primed grenade!
//
ULONG colour;
SLONG secsleft;
secsleft = p_special->Genus.Special->timer / (16 * 20) + 1;
if (secsleft > 6)
{
secsleft = 6;
}
switch(secsleft)
{
case 0:
case 1:
colour = 0xff3300;
break;
case 2:
colour = 0xff8800;
break;
case 3:
colour = 0x88ff00;
break;
default:
colour = 0x00ff00;
break;
}
PANEL_funky_quad(
PANEL_IC_DIGIT_0 + secsleft,
PANEL_IC_MBX,
PANEL_IC_MBY,
PANEL_PAGE_ADDITIVE,
colour);
}
}
}
//
// Which gun shall we draw.
//
switch(specialtype)
{
default:
if (who == PANEL_WHO_DARCI)
{
which_gun = PANEL_IC_DARCI_HAND;
}
else
{
which_gun = PANEL_IC_ROPER_HAND;
}
which_ammo = -1;
break;
case SPECIAL_GUN:
which_gun = PANEL_IC_PISTOL;
which_ammo = PANEL_AMMO_PISTOL;
clip_which = PANEL_IC_CLIP_PISTOL;
clip_number = darci->Genus.Person->ammo_packs_pistol;
break;
case SPECIAL_AK47:
which_gun = PANEL_IC_AK47;
which_ammo = PANEL_AMMO_AK47;
which_dx = -45;
clip_which = PANEL_IC_CLIP_AK47;
clip_number = darci->Genus.Person->ammo_packs_ak47;
break;
case SPECIAL_BASEBALLBAT:
which_gun = PANEL_IC_BASEBALLBAT;
which_ammo = -1;
which_dx = -50;
break;
case SPECIAL_KNIFE:
which_gun = PANEL_IC_KNIFE;
which_ammo = -1;
which_dy = 15;
break;
case SPECIAL_SHOTGUN:
which_gun = PANEL_IC_SHOTGUN;
which_ammo = PANEL_AMMO_SHOTGUN;
which_dx = -35;
which_dy = 10;
clip_which = PANEL_IC_CLIP_SHOTGUN;
clip_number = darci->Genus.Person->ammo_packs_shotgun;
break;
case SPECIAL_GRENADE:
which_gun = PANEL_IC_GRENADE;
which_ammo = PANEL_AMMO_GRENADE;
break;
case SPECIAL_EXPLOSIVES:
which_gun = PANEL_IC_EXPLOSIVES;
which_ammo = PANEL_AMMO_GRENADE;
break;
}
PANEL_funky_quad(
which_gun,
PANEL_IC_GX + which_dx,
PANEL_IC_GY + which_dy,
PANEL_PAGE_ALPHA_END,
0xffffffff);
if (which_ammo == -1)
{
//
// This weapon has no ammo.
//
}
else
{
SLONG ax = PANEL_IC_AX;
SLONG ay = PANEL_IC_AY;
ASSERT(WITHIN(which_ammo, 0, PANEL_AMMO_NUMBER - 1));
PANEL_Ammo *pa = &PANEL_ammo[which_ammo];
while(ammo >= pa->size_group)
{
PANEL_funky_quad(
pa->page_group,
ax,
ay,
PANEL_PAGE_ALPHA_END,
0xffffffff);
ax += 2;
ay += 7;
ammo -= pa->size_group;
}
for (i = 0; i < ammo; i++)
{
PANEL_funky_quad(
pa->page_one,
ax,
ay,
PANEL_PAGE_ALPHA_END,
0xffffffff);
ax += pa->width;
}
if (PANEL_beat_last_specialtype[which] == specialtype && PANEL_beat_last_ammo[which] > ammo)
{
while(i < PANEL_beat_last_ammo[which])
{
PANEL_new_toss(
which_ammo,
float(ax),
float(ay));
ax += pa->width;
if (i % pa->size_group == 0)
{
ax -= pa->width * pa->size_group - 2;
ay += 7;
}
else
{
}
i += 1;
}
}
}
if (clip_number)
{
PANEL_funky_quad(
clip_which,
PANEL_IC_CLIPX,
PANEL_IC_CLIPY,
PANEL_PAGE_ALPHA_END,
0xffffffff);
{
CBYTE text[16];
sprintf(text, "x%d", clip_number);
extern void FONT2D_DrawString_NoTrueType(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade);
FONT2D_DrawString_NoTrueType(
text,
PANEL_IC_CLIPX + 20,
PANEL_IC_CLIPY + 4,
0x00ff00,
256,
POLY_PAGE_FONT2D,
0);
}
}
// skip_the_gun_and_ammo:;
PANEL_do_tosses();
PANEL_beat_last_specialtype[which] = specialtype;
PANEL_beat_last_ammo[which] = ammo;
//
// The grimreapers for the number of civs you've killed.
//
{
float x;
x = PANEL_IC_SPLX;
for (i = 0; i < player->Genus.Player->RedMarks; i++)
{
PANEL_funky_quad(
PANEL_IC_GRIMREAPER,
x,
PANEL_IC_SPLY,
PANEL_PAGE_ALPHA_END,
0xffffffff);
x += 20.0F;
if (i == 4)
{
x += 12.0F;
}
}
}
//
// The danger meter.
//
{
ULONG danger_colour;
switch(player->Genus.Player->Danger)
{
case 0:
goto no_danger_meter;
case 1: danger_colour = 0xffff0000; break;
case 2: danger_colour = 0xffffdd00; break;
case 3: danger_colour = 0xff00dd00; break;
default:
break;
}
PANEL_funky_quad(
PANEL_IC_DANGERMETER,
PANEL_IC_DMX,
PANEL_IC_DMY,
PANEL_PAGE_ALPHA,
danger_colour);
}
no_danger_meter:;
//
// The crime rate.
//
if (GAME_FLAGS & GF_SHOW_CRIMERATE)
{
CBYTE crimerate[128];
sprintf(crimerate, "%d%% ", CRIME_RATE);
FONT2D_DrawStringCentred(
crimerate,
PANEL_IC_CRX,
PANEL_IC_CRY,
0x00ff00);
FONT2D_DrawStringCentred(
XLAT_str(X_CRIME_RATE,crimerate),
PANEL_IC_CRX,
PANEL_IC_CRY - 20,
0x00ff00);
}
//
// The text.
//
PANEL_new_text_process();
PANEL_new_text_draw();
PANEL_help_message_do();
if (darci->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
//
// Draw the gear you are in.
//
Thing *p_vehicle = TO_THING(darci->Genus.Person->InCar);
PANEL_funky_quad(
PANEL_IC_GEAR_BOX,
PANEL_IC_GBX,
PANEL_IC_GBY,
PANEL_PAGE_ALPHA,
0xffffffff);
if (p_vehicle->Genus.Vehicle->Siren)
{
//
// High gear.
//
PANEL_funky_quad(
PANEL_IC_GEAR_HIGH,
PANEL_IC_GBX + 25 - 3,
PANEL_IC_GBY + 18 - 21,
PANEL_PAGE_ALPHA_END,
0xffffffff);
}
else
{
//
// Low gear.
//
PANEL_funky_quad(
PANEL_IC_GEAR_LOW,
PANEL_IC_GBX + 25 - 17,
PANEL_IC_GBY + 18 - 20,
PANEL_PAGE_ALPHA_END,
0xffffffff);
}
}
//
// The on-screen map beacons.
//
PANEL_draw_beacons();
}
void PANEL_new_funky()
{
//
// We have to stop the clipping getting rid of whatever we are doing!
//
extern float POLY_screen_clip_top;
extern float POLY_screen_clip_bottom;
POLY_screen_clip_top = 0.0F;
POLY_screen_clip_bottom = float(DisplayHeight);
if (FC_cam[1].focus)
{
//
// We are in splitscreen mode.
//
PANEL_new_funky_do(0,1);
// PANEL_new_funky_do(1,0);
}
else
{
//
// One player mode.
//
PANEL_new_funky_do(0,0);
}
}
#endif //#ifdef PSX
void PANEL_start(void)
{
#ifndef TARGET_DC
POLY_frame_init(FALSE, FALSE);
#endif
}
void PANEL_finish(void)
{
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
#endif
}
// ========================================================
//
// FADEOUT STUFF
//
// ========================================================
SLONG PANEL_fadeout_time; // 0 => No fadeout currently active.
void PANEL_fadeout_init()
{
PANEL_fadeout_time = 0;
}
void PANEL_fadeout_start()
{
if (!PANEL_fadeout_time)
{
PANEL_fadeout_time = GetTickCount();
}
}
float angle_mul = 0.004F;
float zoom_mul = 0.500F;
void PANEL_fadeout_draw()
{
if (PANEL_fadeout_time)
{
#ifndef TARGET_DC
POLY_frame_init(FALSE,FALSE);
#endif
//
// Make the fadeout zoom in and turn.
//
float angle = float(GetTickCount() - PANEL_fadeout_time) * angle_mul;
float zoom = angle * zoom_mul;
float xdu = -(float)cos(angle) * zoom * 1.33F;
float xdv = (float)sin(angle) * zoom * 1.33F;
float ydu = (float)sin(angle) * zoom;
float ydv = (float)cos(angle) * zoom;
SLONG colour;
colour = 0xffffffff;
//
// Add a single crappy poly!
//
POLY_Point pp [4];
POLY_Point *quad[4];
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = 0.0F;
pp[0].Y = 0.0F;
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].u = 0.5F - xdu - ydu;
pp[0].v = 0.5F - xdv - ydv;
pp[0].colour = colour;
pp[0].specular = 0xff000000;
pp[1].X = 640.0F;
pp[1].Y = 0.0F;
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].u = 0.5F + xdu - ydu;
pp[1].v = 0.5F + xdv - ydv;
pp[1].colour = colour;
pp[1].specular = 0xff000000;
pp[2].X = 0.0F;
pp[2].Y = 480.0F;
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].u = 0.5F - xdu + ydu;
pp[2].v = 0.5F - xdv + ydv;
pp[2].colour = colour;
pp[2].specular = 0xff000000;
pp[3].X = 640.0F;
pp[3].Y = 480.0F;
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].u = 0.5F + xdu + ydu;
pp[3].v = 0.5F + xdv + ydv;
pp[3].colour = colour;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, POLY_PAGE_FADECAT, FALSE, TRUE);
//
// Darken the screen at the end.
//
if (GetTickCount() > (unsigned)PANEL_fadeout_time + 768)
{
SLONG bright;
//
// Fadeout the colour.
//
bright = GetTickCount() - (PANEL_fadeout_time + 768);
SATURATE(bright, 0, 255);
colour = bright << 24;
#ifdef TARGET_DC
// On the DC, there's a hardware bug that means the UV clamp down't quite work.
// So we need to darken the whole screen this way.
PANEL_draw_quad(
0.0f,
0.0f,
640.0f,
480.0f,
POLY_PAGE_ALPHA,
colour);
#else
#define PANEL_BLACKEN_WIDTH 70
PANEL_draw_quad(
320.0F - PANEL_BLACKEN_WIDTH,
240.0F - PANEL_BLACKEN_WIDTH,
320.0F + PANEL_BLACKEN_WIDTH,
240.0F + PANEL_BLACKEN_WIDTH,
POLY_PAGE_ALPHA,
colour);
#endif
}
#ifndef TARGET_DC
POLY_frame_draw(FALSE,FALSE);
#endif
}
}
SLONG PANEL_fadeout_finished()
{
if (PANEL_fadeout_time)
{
if (GetTickCount() > (unsigned)PANEL_fadeout_time + 1024)
{
return TRUE;
}
}
return FALSE;
}
//
// The coordinates of each sprite
//
#define PANEL_LSPRITE_BACKGROUND 0
#define PANEL_LSPRITE_AK47 1
#define PANEL_LSPRITE_SHOTGUN 2
#define PANEL_LSPRITE_LOW_GEAR 3
#define PANEL_LSPRITE_HIGH_GEAR 4
#define PANEL_LSPRITE_GRENADE 5
#define PANEL_LSPRITE_ARROW 6
#define PANEL_LSPRITE_QMARK 7
#define PANEL_LSPRITE_DOT 8
#define PANEL_LSPRITE_PISTOL 9
#define PANEL_LSPRITE_TEXT_BOX 10
#define PANEL_LSPRITE_BBB 11
#define PANEL_LSPRITE_FIST 12
#define PANEL_LSPRITE_EXPLOSIVES 13
#define PANEL_LSPRITE_KNIFE 14
#define PANEL_LSPRITE_NUMBER 15
typedef struct
{
SLONG page;
float u1;
float v1;
float u2;
float v2;
} PANEL_Lsprite;
/*
PANEL_Lsprite PANEL_lsprite[PANEL_LSPRITE_NUMBER] =
{
#define PLS(a,b,c,d) {float(a) / 256.0F, float(b) / 256.F, float(c) / 256.F, float(d) / 256.F}
#if THE_REAL_POSITIONS
PLS(0,114, 142,256),
PLS(1,1, 76,44),
PLS(0,46, 77,87),
PLS(77,1, 149,51),
PLS(78,56, 148,106),
PLS(182,32, 220,79), // Grenade
PLS(223,42, 247,68),
PLS(226,76, 246,103),
PLS(189,83, 211,105), // Dot
PLS(186,106, 256,158),
PLS(144,112, 180,148),
PLS(145,157, 217,204), // BBB
PLS(219,160, 255,204),
PLS(146, 207, 195,246),
PLS(1,95, 75,111),
#else
//
// Made all coordinates even.
//
PLS(0,114, 142,256),
PLS(0,0, 76,44),
PLS(0,46, 78,88),
PLS(76,0, 150,52),
PLS(78,56, 148,106),
PLS(182,32, 220,80), // Grenade
PLS(222,42, 248,68),
PLS(226,76, 246,104),
PLS(188,82, 212,106), // Dot
PLS(186,106, 256,158),
PLS(144,112, 180,148),
// PLS(144,156, 218,204), // BBB
PLS(145,157, 219,205), // BBB 2
PLS(218,160, 256,204),
PLS(146, 206, 196,246),
PLS(0,94, 76,112),
#endif
};
*/
PANEL_Lsprite PANEL_lsprite[PANEL_LSPRITE_NUMBER] =
{
#define PLS(p, a,b,c,d) { p, float(a) / 256.0F, float(b) / 256.F, float(c) / 256.F, float(d) / 256.F}
/*
PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 90, 212, 256), // display
PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 50, 142, 90), // AK
PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 50, 70, 88), // Shotgun
PLS(POLY_PAGE_LASTPANEL_ALPHA, 174, 0, 246, 50), // LoGear
PLS(POLY_PAGE_LASTPANEL_ALPHA, 104, 0, 174, 50), // HiGear
PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 0, 104, 46), // Grenade
PLS(POLY_PAGE_LASTPANEL_ALPHA, 224, 102, 242, 114), // Arrow
PLS(POLY_PAGE_LASTPANEL_ALPHA, 226, 76, 246, 104), // ?
PLS(POLY_PAGE_LASTPANEL_ALPHA, 230, 176, 238, 184), // Dot
PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 0, 70, 50), // Pistol
PLS(POLY_PAGE_LASTPANEL_ALPHA, 218, 128, 250, 160), // TxtBox
PLS(POLY_PAGE_LASTPANEL2_ALPHA, 0, 122, 72, 168), // BBB
PLS(POLY_PAGE_LASTPANEL2_ALPHA,126, 122, 162, 168), // Fist
PLS(POLY_PAGE_LASTPANEL2_ALPHA, 72, 122, 120, 162), // splosive
PLS(POLY_PAGE_LASTPANEL_ALPHA, 140, 62, 212, 84), // knife
*/
PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 90, 212, 256), // display
PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 52, 141, 89), // AK
PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 52, 69, 88), // Shotgun
PLS(POLY_PAGE_LASTPANEL_ALPHA, 175, 0, 246, 50), // LoGear
PLS(POLY_PAGE_LASTPANEL_ALPHA, 104, 0, 174, 50), // HiGear
PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 0, 104, 46), // Grenade
PLS(POLY_PAGE_LASTPANEL_ALPHA, 224, 102, 242, 114), // Arrow
PLS(POLY_PAGE_LASTPANEL_ALPHA, 226,76, 246,103), // ?
PLS(POLY_PAGE_LASTPANEL_ALPHA, 230, 176, 238, 184), // Dot
PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 0, 69, 50), // Pistol
PLS(POLY_PAGE_LASTPANEL_ALPHA, 218, 128, 250, 160), // TxtBox
PLS(POLY_PAGE_LASTPANEL2_ALPHA, 0, 124, 71, 168), // BBB
PLS(POLY_PAGE_LASTPANEL2_ALPHA,126, 124, 162, 168), // Fist
PLS(POLY_PAGE_LASTPANEL2_ALPHA, 72, 123, 120, 161), // splosive
PLS(POLY_PAGE_LASTPANEL_ALPHA, 141, 62, 212, 84), // knife
};
//
// Draws an arrow.
//
void PANEL_last_arrow(float x, float y, float angle, float size, ULONG colour, UBYTE is_dot=0)
{
PANEL_Lsprite *pls;
if (is_dot)
pls = &PANEL_lsprite[PANEL_LSPRITE_DOT];
else
pls = &PANEL_lsprite[PANEL_LSPRITE_ARROW];
float dx = sin(angle) * size;
float dy = cos(angle) * size;
POLY_Point pp [4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = x + dx + (-dy);
pp[0].Y = y + dy + (+dx);
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].x = 0.0F;
pp[0].y = 0.0F;
pp[0].u = pls->u1;
pp[0].v = pls->v1;
pp[0].colour = colour;
pp[0].specular = 0xff000000;
pp[1].X = x + dx - (-dy);
pp[1].Y = y + dy - (+dx);
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].x = 0.0F;
pp[1].y = 0.0F;
pp[1].u = pls->u2;
pp[1].v = pls->v1;
pp[1].colour = colour;
pp[1].specular = 0xff000000;
pp[2].X = x - dx + (-dy);
pp[2].Y = y - dy + (+dx);
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].x = 0.0F;
pp[2].y = 0.0F;
pp[2].u = pls->u1;
pp[2].v = pls->v2;
pp[2].colour = colour;
pp[2].specular = 0xff000000;
pp[3].X = x - dx - (-dy);
pp[3].Y = y - dy - (+dx);
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].x = 0.0F;
pp[3].y = 0.0F;
pp[3].u = pls->u2;
pp[3].v = pls->v2;
pp[3].colour = colour;
pp[3].specular = 0xff000000;
POLY_add_quad(quad, pls->page, FALSE, TRUE);
}
void PANEL_last_bubble(float x1, float y1, float x2, float y2)
{
POLY_Point pp[16];
#define SET_PP(qn, qx,qy, qu,qv) \
{ \
pp[qn].x = 0.0F; \
pp[qn].y = 0.0F; \
pp[qn].X = qx; \
pp[qn].Y = qy; \
pp[qn].z = fZDepthBodge; \
pp[qn].Z = fWDepthBodge; \
pp[qn].u = qu; \
pp[qn].v = qv; \
pp[qn].colour = 0xffffffff; \
pp[qn].specular = 0xff000000; \
}
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
PANEL_Lsprite *pls = &PANEL_lsprite[PANEL_LSPRITE_TEXT_BOX];
SET_PP(0, x1, y1, pls->u1, pls->v1);
SET_PP(1, x1 + 8.0F, y1, pls->u1 + (8.0F / 256.0F), pls->v1);
SET_PP(2, x2 - 8.0F, y1, pls->u2 - (8.0F / 256.0F), pls->v1);
SET_PP(3, x2, y1, pls->u2, pls->v1);
SET_PP(4, x2, y1 + 8.0F, pls->u2, pls->v1 + (8.0F / 256.0F));
SET_PP(5, x2, y2 - 8.0F, pls->u2, pls->v2 - (8.0F / 256.0F));
SET_PP(6, x2, y2, pls->u2, pls->v2);
SET_PP(7, x2 - 8.0F, y2, pls->u2 - (8.0F / 256.0F), pls->v2);
SET_PP(8, x1 + 8.0F, y2, pls->u1 + (8.0F / 256.0F), pls->v2);
SET_PP(9, x1, y2, pls->u1, pls->v2);
SET_PP(10, x1, y2 - 8.0F, pls->u1, pls->v2 - (8.0F / 256.0F));
SET_PP(11, x1, y1 + 8.0F, pls->u1, pls->v1 + (8.0F / 256.0F));
SET_PP(12, x1 + 8.0F, y1 + 8.0F, pls->u1 + (8.0F / 256.0F), pls->v1 + (8.0F / 256.0F));
SET_PP(13, x2 - 8.0F, y1 + 8.0F, pls->u2 - (8.0F / 256.0F), pls->v1 + (8.0F / 256.0F));
SET_PP(14, x2 - 8.0F, y2 - 8.0F, pls->u2 - (8.0F / 256.0F), pls->v2 - (8.0F / 256.0F));
SET_PP(15, x1 + 8.0F, y2 - 8.0F, pls->u1 + (8.0F / 256.0F), pls->v2 - (8.0F / 256.0F));
SLONG i;
SLONG p1;
SLONG p2;
POLY_Point *quad[4];
struct
{
UBYTE p1;
UBYTE p2;
UBYTE p3;
UBYTE p4;
} blah[9] =
{
{0,1,11,12},
{1,2,12,13},
{2,3,13,4},
{11,12,10,15},
{12,13,15,14},
{13,4,14,5},
{10,15,9,8},
{15,14,8,7},
{14,5,7,6}
};
for (i = 0; i < 9; i++)
{
quad[0] = &pp[blah[i].p1];
quad[1] = &pp[blah[i].p2];
quad[2] = &pp[blah[i].p3];
quad[3] = &pp[blah[i].p4];
POLY_add_quad(quad, pls->page, FALSE, TRUE);
}
}
SLONG PANEL_sign_which;
SLONG PANEL_sign_flip;
SLONG PANEL_sign_time;
void PANEL_flash_sign(SLONG sign, SLONG flip)
{
PANEL_sign_time = GetTickCount();
PANEL_sign_flip = flip;
PANEL_sign_which = sign;
}
CBYTE PANEL_info_message[512];
ULONG PANEL_info_time;
void PANEL_new_info_message(CBYTE *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsprintf(PANEL_info_message, fmt, ap);
va_end (ap);
PANEL_info_time = GetTickCount();
}
void PANEL_darken_screen(SLONG x)
{
PANEL_draw_quad(640.0F - float(x), 0.0F, 640.0F, 480.0F, POLY_PAGE_ALPHA_OVERLAY, 0x88000000);
}
// this sucks!
inline SLONG BodgePageIntoAddAlpha(SLONG oldpage)
{
if (oldpage==POLY_PAGE_LASTPANEL_ALPHA) return POLY_PAGE_LASTPANEL_ADDALPHA;
return POLY_PAGE_LASTPANEL2_ADDALPHA;
}
// this sucks too!
inline SLONG BodgePageIntoAdd(SLONG oldpage)
{
if (oldpage==POLY_PAGE_LASTPANEL_ALPHA) return POLY_PAGE_LASTPANEL_ADD;
return POLY_PAGE_LASTPANEL2_ADD;
}
// this sucks as well!
inline SLONG BodgePageIntoSub(SLONG oldpage)
{
if (oldpage==POLY_PAGE_LASTPANEL_ALPHA) return POLY_PAGE_LASTPANEL_SUB;
return POLY_PAGE_LASTPANEL2_SUB;
}
/*************************************************************
*
* Pop-up inventory panel
*
*/
void PANEL_inv_weapon(SLONG x, SLONG y, SLONG item, UBYTE who, SLONG rgb, UBYTE sel) {
/* SLONG which_gun, which_dx=0;
//
// Which gun shall we draw.
//
switch(item)
{
default:
if (who == PANEL_WHO_DARCI)
which_gun = PANEL_IC_DARCI_HAND;
else
which_gun = PANEL_IC_ROPER_HAND;
break;
case SPECIAL_GUN:
which_gun = PANEL_IC_PISTOL;
break;
case SPECIAL_AK47:
which_gun = PANEL_IC_AK47;
which_dx = -45;
break;
case SPECIAL_BASEBALLBAT:
which_gun = PANEL_IC_BASEBALLBAT;
which_dx = -50;
break;
case SPECIAL_KNIFE:
which_gun = PANEL_IC_KNIFE;
// which_dy = 15;
break;
case SPECIAL_SHOTGUN:
which_gun = PANEL_IC_SHOTGUN;
which_dx = -35;
break;
case SPECIAL_GRENADE:
which_gun = PANEL_IC_GRENADE;
break;
case SPECIAL_EXPLOSIVES:
which_gun = PANEL_IC_EXPLOSIVES;
break;
case SPECIAL_WIRE_CUTTER:
which_gun = PANEL_IC_EXPLOSIVES;
break;
}
PANEL_funky_quad(
which_gun,
x + which_dx,
y,
PANEL_PAGE_ALPHA_END,
0x00ffffff|alpha);
*/
SLONG sprite = -1, faded;
switch(item)
{
case SPECIAL_GUN:
sprite = PANEL_LSPRITE_PISTOL;
break;
case SPECIAL_SHOTGUN:
sprite = PANEL_LSPRITE_SHOTGUN;
break;
case SPECIAL_AK47:
sprite = PANEL_LSPRITE_AK47;
break;
case SPECIAL_EXPLOSIVES:
sprite = PANEL_LSPRITE_EXPLOSIVES;
break;
case SPECIAL_GRENADE:
sprite = PANEL_LSPRITE_GRENADE;
break;
case SPECIAL_KNIFE:
sprite = PANEL_LSPRITE_KNIFE;
break;
case SPECIAL_BASEBALLBAT:
sprite = PANEL_LSPRITE_BBB;
break;
default:
sprite = PANEL_LSPRITE_FIST;
break;
}
//
// Centre the sprite.
//
ASSERT(WITHIN(sprite, 0, PANEL_LSPRITE_NUMBER - 1));
PANEL_Lsprite *pls = &PANEL_lsprite[sprite];
float uwidth = (pls->u2 - pls->u1) * 256.0F;
float vwidth = (pls->v2 - pls->v1) * 256.0F;
#ifdef TARGET_DC
// Got to make it much more obvious which weapon is selected.
if (sel)
{
// Enlarge it.
uwidth *= 2.0f;
vwidth *= 2.0f;
}
else
{
// Dark red
faded=(rgb&0xff)>>1;
faded|=(faded<<8)|(faded<<16)|(faded<<24);
rgb = faded;
}
#else
faded=(rgb&0xff)>>1;
faded|=(faded<<8)|(faded<<16)|(faded<<24);
if (!sel) rgb=faded;
#endif
/* PANEL_draw_quad(
(float)x - uwidth * 0.35F,
(float)y - vwidth * 0.35F,
(float)x + uwidth * 0.35F,
(float)y + vwidth * 0.35F,
POLY_PAGE_LASTPANEL_SUB,
// 0x7f007fff,
faded,
pls->u1,
pls->v1,
pls->u2,
pls->v2);*/
/* PANEL_draw_quad(
(float)x - 30,
(float)y - 30,
(float)x + 30,
(float)y + 30,
POLY_PAGE_SHADOW_OVAL,
faded,
0.0, 0.0, 1.0, 1.0
);*/
/* PANEL_draw_quad(
(float)x + 2 - uwidth * 0.25F,
(float)y + 2 - vwidth * 0.25F,
(float)x + 2 + uwidth * 0.25F,
(float)y + 2 + vwidth * 0.25F,
BodgePageIntoSub(pls->page),
// 0x7f007fff,
faded,
pls->u1,
pls->v1,
pls->u2,
pls->v2);*/
PANEL_draw_quad(
(float)x - uwidth * 0.25F,
(float)y - vwidth * 0.25F,
(float)x + uwidth * 0.25F,
(float)y + vwidth * 0.25F,
BodgePageIntoAdd/*Alpha*/(pls->page),
rgb,
pls->u1,
pls->v1,
pls->u2,
pls->v2);
}
#define PANEL_ADDWEAPON(item) { draw_list[draw_count]=item; draw_count++; }
#define ITEM_SEPERATION (150)
void PANEL_inventory(Thing *darci, Thing *player) {
SLONG rgb,rgb2;
CBYTE draw_list[10];
UBYTE draw_count=0;
Thing *p_special = NULL;
SLONG x,c0;
UBYTE current_item = 0;
SLONG sel;
UWORD CONTROLS_inv_fade = player->Genus.Player->PopupFade;
if (!CONTROLS_inv_fade) return;
if (darci->Genus.Person->Flags & FLAG_PERSON_DRIVING) return;
// Bad Dog! Obsolete code.
//extern SLONG EWAY_cam_active;
//if (EWAY_cam_active) return;
if ( EWAY_stop_player_moving() )
{
return;
}
/* rgb=((SLONG)(CONTROLS_inv_fade-1))<<24;
rgb2=((SLONG)(CONTROLS_inv_fade-1)>>1)<<24;
DRAW2D_Box_Page(0, 20, 640, 80, rgb2|0xAFA583, POLY_PAGE_ALPHA_OVERLAY, 128);
DRAW2D_Box_Page(0,20,CONTROLS_inv_fade*3,21,rgb|0xFFFFFF,POLY_PAGE_ALPHA_OVERLAY,128);
DRAW2D_Box_Page(640-(CONTROLS_inv_fade*3),79,640,80,rgb|0xFFFFFF,POLY_PAGE_ALPHA_OVERLAY,128);
CBYTE stat_up[10];
sprintf(stat_up,"%s: %d",XLAT_str(X_STR),player->Genus.Player->Strength);
FONT2D_DrawString(stat_up,0,1,0xffffff,256,POLY_PAGE_FONT2D,rgb);
sprintf(stat_up,"%s: %d",XLAT_str(X_CON),player->Genus.Player->Constitution);
FONT2D_DrawString(stat_up,80,1,0xffffff,256,POLY_PAGE_FONT2D,rgb);
sprintf(stat_up,"%s: %d",XLAT_str(X_STA),player->Genus.Player->Stamina);
FONT2D_DrawString(stat_up,160,1,0xffffff,256,POLY_PAGE_FONT2D,rgb);
sprintf(stat_up,"%s: %d",XLAT_str(X_DEX),player->Genus.Player->Skill);
FONT2D_DrawString(stat_up,240,1,0xffffff,256,POLY_PAGE_FONT2D,rgb);
*/
PANEL_ADDWEAPON(0);
sel=darci->Genus.Person->SpecialUse;
if (darci->Genus.Person->SpecialList)
{
p_special = TO_THING(darci->Genus.Person->SpecialList);
while(p_special)
{
ASSERT(p_special->Class == CLASS_SPECIAL);
if (SPECIAL_info[p_special->Genus.Special->SpecialType].group == SPECIAL_GROUP_ONEHANDED_WEAPON ||
SPECIAL_info[p_special->Genus.Special->SpecialType].group == SPECIAL_GROUP_TWOHANDED_WEAPON ||
p_special->Genus.Special->SpecialType == SPECIAL_EXPLOSIVES ||
p_special->Genus.Special->SpecialType == SPECIAL_WIRE_CUTTER)
{
if (THING_NUMBER(p_special)==darci->Genus.Person->SpecialUse)
{
current_item=draw_count;
sel=p_special->Genus.Special->SpecialType;
}
PANEL_ADDWEAPON(p_special->Genus.Special->SpecialType);
}
if (p_special->Genus.Special->NextSpecial)
p_special = TO_THING(p_special->Genus.Special->NextSpecial);
else
p_special = NULL;
}
}
if (darci->Flags & FLAGS_HAS_GUN)
{
if (darci->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
{
current_item=draw_count;
sel=SPECIAL_GUN;
}
PANEL_ADDWEAPON(SPECIAL_GUN);
}
current_item = player->Genus.Player->ItemFocus;
if (current_item==-1) return;
// x = 320 - (50*draw_count) - (current_item*50);
/* x = 320 - (current_item*ITEM_SEPERATION);
for (c0=0;c0<draw_count;c0++) {
PANEL_inv_weapon(x,20,draw_list[c0],0,rgb);
x+=ITEM_SEPERATION;
}
*/
if (draw_list[current_item]&&!sel) sel=draw_list[current_item];
int iYPos, iYInc;
if ( m_iPanelYPos > 300 )
{
// Inventory starts above and goes upwards.
iYPos = m_iPanelYPos - 150; //330
iYInc = -35;
}
else
{
// Inventory starts below and goes down.
iYPos = m_iPanelYPos + 20;
iYInc = 35;
}
rgb=CONTROLS_inv_fade-1;
rgb2=rgb|(rgb<<8)|(rgb<<24);
rgb|=(rgb<<8)|(rgb<<16)|(rgb<<24);
for (c0=0;c0<draw_count;c0++) {
// if ((c0!=current_item)&&(draw_list[c0]!=darci->Genus.Person->SpecialUse))
if (draw_list[c0]!=sel)
{
PANEL_inv_weapon(m_iPanelXPos+170,iYPos,draw_list[c0],0,rgb, 0);
}
else
{
PANEL_inv_weapon(m_iPanelXPos+170,iYPos,draw_list[c0],0,rgb ,1);
}
iYPos += iYInc;
}
}
#define PANEL_LAST_HEIGHT 165
#define SCANNER_LAST_CTR_X 74
#define SCANNER_LAST_CTR_Y (480 - PANEL_LAST_HEIGHT + 74)
#define SCANNER_LAST_CTR_U 74
#define SCANNER_LAST_CTR_V 74
void PANEL_last()
{
//TRACE ( "PDi" );
bool bPanelIsAtBottomOfScreen = ( m_iPanelYPos > 300 );
#ifdef TARGET_DC
PANEL_draw_VMU_ammo_counts();
#endif
if (EWAY_tutorial_string)
{
//
// Darken the whole screen...
//
PANEL_darken_screen(640);
#ifndef TARGET_DC
POLY_frame_draw(FALSE, FALSE);
POLY_frame_init(FALSE, FALSE);
#endif
//
// Draw a speech bubble in the top left of the screen.
//
#ifdef TARGET_DC
// We have to keep stuff away from the edges by 32 pixels. Waaa.
SLONG height = FONT2D_DrawStringWrapTo(
EWAY_tutorial_string,
32,
32,
0xffffff,
256,
POLY_PAGE_FONT2D,
0,
640-32*2);
PANEL_last_bubble(
32 - 6,
32 - 4,
float(FONT2D_rightmost_x) + 6.0F,
height + 18);
// Do it again so it's brighter.
FONT2D_DrawStringWrapTo(
EWAY_tutorial_string,
32,
32,
0xffffff,
256,
POLY_PAGE_FONT2D,
0,
640-32*2);
#else
#define PANEL_TUT_X 16
#define PANEL_TUT_Y 16
SLONG height = FONT2D_DrawStringWrap(
EWAY_tutorial_string,
PANEL_TUT_X,
PANEL_TUT_Y,
0xffffff);
PANEL_last_bubble(
PANEL_TUT_X - 6,
PANEL_TUT_Y - 4,
float(FONT2D_rightmost_x) + 6.0F,
PANEL_TUT_Y + height + 4);
#endif
return;
}
Thing *darci = NET_PERSON(0);
if (darci == NULL)
{
return;
}
if (EWAY_stop_player_moving())
{
//
// There is a widescreen cutscene playing.
//
PANEL_new_widescreen();
return;
}
else
{
PANEL_wide_top_person = NULL;
PANEL_wide_bot_person = NULL;
PANEL_wide_top_is_talking = FALSE;
PANEL_wide_text[0] = '\000';
}
//
// Draw the background first.
//
/*
PANEL_draw_quad(
0.0F,
480.0F - 165.0F,
212.0F,
480.0F,
POLY_PAGE_LASTPANEL_ALPHA,
0xffffffff,
0.0F,
90.0F / 256.0F,
212.0F / 256.0F,
1.0F);*/
PANEL_draw_quad(
(float)( m_iPanelXPos + 0 ),
(float)( m_iPanelYPos - 165 ),
(float)( m_iPanelXPos + 212 ),
(float)( m_iPanelYPos - 0 ),
POLY_PAGE_LASTPANEL_ALPHA,
0xffffffff,
0.0F,
90.0F / 256.0F,
212.0F / 256.0F,
1.0F);
/* PANEL_draw_quad(
0.0F,
480.0F - 142.0F,
126.0F,
480.0F,
POLY_PAGE_LASTPANEL_ALPHA,
0xffffffff,
0.0F,
114.0F / 256.0F,
126.0F / 256.0F,
1.0F);
PANEL_draw_quad(
126.0F,
480.0F - 142.0F,
186.0F,
480.0F,
POLY_PAGE_LASTPANEL_ALPHA,
0xffffffff,
126.0F / 256.0F,
114.0F / 256.0F,
127.0F / 256.0F,
1.0F);
PANEL_draw_quad(
186.0F,
480.0F - 142.0F,
186.0F + 142.0F - 127.0F,
480.0F,
POLY_PAGE_LASTPANEL_ALPHA,
0xffffffff,
127.0F / 256.0F,
114.0F / 256.0F,
142.0F / 256.0F,
1.0F);
*/
//
// The weapon/ammo box.
//
SLONG sprite = -1;
CBYTE text[64];
text[0] = '\000';
int iGrenadeCountdown = -1;
if (darci->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
Thing *p_vehicle = TO_THING(darci->Genus.Person->InCar);
sprite = PANEL_LSPRITE_LOW_GEAR;
/* if (p_vehicle->Genus.Vehicle->Siren)
{
sprite = PANEL_LSPRITE_HIGH_GEAR;
sprintf(text, "High");
}
else
{
sprite = PANEL_LSPRITE_LOW_GEAR;
sprintf(text, "Low");
}*/
}
else
{
if (darci->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
{
sprite = PANEL_LSPRITE_PISTOL;
if (darci->Genus.Person->ammo_packs_pistol)
{
sprintf(text, "%d\\%d", darci->Genus.Person->Ammo, darci->Genus.Person->ammo_packs_pistol/15);
}
else
{
sprintf(text, "%d", darci->Genus.Person->Ammo);
}
}
else
if (darci->Genus.Person->SpecialUse)
{
Thing *p_special = TO_THING(darci->Genus.Person->SpecialUse);
switch(p_special->Genus.Special->SpecialType)
{
case SPECIAL_SHOTGUN:
sprite = PANEL_LSPRITE_SHOTGUN;
if (darci->Genus.Person->ammo_packs_shotgun)
{
sprintf(text, "%d\\%d", p_special->Genus.Special->ammo, darci->Genus.Person->ammo_packs_shotgun/SPECIAL_AMMO_IN_A_SHOTGUN);
}
else
{
sprintf(text, "%d", p_special->Genus.Special->ammo);
}
break;
case SPECIAL_AK47:
sprite = PANEL_LSPRITE_AK47;
if (darci->Genus.Person->ammo_packs_ak47)
{
sprintf(text, "%d\\%d", p_special->Genus.Special->ammo, darci->Genus.Person->ammo_packs_ak47/SPECIAL_AMMO_IN_A_AK47);
}
else
{
sprintf(text, "%d", p_special->Genus.Special->ammo);
}
break;
case SPECIAL_EXPLOSIVES:
sprite = PANEL_LSPRITE_EXPLOSIVES;
sprintf(text, "%d", p_special->Genus.Special->ammo);
break;
case SPECIAL_GRENADE:
sprite = PANEL_LSPRITE_GRENADE;
//
// If the player is holding a grenade that has had its pin pulled then
// show how long the grenade has before it goes off.
//
if (p_special->SubState == SPECIAL_SUBSTATE_ACTIVATED)
{
SLONG secsleft;
secsleft = p_special->Genus.Special->timer / (16 * 20) + 1;
SATURATE(secsleft,0,6);
#ifdef TARGET_DC
// This gets done later, over the grenade icon.
iGrenadeCountdown = secsleft;
#else
ULONG colour, colours[]={0xff3300,0xff8800,0x88ff00,0x888888};
if (secsleft<1)
colour=*colours;
else
if (secsleft>3)
colour=colours[3];
else
colour=colours[secsleft];
itoa(secsleft,text,10);
FONT2D_DrawString(
text,
m_iPanelXPos + 141,
m_iPanelYPos - 53,
colour,
256);
#endif
}
#ifdef TARGET_DC
else
{
iGrenadeCountdown = -1;
}
#endif
itoa(p_special->Genus.Special->ammo,text,10);
break;
case SPECIAL_KNIFE:
sprite = PANEL_LSPRITE_KNIFE;
break;
case SPECIAL_BASEBALLBAT:
sprite = PANEL_LSPRITE_BBB;
break;
default:
sprite = PANEL_LSPRITE_QMARK;
break;
}
}
else
{
sprite = PANEL_LSPRITE_FIST;
}
}
//
// Centre the sprite.
//
{
ASSERT(WITHIN(sprite, 0, PANEL_LSPRITE_NUMBER - 1));
PANEL_Lsprite *pls = &PANEL_lsprite[sprite];
float uwidth = (pls->u2 - pls->u1) * 256.0F;
float vwidth = (pls->v2 - pls->v1) * 256.0F;
/*
float x1 = 170.0F - uwidth * 0.5F;
float y1 = 417.0F - vwidth * 0.5F;
float x2 = 170.0F + uwidth * 0.5F;
float y2 = 417.0F + vwidth * 0.5F;
*/
float x1 = (float)( m_iPanelXPos + 170 ) - uwidth * 0.5F;
float y1 = (float)( m_iPanelYPos - 63 ) - vwidth * 0.5F;
float x2 = (float)( m_iPanelXPos + 170 ) + uwidth * 0.5F;
float y2 = (float)( m_iPanelYPos - 63 ) + vwidth * 0.5F;
if (ftol(uwidth) & 0x1)
{
x1 -= 0.5F;
x2 -= 0.5F;
}
if (ftol(vwidth) & 0x1)
{
y1 -= 0.5F;
y2 -= 0.5F;
}
// And move the M16 up a bit, so it doesn't cover the ammo count.
if ( sprite == PANEL_LSPRITE_AK47 )
{
y1 -= 8.0F;
y2 -= 8.0F;
}
PANEL_draw_quad(
x1, y1,
x2, y2,
BodgePageIntoAdd/*Alpha*/(pls->page),
0xFFffffff,
pls->u1,
pls->v1,
pls->u2,
pls->v2);
}
//
// Draw the ammo.
//
if (text)
{
FONT2D_DrawStringRightJustify(
text,
m_iPanelXPos + 215, // 214,
m_iPanelYPos - 50, // 427,
0xffffff,
256 + 64);
/*
FONT2D_DrawStringRightJustify(
text,
m_iPanelXPos + 217, // 214,
m_iPanelYPos - 51, // 427,
0x000000,
384);
*/
/*
FONT2D_DrawStringRightJustify(
text,
m_iPanelXPos + 214, // 214,
m_iPanelYPos - 53, // 427,
0xffffff,
256);
*/
}
#ifdef TARGET_DC
if ( iGrenadeCountdown >= 0 )
{
// Draw the countdown over the grenade.
ULONG colour = 0xff3300;
if ( iGrenadeCountdown <= 4 )
{
static int iFlash = 0;
iFlash += ( 5 - iGrenadeCountdown );
if ( ( iFlash & 0x4 ) == 0 )
{
// Flash it.
colour = 0x000000;
}
}
itoa(iGrenadeCountdown,text,10);
// BRIGHTER! BIGGER! MORE! You can barely see the damn countdown on the PC.
FONT2D_DrawString(
text,
m_iPanelXPos + 160 + 2,
m_iPanelYPos - 73 + 2,
0x00000000,
512);
FONT2D_DrawString(
text,
m_iPanelXPos + 160 - 2,
m_iPanelYPos - 73 - 2,
0x00000000,
512);
FONT2D_DrawString(
text,
m_iPanelXPos + 160 - 2,
m_iPanelYPos - 73 + 2,
0x00000000,
512);
FONT2D_DrawString(
text,
m_iPanelXPos + 160 + 2,
m_iPanelYPos - 73 - 2,
0x00000000,
512);
FONT2D_DrawString(
text,
m_iPanelXPos + 160,
m_iPanelYPos - 73,
colour,
512);
}
#endif
//
// And the crime rate, if applicable
//
if (GAME_FLAGS & GF_SHOW_CRIMERATE)
{
CBYTE crimerate[64];
sprintf(crimerate, "%d%%", CRIME_RATE);
if (CRIME_RATE>=95)
{
static UWORD pulse=0;
SLONG colour;
pulse+=(TICK_RATIO*80)>>TICK_SHIFT;
colour=(SIN(pulse&2047)>>9)+128;
colour=colour|(colour<<8);
FONT2D_DrawStringCentred(
crimerate,
m_iPanelXPos + 170, //170,
m_iPanelYPos - 116, //364,
0xff0000|colour);
} else
FONT2D_DrawStringCentred(
crimerate,
m_iPanelXPos + 170, //170,
m_iPanelYPos - 116, //364,
0xffffff);
}
#ifndef TARGET_DC
{
CBYTE timing[256];
float strip;
SLONG c;
extern ULONG AENG_draw_time;
extern ULONG AENG_poly_add_quad_time;
#ifdef STRIP_STATS
extern ULONG strip_stats[];
if(strip_stats[0])
strip=(float)strip_stats[1]/(float)strip_stats[0];
sprintf(
timing,
"Frame time %d strip len %f",
AENG_draw_time >> 12,strip);
FONT2D_DrawString(
timing,
50,
65,
0xffffff);
for(c=2;c<34;c++)
{
sprintf(
timing,
"(%d)%d",c-1,
strip_stats[c]);
FONT2D_DrawString(
timing,
10+(((c-2)&7))*75,
120+(((c-2)&0xf8)>>3)*20,
0xffffff);
}
#endif
sprintf(
timing,
"Poly add quad %d",
AENG_poly_add_quad_time >> 12);
FONT2D_DrawString(
timing,
50,
80,
0xffffff);
}
#endif
//
// Draw the health bar.
//
{
SLONG i;
float angle;
float du;
float dv;
float u1;
float v1;
float u2;
float v2;
float last_u1;
float last_v1;
float last_u2;
float last_v2;
POLY_Point pp [4];
POLY_Point *quad[4];
POLY_Point *tri [3];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
tri[0] = &pp[0];
tri[1] = &pp[1];
tri[2] = &pp[2];
static float blah1 = ( -43 * 2.0F * PI / 360.0F);
static float blah2 = (-227 * 2.0F * PI / 360.0F);
UBYTE is_in_car = darci->Genus.Person->InCar ? 1 : 0;
float car_offset = is_in_car ? 130.0F : 0.0F;
Thing *the_car=is_in_car? TO_THING(darci->Genus.Person->InCar) : 0;
#define PLH_MID_U (71.0F + car_offset)
#define PLH_MID_V (71.0F)
#define PLH_RADIUS (66.0F)
#define PLH_WIDTH (10.0F)
#define PLH_ANGLE1 blah1
#define PLH_ANGLE2 blah2
#define PLH_SEGS (8)
//#define PLH_MID_X (74.0F)
//#define PLH_MID_Y (480.0F - (256.0F - 166.0F))
#define PLH_MID_X ((float)(m_iPanelXPos + 74))
#define PLH_MID_Y ((float)(m_iPanelYPos - (256 - 166)))
angle = PLH_ANGLE1;
float dangle;
float fraction;
dangle = (PLH_ANGLE2 - PLH_ANGLE1) / PLH_SEGS;
//
// What fraction of health does Darci have?
//
fraction = is_in_car ? float(the_car->Genus.Vehicle->Health) * (1.0F / 300.0F) : float(darci->Genus.Person->Health) * ((darci->Genus.Person->PersonType == PERSON_ROPER) ? (1.0F / 400.0F) : (1.0F / 200.0F));
SATURATE(fraction, 0.0F, 1.0F);
dangle *= fraction;
for (i = 0; i <= PLH_SEGS; i++)
{
du = sin(angle);
dv = cos(angle);
u1 = (PLH_MID_U + du * (PLH_RADIUS + PLH_WIDTH));
v1 = (PLH_MID_V + dv * (PLH_RADIUS + PLH_WIDTH));
u2 = (PLH_MID_U + du * (PLH_RADIUS - PLH_WIDTH));
v2 = (PLH_MID_V + dv * (PLH_RADIUS - PLH_WIDTH));
if (i > 0)
{
float fWDepthBodge = PANEL_GetNextDepthBodge();
float fZDepthBodge = 1.0f - fWDepthBodge;
pp[0].X = PLH_MID_X + (u1 - PLH_MID_U);
pp[0].Y = PLH_MID_Y + (v1 - PLH_MID_V);
pp[0].z = fZDepthBodge;
pp[0].Z = fWDepthBodge;
pp[0].x = 0.0F;
pp[0].y = 0.0F;
pp[0].u = u1 * (1.0F / 256.0F);
pp[0].v = v1 * (1.0F / 256.0F);
pp[0].colour = 0xffffffff;
pp[0].specular = 0xff000000;
pp[1].X = PLH_MID_X + (u2 - PLH_MID_U);
pp[1].Y = PLH_MID_Y + (v2 - PLH_MID_V);
pp[1].z = fZDepthBodge;
pp[1].Z = fWDepthBodge;
pp[1].x = 0.0F;
pp[1].y = 0.0F;
pp[1].u = u2 * (1.0F / 256.0F);
pp[1].v = v2 * (1.0F / 256.0F);
pp[1].colour = 0xffffffff;
pp[1].specular = 0xff000000;
pp[2].X = PLH_MID_X + (last_u1 - PLH_MID_U);
pp[2].Y = PLH_MID_Y + (last_v1 - PLH_MID_V);
pp[2].z = fZDepthBodge;
pp[2].Z = fWDepthBodge;
pp[2].x = 0.0F;
pp[2].y = 0.0F;
pp[2].u = last_u1 * (1.0F / 256.0F);
pp[2].v = last_v1 * (1.0F / 256.0F);
pp[2].colour = 0xffffffff;
pp[2].specular = 0xff000000;
pp[3].X = PLH_MID_X + (last_u2 - PLH_MID_U);
pp[3].Y = PLH_MID_Y + (last_v2 - PLH_MID_V);
pp[3].z = fZDepthBodge;
pp[3].Z = fWDepthBodge;
pp[3].x = 0.0F;
pp[3].y = 0.0F;
pp[3].u = last_u2 * (1.0F / 256.0F);
pp[3].v = last_v2 * (1.0F / 256.0F);
pp[3].colour = 0xffffffff;
pp[3].specular = 0xff000000;
POLY_add_quad(quad, POLY_PAGE_LASTPANEL2_ALPHA, FALSE, TRUE);
}
last_u1 = u1;
last_v1 = v1;
last_u2 = u2;
last_v2 = v2;
angle += dangle;
}
}
//
// Draw the stamina marks
//
{
UBYTE i, stamina = darci->Genus.Person->Stamina / 25;
//SLONG x = 107;
//SLONG y = 480 - 36;
SLONG x = m_iPanelXPos + 107;
SLONG y = m_iPanelYPos - 36;
SLONG rgb[] = { 0x00FF0000, 0x00C04000, 0x00808000, 0x0040C000, 0x0000ff00 };
SATURATE(stamina,0,5);
for (i=0;i<stamina;i++)
{
PANEL_draw_quad(
x, y-10,
x+10, y,
POLY_PAGE_LASTPANEL_ADD,
rgb[i],
(243.0/256.0),
(198.0/256.0),
(253.0/256.0),
(208.0/256.0));
x+=3; y-=3;
}
}
//
// Draw the navigation beacons.
//
{
SLONG i;
float dx;
float dz;
float dist;
float dangle;
float score;
float x;
float y;
BOOL thugly;
POLY_Point pp [3];
POLY_Point *tri[3];
MAP_Beacon *mb;
ULONG colour;
SLONG best_beacon = NULL;
float best_score = float(INFINITY);
for (i = 1; i < MAP_MAX_BEACONS; i++)
{
mb = &MAP_beacon[i];
if (!mb->used)
{
continue;
}
thugly=FALSE;
if (mb->track_thing)
{
Thing *p_track = TO_THING(mb->track_thing);
mb->wx = p_track->WorldPos.X >> 8;
mb->wz = p_track->WorldPos.Z >> 8;
extern SLONG is_person_dead(Thing *p_person);
if (p_track->Class == CLASS_PERSON)
{
switch(p_track->Genus.Person->PersonType)
{
case PERSON_THUG_RASTA:
case PERSON_THUG_GREY:
case PERSON_THUG_RED:
case PERSON_MIB1:
case PERSON_MIB2:
case PERSON_MIB3:
thugly=TRUE;
}
if (p_track->State == STATE_DEAD)
{
//
// Don't draw beacons to dead people.
//
if (p_track->SubState == SUB_STATE_DEAD_INJURED)
{
//
// Except if they're only injured...
//
if (p_track->Genus.Person->pcom_ai == PCOM_AI_FIGHT_TEST)
{
//
// Except if they're fight test dummies!
//
continue;
}
}
else
{
continue;
}
}
}
}
colour = PANEL_beacon_colour[i % PANEL_MAX_BEACON_COLOURS] | (0xff000000);
//
// Work out the distance and relative angle of this beacon from darci.
//
dx = float(mb->wx - (darci->WorldPos.X >> 8));
dz = float(mb->wz - (darci->WorldPos.Z >> 8));
dist = sqrt(dx*dx + dz*dz);
/*
if (dist < 256.0F * 4.0F)
{
score = dist * (1.0F / (256.0F * 4.0F));
score *= 2.0F * PI * 22.0F / 360.0F;
PANEL_funky_quad(
PANEL_IC_DOT,
PANEL_IC_SCANX - 7.0F,
PANEL_IC_SCANY - 7.0F,
PANEL_PAGE_ALPHA_END,
colour);
}
else
*/
{
UBYTE is_dot=0;
if (PANEL_scanner_poo)
dangle = atan2(dx,dz) - float(darci->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F);
else
dangle = atan2(dx,dz) - float(FC_cam[0].yaw>>8) * (2.0F * PI / 2048.0F);
score = (float)fmod(dangle, 2.0F * PI) - PI;
if (score > +PI) {score -= 2.0F * PI;}
if (score < -PI) {score += 2.0F * PI;}
//dist -= 3.0F * 256.0F;
dist /= 16.0F * 256.0F;
if (dist < 1.0F) is_dot=1;
SATURATE(dist, 0.0F, 1.0F);
#define PLS_MID_X PLH_MID_X
#define PLS_MID_Y PLH_MID_Y
#define PLS_RADIUS 50.0F
//if (!(is_dot&&thugly)) // it'll get drawn by the thug scanner below
{
x = PLS_MID_X + (float)sin(dangle) * PLS_RADIUS * dist;
y = PLS_MID_Y + (float)cos(dangle) * PLS_RADIUS * dist;
float size = (mb->pad&&!is_dot) ? 9.0F : 6.0F;
SLONG alive = GetTickCount() - mb->ticks;
if (alive < 4096)
{
alive &= 0x100;
SATURATE(alive, 0, 255);
colour &= 0x00ffffff;
colour |= alive << 24;
/*
SLONG r = (colour >> 16) & 0xff;
SLONG g = (colour >> 8) & 0xff;
SLONG b = (colour >> 0) & 0xff;
r = r * alive >> 8;
g = g * alive >> 8;
b = b * alive >> 8;
colour = 0xff000000 | (r << 16) | (g << 8) | b;
*/
}
PANEL_last_arrow(x,y, dangle, size, colour, is_dot);
}
}
if (fabs(score) < best_score)
{
best_score = fabs(score);
best_beacon = i;
}
mb->pad = FALSE;
}
if (PANEL_info_time > GetTickCount() - 2000)
{
SLONG x_right;
SLONG colour_main;
SLONG colour_shad;
// if (!WITHIN(PANEL_info_time, GetTickCount() - 1100, GetTickCount() - 900))
SLONG now = GetTickCount();
SLONG onfor = now - PANEL_info_time;
if (onfor < 255)
{
colour_main = onfor;
colour_shad = onfor;
}
else
if (onfor < 768)
{
colour_main = 0xff;
colour_shad = 255 - (onfor - 256 >> 1);
}
else
{
colour_main = 0xff;
colour_shad = 0x00;
}
x_right = onfor >> 1;
SATURATE(colour_main, 0, 255);
SATURATE(colour_shad, 0, 255);
//SATURATE(x_right, 16, 205);
SATURATE(x_right, 16, 205);
x_right += m_iPanelXPos;
colour_main = colour_main | (colour_main << 8) | (colour_main << 16);
colour_shad = colour_shad | (colour_shad << 8) | (colour_shad << 16);
{
FONT2D_DrawStringRightJustifyNoWrap(
PANEL_info_message,
x_right + 2,
m_iPanelYPos - 23 + 2, //457 + 2,
colour_shad,
256);
FONT2D_DrawStringRightJustifyNoWrap(
PANEL_info_message,
x_right,
m_iPanelYPos - 23, //457,
colour_main,
256);
}
}
else
{
if (best_beacon)
{
ASSERT(WITHIN(best_beacon, 1, MAP_MAX_BEACONS - 1));
mb = &MAP_beacon[best_beacon];
extern CBYTE *EWAY_get_mess(SLONG index);
#ifndef TARGET_DC
extern UBYTE sw_hack;
if (!sw_hack)
#endif
{
FONT2D_DrawString(
EWAY_get_mess(mb->index),
m_iPanelXPos + 12 + 2, //12 + 2,
m_iPanelYPos - 23 + 2, //457 + 2,
0x00000000,
256);
}
FONT2D_DrawString(
EWAY_get_mess(mb->index),
m_iPanelXPos + 12, //12
m_iPanelYPos - 23, //457,
PANEL_beacon_colour[best_beacon % PANEL_MAX_BEACON_COLOURS],
256);
mb->pad = TRUE;
}
}
}
//
// Draw the thugs on the scanner.
//
{
SLONG i;
float x;
float y;
float dx;
float dz;
float dist;
float dangle;
float size;
float flash = fabs(sin(float(GAME_TURN) * 0.2F));
SLONG display;
ULONG colour;
PANEL_Lsprite *pls = &PANEL_lsprite[PANEL_LSPRITE_DOT];
SLONG num_found = THING_find_sphere(
darci->WorldPos.X >> 8,
darci->WorldPos.Y >> 8,
darci->WorldPos.Z >> 8,
0x1000,
THING_array,
THING_ARRAY_SIZE,
1 << CLASS_PERSON);
Thing *p_found;
for (i = 0; i < num_found; i++)
{
p_found = TO_THING(THING_array[i]);
if (p_found == darci)
{
continue;
}
if (p_found->State == STATE_DEAD)
{
continue;
}
display = FALSE;
switch(p_found->Genus.Person->PersonType)
{
case PERSON_THUG_RASTA:
case PERSON_THUG_GREY:
case PERSON_THUG_RED:
display = TRUE;
size = 0.5F;
colour = 0xdd2222;
break;
case PERSON_MIB1:
case PERSON_MIB2:
case PERSON_MIB3:
display = TRUE;
size = 0.5F;
colour = 0xdddddd;
break;
default:
break;
}
if (PCOM_person_wants_to_kill(p_found) == THING_NUMBER(darci))
{
display = TRUE;
size = flash;
}
if (display)
{
dx = float(p_found->WorldPos.X - darci->WorldPos.X >> 8);
dz = float(p_found->WorldPos.Z - darci->WorldPos.Z >> 8);
dist = sqrt(dx*dx + dz*dz);
dist *= 1.0F / (16.0F * 256.0F);
if (dist < 1.0F)
{
if (PANEL_scanner_poo)
{
dangle = atan2(dx,dz) - float(darci->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F);
}
else
{
dangle = atan2(dx,dz) - float(FC_cam[0].yaw>>8) * (2.0F * PI / 2048.0F);
}
x = PLS_MID_X + (float)sin(dangle) * PLS_RADIUS * dist;
y = PLS_MID_Y + (float)cos(dangle) * PLS_RADIUS * dist;
size += 0.5F;
size *= 2.0F;
PANEL_draw_quad(
x - size, y - size,
x + size, y + size,
POLY_PAGE_LASTPANEL_ADD,
colour,
pls->u1,
pls->v1,
pls->u2,
pls->v2);
}
}
}
}
//
// Draw the text messages.
//
PANEL_new_text_process();
{
#define PLT_X 214
#define PLT_Y 360
SLONG i;
SLONG ybase;
SLONG y = m_iPanelYPos - ( 480 - PLT_Y );
// Left edge.
SLONG x1 = ( m_iPanelXPos < 260 ) ? ( m_iPanelXPos + PLT_X ) : ( 32 );
// Right edge.
SLONG x2 = ( m_iPanelXPos < 260 ) ? ( 640 - 32 ) : ( m_iPanelXPos - 16 );
SLONG height;
PANEL_Text *pt;
// This is a very clunky bodge, in coversations multiple lines
// of text are added but none are removed from the tail, so when
// we come back the difference between head and tail can be over
// the maximum buffer length, which will then wrap around and display
// the same message multiple times, therefore if we have more than
// PANEL_MAX_TEXTS messages we need to shift our head forwards.to
// remove those bogus messages.
// Nicked from the PSX. Oh, and "klunky" is spelled thusly - TomF.
if ((PANEL_text_tail-PANEL_text_head)>PANEL_MAX_TEXTS)
{
PANEL_text_head=PANEL_text_tail-(PANEL_MAX_TEXTS-1);
}
for (i = PANEL_text_head; i < PANEL_text_tail; i++)
{
pt = &PANEL_text[i & (PANEL_MAX_TEXTS - 1)];
if (i == PANEL_text_head)
{
if (pt->delay == 0)
{
PANEL_text_head += 1;
}
}
if (pt->delay != 0)
{
//
// Draw this message. Start off with the face.
//
ybase = y;
PANEL_new_face(
pt->who,
x1,
ybase - 2,
PANEL_FACE_SMALL);
//
// The text....
//
height = FONT2D_DrawStringWrapTo ( pt->text,
x1 + 36 + 6,
y+2,
0xffffff,
256,
POLY_PAGE_FONT2D,
0,
x2
) - y;
height += 20;
//
// The speech bubble.
//
PANEL_last_bubble(
x1 + 36,
ybase - 4,
float(FONT2D_rightmost_x) + 6.0F,
ybase - 2 + height);
#ifdef TARGET_DC
// draw it again, so it's brighter.
FONT2D_DrawStringWrapTo ( pt->text,
x1 + 36 + 6,
y+2,
0xffffff,
256,
POLY_PAGE_FONT2D,
0,
x2
);
#endif
if (height < 34)
{
height = 34;
}
y += height;
}
}
}
#ifdef TARGET_DC
// This is instead of that wank PANEL_draw_buffered tripe.
if ( slPANEL_draw_timer_time >= 0 )
{
float time = slPANEL_draw_timer_time * ( 1.0f / 100.0f );
CBYTE countdown[8];
SLONG mins = 0;
ASSERT(time < 1000.0F);
while(time >= 60.0F)
{
mins += 1;
time -= 60.0F;
}
sprintf(countdown, "%02d:%02d", mins, SLONG(time));
if ((time<30)&&!mins)
{
static UWORD pulse=0;
SLONG colour;
pulse+=(TICK_RATIO*80)>>TICK_SHIFT;
colour=(SIN(pulse&2047)>>9)+128;
colour=colour|(colour<<8);
FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xff0000|colour, 256 + 64);
}
else
{
FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xffffff, 256 + 64);
}
slPANEL_draw_timer_time = -1;
}
#endif
//
// Draw the signs.
//
SLONG dtime = GetTickCount() - PANEL_sign_time;
if (dtime < 3000)
{
dtime %= 600;
if (dtime < 400)
{
float du;
float dv;
float u_mid;
float v_mid;
u_mid = (PANEL_sign_which & 1) ? 0.75F : 0.25F;
v_mid = (PANEL_sign_which & 2) ? 0.75F : 0.25F;
du = (PANEL_sign_flip & PANEL_SIGN_FLIP_LEFT_AND_RIGHT) ? -0.25F : +0.25F;
dv = (PANEL_sign_flip & PANEL_SIGN_FLIP_TOP_AND_BOTTOM) ? -0.25F : +0.25F;
#define PANEL_SIGN_X 320
//#define PANEL_SIGN_Y 100
int iYPos;
if ( bPanelIsAtBottomOfScreen )
{
iYPos = 100;
}
else
{
iYPos = 480 - 100;
}
PANEL_draw_quad(
PANEL_SIGN_X - 64,
iYPos - 64,
PANEL_SIGN_X + 64,
iYPos + 64,
POLY_PAGE_SIGN,
0xffffffff,
u_mid - du,
v_mid - dv,
u_mid + du,
v_mid + dv);
}
}
//
// The panel search mode.
//
{
Thing *darci = NET_PERSON(0);
if(darci)
{
if(darci->State==STATE_SEARCH)
{
//
// Percentage complete...
//
float percent;
percent = darci->Genus.Person->Timer1 * (1.0F / (100.0F * 256.0F));
SATURATE(percent, 0.0F, 1.0F);
//
// Draw the background box...
//
PANEL_last_bubble(
320 - 80,
220 - 16,
320 + 80,
220 + 16);
//
// The completion bar...
//
PANEL_draw_quad(
320 - 75,
220 - 12,
320 - 75 + 151 * percent,
220 + 13,
POLY_PAGE_COLOUR,
0x7788bb);
if ((darci->Genus.Person->Timer1 & 0xfff) < 3000 || percent == 1.0F)
{
CBYTE *text;
if (percent == 1.0F)
{
text = XLAT_str(X_COMPLETE);
}
else
{
text = XLAT_str(X_SEARCHING);
}
FONT2D_DrawStringCentred(text, 320, 220 - 8, 0xffffff);
}
}
}
}
{
int iYPos = bPanelIsAtBottomOfScreen ? 0 : 360;
#ifdef TARGET_DC
extern bool g_bShowDarcisPositionOnScreen;
CBYTE text[64];
if ( g_bShowDarcisPositionOnScreen )
{
sprintf(text, "Darci is at (%d,%d)", NET_PERSON(0)->WorldPos.X >> 16, NET_PERSON(0)->WorldPos.Z >> 16);
PANEL_crap_text ( 320, iYPos + 40, text );
}
extern bool g_bCheatsEnabled;
if ( g_bCheatsEnabled )
{
sprintf(text, "Cheats are enabled" );
PANEL_crap_text ( 320, iYPos + 20, text );
}
extern bool m_bTweakFramerates;
extern int m_iDCFramerateMin;
extern int m_iDCFramerateMax;
extern SLONG CurDrawDistance;
if ( m_bTweakFramerates )
{
sprintf(text, "Lo %i, hi %i, draw %f", m_iDCFramerateMin, m_iDCFramerateMax, (float)CurDrawDistance / 256.0f );
PANEL_crap_text ( 320, iYPos + 100, text );
}
#endif
#ifdef DEBUG
#ifdef TARGET_DC
// Show the cheat string on screen.
extern char cCheatString[];
if ( cCheatString[0] != '\0' )
{
sprintf(text, "Cheat string: <%s>", cCheatString );
PANEL_crap_text ( 320, iYPos + 80, text );
}
#endif
#if 0
// Show the fog table mode stuff.
extern float m_fFogTableDebugStart;
extern float m_fFogTableDebugEnd;
extern float m_fFogTableDebugDensity;
extern DWORD m_dwFogTableDebugFogTableMode;
char *pcMode;
switch ( m_dwFogTableDebugFogTableMode )
{
case D3DFOG_LINEAR:
pcMode = "Lin";
break;
case D3DFOG_EXP:
pcMode = "Exp";
break;
case D3DFOG_EXP2:
pcMode = "Exp2";
break;
case D3DFOG_NONE:
pcMode = "None";
break;
default:
pcMode = "None";
break;
}
sprintf ( text, "Start %f, end %f, density %f, mode %s",
m_fFogTableDebugStart,
m_fFogTableDebugEnd,
m_fFogTableDebugDensity,
pcMode );
PANEL_crap_text ( 20, iYPos + 100, text );
#endif
#endif
#ifdef TARGET_DC
#ifdef _DEBUG
extern int g_iCacheReplacements;
extern bool g_bCacheReplacementThrash;
// Show the cache performance.
static char cCacheHistory[31] = "\0";
for ( int i = 29; i > 0; i-- )
{
cCacheHistory[i] = cCacheHistory[i-1];
}
cCacheHistory[30] = '\0';
if ( g_iCacheReplacements > 0 )
{
if ( g_iCacheReplacements < 100 )
{
cCacheHistory[0] = "0123456789"[g_iCacheReplacements/10];
}
else
{
// Nads - way too many.
cCacheHistory[0] = '+';
}
}
else
{
cCacheHistory[0] = ' ';
}
PANEL_crap_text ( 320, iYPos + 60, cCacheHistory );
if ( g_bCacheReplacementThrash )
{
// Thrash!
PANEL_crap_text ( 310, iYPos + 60, "T" );
}
g_iCacheReplacements = 0;
g_bCacheReplacementThrash = FALSE;
// And show the actual cache behaviour.
extern int m_iLRUQueueSize;
extern DWORD m_dwSizeOfQueue;
sprintf ( text, "Length %i, size %i",
m_iLRUQueueSize,
m_dwSizeOfQueue );
PANEL_crap_text ( 310, iYPos + 80, text );
#endif
#endif
}
#ifndef TARGET_DC
extern SLONG FARFACET_num_squares_drawn;
{
CBYTE text[64];
sprintf(text, "FARFACET squares drawn: %d", FARFACET_num_squares_drawn);
FONT2D_DrawString(
text,
51,
51,
0x000000,
256,
POLY_PAGE_FONT2D,
0);
FONT2D_DrawString(
text,
50,
50,
0xffffff,
256,
POLY_PAGE_FONT2D,
0);
}
extern UBYTE just_asked_for_mode_now;
extern UBYTE just_asked_for_mode_number;
extern float music_volume;
extern SLONG MUSIC_is_playing(void);
#ifdef _DEBUG
if (just_asked_for_mode_now)
{
just_asked_for_mode_now = FALSE;
CBYTE text[64];
sprintf(text, "music mode %d vol %f %s", just_asked_for_mode_number, music_volume, (MUSIC_is_playing()) ? "Playing" : "Silence");
FONT2D_DrawString(
text,
320,
200,
0xffff,
256,
POLY_PAGE_FONT2D,
0);
}
#endif
#endif
#ifndef TARGET_DC
static SLONG i_know = 0;
static SLONG the_answer = 0;
if (!i_know)
{
the_answer = ENV_get_value_number("iamapsx",FALSE);
i_know = TRUE;
}
if (the_answer)
{
FONT2D_DrawString("PSX mode", 7, 17, 0x000000);
FONT2D_DrawString("PSX mode", 5, 15, 0xff2288);
}
#endif
#ifndef TARGET_DC
{
static ULONG timestamp_colour = 0;
static CBYTE version_number[128];
if (Keys[KB_V])
{
timestamp_colour = 0xf0f0f0f0;
}
if (timestamp_colour)
{
if (!version_number[0])
{
CBYTE ts[256];
float vn;
sprintf(ts, __DATE__);
CBYTE *month[12] =
{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
SLONG i;
vn = 0.0F;
for (i = 0; i < 12; i++)
{
if (toupper(ts[0]) == toupper(month[i][0]) &&
toupper(ts[1]) == toupper(month[i][1]) &&
toupper(ts[2]) == toupper(month[i][2]))
{
vn = i - 8.0F;
}
}
SLONG day = atoi(ts + 4);
vn += day * 0.03F;
SLONG year = atoi(ts + 7);
vn += (year - 1999) * 12;
sprintf(version_number, "Version number %.2f : Compiled %s", vn, __DATE__);
}
timestamp_colour -= 0x10101010;
//
// Show the version number.
//
FONT2D_DrawString(
version_number,
22,
22,
0x00000000);
FONT2D_DrawString(
version_number,
20,
20,
timestamp_colour);
}
}
#endif
#if 0
// FINAL BUILD DONE! HOORAY!
#ifdef TARGET_DC
// Just for non-final builds.
static CBYTE version_number[64] = "";
if ( version_number[0] == '\0' )
{
CBYTE ts[40] = __DATE__;
float vn;
CBYTE *month[12] =
{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
SLONG i;
vn = 0.0F;
for (i = 0; i < 12; i++)
{
if (toupper(ts[0]) == toupper(month[i][0]) &&
toupper(ts[1]) == toupper(month[i][1]) &&
toupper(ts[2]) == toupper(month[i][2]))
{
vn = i - 8.0F;
}
}
SLONG day = atoi(ts + 4);
vn += day * 0.03F;
SLONG year = atoi(ts + 7);
vn += (year - 1999) * 12;
sprintf(version_number, "Version %.2f", vn );
}
extern bool bDontShowThePauseScreen;
if ( !bDontShowThePauseScreen )
{
FONT2D_DrawString(
"(C)2000 Mucky Foot Productions",
20,
20,
0xffffffff);
FONT2D_DrawString(
"Test version - not for release",
20,
35,
0xffffffff);
FONT2D_DrawString(
version_number,
20,
50,
0xffffffff);
}
#endif
#endif
//TRACE ( "PDo" );
}
#ifdef TARGET_DC
static int iVMUAmmoDrawCountdown = 0;
static VMU_Screen vmuscreenTemp;
// The byte patterns of numbers.
#define FROM_BINARY(a,b,c,d,e) ( (a<<4) | (b<<3) | (c<<2) | (d<<1) | (e<<0) )
UBYTE bNumberPattern[11][7] =
{
{ // 0
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
},
{ // 1
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,1,1,1,1 ),
},
{ // 2
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,1,1,0,0 ),
FROM_BINARY ( 1,1,0,0,0 ),
FROM_BINARY ( 1,1,1,1,1 ),
},
{ // 3
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
},
{ // 4
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,1,1,1 ),
FROM_BINARY ( 0,1,1,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,1,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
},
{ // 5
FROM_BINARY ( 1,1,1,1,1 ),
FROM_BINARY ( 1,1,0,0,0 ),
FROM_BINARY ( 1,1,1,1,0 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
},
{ // 6
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,0,0 ),
FROM_BINARY ( 1,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
},
{ // 7
FROM_BINARY ( 1,1,1,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,1,1,1 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 0,1,1,0,0 ),
FROM_BINARY ( 0,1,1,0,0 ),
},
{ // 8
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
},
{ // 9
FROM_BINARY ( 0,1,1,1,0 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 1,1,0,1,1 ),
FROM_BINARY ( 0,1,1,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,1,1,1,0 ),
},
{ // separator dot.
FROM_BINARY ( 0,0,0,0,0 ),
FROM_BINARY ( 0,0,0,0,0 ),
FROM_BINARY ( 0,0,0,1,1 ),
FROM_BINARY ( 0,0,1,1,1 ),
FROM_BINARY ( 0,0,1,1,0 ),
FROM_BINARY ( 0,0,0,0,0 ),
FROM_BINARY ( 0,0,0,0,0 ),
},
};
void Panel_Draw_VMU_Character ( int iCharacter, UBYTE *pbScanline, int iXpos )
{
// Can't do anything too close to the left edge.
ASSERT ( iXpos < ( 48 - 16 ) );
// Go to correct X pos (right-hand byte).
pbScanline += 5 - ( iXpos >> 3 );
UBYTE *pbSrc = bNumberPattern[iCharacter];
int iShift = iXpos & 0x7;
for ( int i = 0; i < 7; i++ )
{
UWORD uwSrc = (UWORD)*pbSrc++;
uwSrc <<= iShift;
*(pbScanline-0) |= (UBYTE)( uwSrc & 0xff );
*(pbScanline-1) |= (UBYTE)( uwSrc >> 8 );
pbScanline += 6;
}
}
void PANEL_draw_VMU_ammo_counts ( void )
{
iVMUAmmoDrawCountdown--;
if ( iVMUAmmoDrawCountdown > 0 )
{
return;
}
iVMUAmmoDrawCountdown = 30;
// OK, find out how much ammo of each sort we have, and whether we have the weapons or not.
// This order matches the order on the VMU screen.
enum eWeaponNumber
{
WEAP_PISTOL = 0,
WEAP_SHOTGUN = 1,
WEAP_M16 = 2,
WEAP_GRENADE = 3,
};
int i;
bool bHaveWeapon[4];
int iAmmo[4];
int iMags[4];
for ( i = 0; i < 4; i++ )
{
bHaveWeapon[i] = FALSE;
iAmmo[i] = 0;
iMags[i] = 0;
}
// Run through the weapons.
Thing *darci = NET_PERSON(0);
Thing *p_special = NULL;
// The pistol is special.
if (darci->Flags & FLAGS_HAS_GUN)
{
bHaveWeapon[WEAP_PISTOL] = TRUE;
}
// THIS IS FUCKING INSANE GUYS. So I'm just going to type it in, and if it doesn't work, it's your fault.
iMags[WEAP_PISTOL] = darci->Genus.Person->ammo_packs_pistol / 15;
iAmmo[WEAP_PISTOL] = darci->Genus.Person->Ammo;
iMags[WEAP_SHOTGUN] = darci->Genus.Person->ammo_packs_shotgun / SPECIAL_AMMO_IN_A_SHOTGUN;
iMags[WEAP_M16] = darci->Genus.Person->ammo_packs_ak47 / SPECIAL_AMMO_IN_A_AK47;
ASSERT ( ( darci->Genus.Person->ammo_packs_pistol % 15 ) == 0 );
ASSERT ( ( darci->Genus.Person->ammo_packs_ak47 % SPECIAL_AMMO_IN_A_AK47 ) == 0 );
ASSERT ( ( darci->Genus.Person->ammo_packs_shotgun % SPECIAL_AMMO_IN_A_SHOTGUN ) == 0 );
if ( darci->Genus.Person->SpecialList != NULL )
{
p_special = TO_THING(darci->Genus.Person->SpecialList);
while(p_special)
{
ASSERT(p_special->Class == CLASS_SPECIAL);
switch ( p_special->Genus.Special->SpecialType )
{
case SPECIAL_SHOTGUN:
// We have a shotty.
ASSERT ( !bHaveWeapon[WEAP_SHOTGUN] );
bHaveWeapon[WEAP_SHOTGUN] = TRUE;
iAmmo[WEAP_SHOTGUN] = p_special->Genus.Special->ammo;
break;
case SPECIAL_AK47:
// We have an AK47, which we now call an M16.
ASSERT ( !bHaveWeapon[WEAP_M16] );
bHaveWeapon[WEAP_M16] = TRUE;
iAmmo[WEAP_M16] = p_special->Genus.Special->ammo;
break;
case SPECIAL_GRENADE:
// Should only have one grenade special.
ASSERT ( !bHaveWeapon[WEAP_GRENADE] );
bHaveWeapon[WEAP_GRENADE] = TRUE;
iAmmo[WEAP_GRENADE] = p_special->Genus.Special->ammo;
if ( iAmmo[WEAP_GRENADE] == 0 )
{
// Er... this means we don't have grenades.
bHaveWeapon[WEAP_GRENADE] = FALSE;
}
break;
default:
// You think I care?
break;
}
if (p_special->Genus.Special->NextSpecial)
p_special = TO_THING(p_special->Genus.Special->NextSpecial);
else
p_special = NULL;
}
}
// Crappy fudge. Driving Bronze and other training missions start you off
// with 15 pistol rounds, but no pistol, which is silly. So if we don't have a
// a pistol, pretend we have no rounds or clips as well.
if ( !bHaveWeapon[WEAP_PISTOL] )
{
iAmmo[WEAP_PISTOL] = 0;
iMags[WEAP_PISTOL] = 0;
}
extern VMU_Screen *pvmuscreenAmmo;
// Copy the weapon bitmaps over.
memcpy ( vmuscreenTemp.bData, pvmuscreenAmmo->bData, 32 * 6 );
vmuscreenTemp.bRotated = FALSE;
#define WEAPON_BAR_SCANLINE_SIZE 8
for ( i = 0; i < 4; i++ )
{
if ( !bHaveWeapon[i] )
{
if ( ( iAmmo[i] == 0 ) && ( iMags[i] == 0 ) )
{
// No ammo or mags and we don't have it. So blank it.
memset ( vmuscreenTemp.bData + 6 * WEAPON_BAR_SCANLINE_SIZE * i, 0, 6 * WEAPON_BAR_SCANLINE_SIZE );
}
else
{
// We have some ammo, but don't actually have the weapon yet. Grey it out.
UBYTE *pbScreen = vmuscreenTemp.bData + 6 * WEAPON_BAR_SCANLINE_SIZE * i;
UBYTE bMask = 0x55;
for ( int j = 0; j < WEAPON_BAR_SCANLINE_SIZE; j++ )
{
*pbScreen++ &= bMask;
*pbScreen++ &= bMask;
*pbScreen++ &= bMask;
*pbScreen++ &= bMask;
*pbScreen++ &= bMask;
*pbScreen++ &= bMask;
bMask = ~bMask;
}
}
}
// X positions of the left side of the char, counted from the left of the screen.
#define WEAPON_MAGS_TENS 22
#define WEAPON_MAGS_UNIT 16
#define WEAPON_SEPARATOR 12
#define WEAPON_AMMO_TENS 6
#define WEAPON_AMMO_UNIT 0
UBYTE *pbScreen = vmuscreenTemp.bData + 6 * WEAPON_BAR_SCANLINE_SIZE * i;
if ( iMags[i] > 0 )
{
// Draw mag number.
if ( iMags[i] >= 10 )
{
Panel_Draw_VMU_Character ( ( iMags[i] / 10 ), pbScreen, WEAPON_MAGS_TENS );
}
Panel_Draw_VMU_Character ( ( iMags[i] % 10 ), pbScreen, WEAPON_MAGS_UNIT );
// The separator - character 10.
Panel_Draw_VMU_Character ( 10, pbScreen, WEAPON_SEPARATOR );
}
if ( ( iMags[i] > 0 ) || ( iAmmo[i] > 0 ) || bHaveWeapon[i] )
{
// Draw ammo number.
if ( iAmmo[i] >= 10 )
{
Panel_Draw_VMU_Character ( ( iAmmo[i] / 10 ), pbScreen, WEAPON_AMMO_TENS );
}
Panel_Draw_VMU_Character ( ( iAmmo[i] % 10 ), pbScreen, WEAPON_AMMO_UNIT );
}
}
// And write the screen out.
WriteLCDScreenToCurrentController ( &vmuscreenTemp );
#undef WEAPON_BAR_SCANLINE_SIZE
#undef WEAPON_MAGS_TENS
#undef WEAPON_MAGS_UNIT
#undef WEAPON_SEPARATOR
#undef WEAPON_AMMO_TENS
#undef WEAPON_AMMO_UNIT
}
#endif
#ifndef TARGET_DC
void PANEL_draw_completion_bar(SLONG completion)
{
#define START_R 50
#define START_G 59
#define START_B 80
#define END_R 210
#define END_G 216
#define END_B 208
SLONG along;
SLONG r;
SLONG g;
SLONG b;
#ifndef TARGET_DC
POLY_frame_init(FALSE,FALSE);
#endif
SLONG i;
SLONG colour;
for (i = 0; i < (completion >> 3); i += 1)
{
r = START_R + (END_R - START_R) * i >> 5;
g = START_G + (END_G - START_G) * i >> 5;
b = START_B + (END_B - START_B) * i >> 5;
colour = (r << 16) | (g << 8) | (b << 0);
PANEL_draw_quad(
5 + i * 20, 455,
23 + i * 20, 475,
POLY_PAGE_COLOUR,
colour);
}
#ifndef TARGET_DC
POLY_frame_draw(FALSE,FALSE);
#endif
}
#endif
bool bScreensaverEnabled = FALSE;
// Darkness of screensaver, from 0(off)->0xffff(full on)
int iScreenSaverDarkness = 0;
int iScreensaverXPos = 320;
int iScreensaverYPos = 240;
int iScreensaverXInc = 4;
int iScreensaverYInc = 4;
int iScreensaverAngle = 0;
int iScreensaverAngleInc = 0x2ff;
DWORD dwPseudorandomSeed = 0;
DWORD dwGetRandomishNumber ( void )
{
dwPseudorandomSeed *= 51929;
dwPseudorandomSeed ^= dwPseudorandomSeed >> 3;
dwPseudorandomSeed ^= dwPseudorandomSeed << 8;
dwPseudorandomSeed += 31415;
return ( dwPseudorandomSeed >> 8 );
}
#define SCREENSAVER_SIZE 128
void PANEL_enable_screensaver ( void )
{
if ( !bScreensaverEnabled )
{
bScreensaverEnabled = TRUE;
iScreensaverXPos = 320;
iScreensaverYPos = 240;
iScreensaverXInc = 4;
iScreensaverYInc = 4;
}
}
void PANEL_disable_screensaver ( bool bImmediately )
{
bScreensaverEnabled = FALSE;
if ( bImmediately )
{
// Bin the fade in.
iScreenSaverDarkness = 0;
}
}
void PANEL_screensaver_draw ( void )
{
if ( bScreensaverEnabled )
{
iScreenSaverDarkness += 100;
if ( iScreenSaverDarkness > 0xffff )
{
iScreenSaverDarkness = 0xffff;
}
}
else
{
iScreenSaverDarkness -= 10000;
if ( iScreenSaverDarkness < 0 )
{
iScreenSaverDarkness = 0;
}
}
if ( iScreenSaverDarkness == 0 )
{
// don't do it.
return;
}
#ifndef TARGET_DC
POLY_frame_init(FALSE,FALSE);
#endif
// Bounce around the screen.
iScreensaverXPos += iScreensaverXInc;
iScreensaverYPos += iScreensaverYInc;
iScreensaverAngle += iScreensaverAngleInc;
if ( iScreensaverXPos > 640 - SCREENSAVER_SIZE )
{
iScreensaverXPos = 640 - SCREENSAVER_SIZE;
iScreensaverXInc = -( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 );
iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff );
}
else if ( iScreensaverXPos < 0 )
{
iScreensaverXPos = 0;
iScreensaverXInc = ( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 );
iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff );
}
if ( iScreensaverYPos > 480 - SCREENSAVER_SIZE )
{
iScreensaverYPos = 480 - SCREENSAVER_SIZE;
iScreensaverYInc = -( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 );
iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff );
}
else if ( iScreensaverYPos < 0 )
{
iScreensaverYPos = 0;
iScreensaverYInc = ( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 );
iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff );
}
POLY_Point pp [4];
POLY_Point *quad[4];
DWORD dwColour = ( ( iScreenSaverDarkness & 0xff00 ) << 16 );
float fSinAngle, fCosAngle;
float fAngle = (float)( iScreensaverAngle & 0xffff ) * ( 2.0f * 3.1415927f / 65536.0f );
#ifdef TARGET_DC
_SinCosA ( &fSinAngle, &fCosAngle, fAngle );
#else
fSinAngle = sinf ( fAngle );
fCosAngle = cosf ( fAngle );
#endif
fSinAngle *= 0.65f;
fCosAngle *= 0.65f;
// First draw the "spotlight" logo.
pp[0].X = (float)iScreensaverXPos;
pp[0].Y = (float)iScreensaverYPos;
pp[0].z = 0.0f;
pp[0].Z = 0.99999f;
pp[0].u = 0.5f + fSinAngle;
pp[0].v = 0.5f + fCosAngle;
pp[0].colour = dwColour;
pp[0].specular = 0xff000000;
pp[1].X = (float)iScreensaverXPos + SCREENSAVER_SIZE;
pp[1].Y = (float)iScreensaverYPos;
pp[1].z = 0.0f;
pp[1].Z = 0.99999f;
pp[1].u = 0.5f - fCosAngle;
pp[1].v = 0.5f + fSinAngle;
pp[1].colour = dwColour;
pp[1].specular = 0xff000000;
pp[2].X = (float)iScreensaverXPos;
pp[2].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
pp[2].z = 0.0f;
pp[2].Z = 0.99999f;
pp[2].u = 0.5f + fCosAngle;
pp[2].v = 0.5f - fSinAngle;
pp[2].colour = dwColour;
pp[2].specular = 0xff000000;
pp[3].X = (float)iScreensaverXPos + SCREENSAVER_SIZE;
pp[3].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
pp[3].z = 0.0f;
pp[3].Z = 0.99999f;
pp[3].u = 0.5f - fSinAngle;
pp[3].v = 0.5f - fCosAngle;
pp[3].colour = dwColour;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, POLY_PAGE_FADE_MF, FALSE, TRUE);
// Now draw the darkener around it.
// Top block.
pp[0].X = 0.0f;
pp[0].Y = 0.0f;
pp[1].X = 640.0f;
pp[1].Y = 0.0f;
pp[2].X = 0.0f;
pp[2].Y = (float)iScreensaverYPos;
pp[3].X = 640.0f;
pp[3].Y = (float)iScreensaverYPos;
POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE);
// Bottom block.
pp[0].X = 0.0f;
pp[0].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
pp[1].X = 640.0f;
pp[1].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
pp[2].X = 0.0f;
pp[2].Y = 480.0f;
pp[3].X = 640.0f;
pp[3].Y = 480.0f;
POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE);
// Left block.
pp[0].X = 0.0f;
pp[0].Y = (float)iScreensaverYPos;
pp[1].X = (float)iScreensaverXPos;
pp[1].Y = (float)iScreensaverYPos;
pp[2].X = 0.0f;
pp[2].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
pp[3].X = (float)iScreensaverXPos;
pp[3].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE);
// Right block.
pp[0].X = (float)iScreensaverXPos + SCREENSAVER_SIZE;
pp[0].Y = (float)iScreensaverYPos;
pp[1].X = 640.0f;
pp[1].Y = (float)iScreensaverYPos;
pp[2].X = (float)iScreensaverXPos + SCREENSAVER_SIZE;
pp[2].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
pp[3].X = 640.0f;
pp[3].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE;
POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE);
#ifndef TARGET_DC
POLY_frame_draw(FALSE,FALSE);
#endif
}