summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cgame/cg_animation.c101
-rw-r--r--src/cgame/cg_buildable.c4
-rw-r--r--src/cgame/cg_draw.c37
-rw-r--r--src/cgame/cg_local.h1
-rw-r--r--src/cgame/cg_main.c8
-rw-r--r--src/cgame/cg_servercmds.c12
-rw-r--r--src/cgame/cg_view.c2
-rw-r--r--src/game/bg_misc.c2
-rw-r--r--src/game/bg_public.h1
-rw-r--r--src/game/g_active.c2
-rw-r--r--src/game/g_buildable.c22
-rw-r--r--src/game/g_combat.c72
-rw-r--r--src/game/g_local.h1
-rw-r--r--src/game/g_weapon.c4
-rw-r--r--src/game/tremulous.h11
-rwxr-xr-xui/generate-infopanes.sh3
-rw-r--r--ui/infopanes.def.h417
17 files changed, 642 insertions, 58 deletions
diff --git a/src/cgame/cg_animation.c b/src/cgame/cg_animation.c
new file mode 100644
index 00000000..5295998e
--- /dev/null
+++ b/src/cgame/cg_animation.c
@@ -0,0 +1,101 @@
+/*
+ * Portions Copyright (C) 2000-2001 Tim Angus
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the OSML - Open Source Modification License v1.0 as
+ * described in the file COPYING which is distributed with this source
+ * code.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "cg_local.h"
+
+/*
+===============
+CG_RunLerpFrame
+
+Sets cg.snap, cg.oldFrame, and cg.backlerp
+cg.time should be between oldFrameTime and frameTime after exit
+===============
+*/
+void CG_RunLerpFrame( lerpFrame_t *lf )
+{
+ int f, numFrames;
+ animation_t *anim;
+
+ // debugging tool to get no animations
+ if( cg_animSpeed.integer == 0 )
+ {
+ lf->oldFrame = lf->frame = lf->backlerp = 0;
+ return;
+ }
+
+ // if we have passed the current frame, move it to
+ // oldFrame and calculate a new frame
+ if( cg.time >= lf->frameTime )
+ {
+ lf->oldFrame = lf->frame;
+ lf->oldFrameTime = lf->frameTime;
+
+ // get the next frame based on the animation
+ anim = lf->animation;
+ if( !anim->frameLerp )
+ return; // shouldn't happen
+
+ if( cg.time < lf->animationTime )
+ lf->frameTime = lf->animationTime; // initial lerp
+ else
+ lf->frameTime = lf->oldFrameTime + anim->frameLerp;
+
+ f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
+ numFrames = anim->numFrames;
+ if( anim->flipflop )
+ numFrames *= 2;
+
+ if( f >= numFrames )
+ {
+ f -= numFrames;
+ if( anim->loopFrames )
+ {
+ f %= anim->loopFrames;
+ f += anim->numFrames - anim->loopFrames;
+ }
+ else
+ {
+ f = numFrames - 1;
+ // the animation is stuck at the end, so it
+ // can immediately transition to another sequence
+ lf->frameTime = cg.time;
+ }
+ }
+
+ if( anim->reversed )
+ lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
+ else if( anim->flipflop && f >= anim->numFrames )
+ lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames );
+ else
+ lf->frame = anim->firstFrame + f;
+
+ if( cg.time > lf->frameTime )
+ {
+ lf->frameTime = cg.time;
+ if( cg_debugAnim.integer )
+ CG_Printf( "Clamp lf->frameTime\n" );
+ }
+ }
+
+ if( lf->frameTime > cg.time + 200 )
+ lf->frameTime = cg.time;
+
+ if( lf->oldFrameTime > cg.time )
+ lf->oldFrameTime = cg.time;
+
+ // calculate current lerp value
+ if( lf->frameTime == lf->oldFrameTime )
+ lf->backlerp = 0;
+ else
+ lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
+}
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
index 954b1aa3..39b6d959 100644
--- a/src/cgame/cg_buildable.c
+++ b/src/cgame/cg_buildable.c
@@ -610,12 +610,12 @@ static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t
VectorMA( inOrigin, -TRACE_DEPTH, normal, end );
VectorMA( inOrigin, 1.0f, normal, start );
- CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
+ CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID );
if( tr.fraction == 1.0f )
{
//erm we missed completely - try again with a box trace
- CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
+ CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID );
}
VectorMA( inOrigin, tr.fraction * -TRACE_DEPTH, normal, outOrigin );
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c
index 40a49358..38af5c76 100644
--- a/src/cgame/cg_draw.c
+++ b/src/cgame/cg_draw.c
@@ -3222,8 +3222,9 @@ static void CG_Draw2D( void )
CG_DrawCenterString( );
}
-#define PAINBLEND_BORDER_W 128.0f
-#define PAINBLEND_BORDER_H 96.0f
+#define PAINBLEND_BORDER_W 0.15f
+#define PAINBLEND_BORDER_H 0.07f
+
/*
===============
CG_PainBlend
@@ -3234,7 +3235,7 @@ static void CG_PainBlend( void )
vec4_t color;
int damage;
float damageAsFracOfMax;
- qhandle_t shader = cgs.media.whiteShader;
+ qhandle_t shader = cgs.media.viewBloodShader;
float x, y, w, h;
damage = cg.lastHealth - cg.snap->ps.stats[ STAT_HEALTH ];
@@ -3283,38 +3284,38 @@ static void CG_PainBlend( void )
//left
x = 0.0f; y = 0.0f;
- w = PAINBLEND_BORDER_W; h = 480.0f;
+ w = PAINBLEND_BORDER_W * 640.0f; h = 480.0f;
CG_AdjustFrom640( &x, &y, &w, &h );
trap_R_DrawStretchPic( x, y, w, h,
- 0.0f, 0.0f,
- PAINBLEND_BORDER_W / 640.0f, 1.0f,
+ cg_painBlendZoom.value, cg_painBlendZoom.value,
+ cg_painBlendZoom.value + PAINBLEND_BORDER_W, 1.0f - cg_painBlendZoom.value,
shader );
//right
- x = 640.0f - PAINBLEND_BORDER_W; y = 0.0f;
- w = PAINBLEND_BORDER_W; h = 480.0f;
+ x = 640.0f - ( PAINBLEND_BORDER_W * 640.0f ); y = 0.0f;
+ w = PAINBLEND_BORDER_W * 640.0f; h = 480.0f;
CG_AdjustFrom640( &x, &y, &w, &h );
trap_R_DrawStretchPic( x, y, w, h,
- ( 640.0f - PAINBLEND_BORDER_W ) / 640.0f, 0.0f,
- 1.0f, 1.0f,
+ 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_W, cg_painBlendZoom.value,
+ 1.0f - cg_painBlendZoom.value, 1.0f - cg_painBlendZoom.value,
shader );
//top
- x = PAINBLEND_BORDER_W; y = 0.0f;
- w = 640.0f - 2 * PAINBLEND_BORDER_W; h = PAINBLEND_BORDER_H;
+ x = PAINBLEND_BORDER_W * 640.0f; y = 0.0f;
+ w = 640.0f - ( 2 * PAINBLEND_BORDER_W * 640.0f ); h = PAINBLEND_BORDER_H * 480.0f;
CG_AdjustFrom640( &x, &y, &w, &h );
trap_R_DrawStretchPic( x, y, w, h,
- PAINBLEND_BORDER_W / 640.0f, 0.0f,
- ( 640.0f - PAINBLEND_BORDER_W ) / 640.0f, PAINBLEND_BORDER_H / 480.0f,
+ cg_painBlendZoom.value + PAINBLEND_BORDER_W, cg_painBlendZoom.value,
+ 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_W, cg_painBlendZoom.value + PAINBLEND_BORDER_H,
shader );
//bottom
- x = PAINBLEND_BORDER_W; y = 480.0f - PAINBLEND_BORDER_H;
- w = 640.0f - 2 * PAINBLEND_BORDER_W; h = PAINBLEND_BORDER_H;
+ x = PAINBLEND_BORDER_W * 640.0f; y = 480.0f - ( PAINBLEND_BORDER_H * 480.0f );
+ w = 640.0f - ( 2 * PAINBLEND_BORDER_W * 640.0f ); h = PAINBLEND_BORDER_H * 480.0f;
CG_AdjustFrom640( &x, &y, &w, &h );
trap_R_DrawStretchPic( x, y, w, h,
- PAINBLEND_BORDER_W / 640.0f, ( 480.0f - PAINBLEND_BORDER_H ) / 480.0f,
- ( 640.0f - PAINBLEND_BORDER_W ) / 640.0f, 1.0f,
+ cg_painBlendZoom.value + PAINBLEND_BORDER_W, 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_H,
+ 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_W, 1.0f - cg_painBlendZoom.value,
shader );
trap_R_SetColor( NULL );
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index c42e1efa..7ee70554 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1475,6 +1475,7 @@ extern vmCvar_t cg_painBlendUpRate;
extern vmCvar_t cg_painBlendDownRate;
extern vmCvar_t cg_painBlendMax;
extern vmCvar_t cg_painBlendScale;
+extern vmCvar_t cg_painBlendZoom;
//TA: hack to get class an carriage through to UI module
extern vmCvar_t ui_currentClass;
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index ebc5c1e8..767aabef 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -208,6 +208,7 @@ vmCvar_t cg_painBlendUpRate;
vmCvar_t cg_painBlendDownRate;
vmCvar_t cg_painBlendMax;
vmCvar_t cg_painBlendScale;
+vmCvar_t cg_painBlendZoom;
//TA: hack to get class and carriage through to UI module
vmCvar_t ui_currentClass;
@@ -317,9 +318,10 @@ static cvarTable_t cvarTable[ ] =
{ &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
{ &cg_painBlendUpRate, "cg_painBlendUpRate", "10.0", 0 },
- { &cg_painBlendDownRate, "cg_painBlendDownRate", "1.0", 0 },
- { &cg_painBlendMax, "cg_painBlendMax", "0.5", 0 },
+ { &cg_painBlendDownRate, "cg_painBlendDownRate", "0.5", 0 },
+ { &cg_painBlendMax, "cg_painBlendMax", "0.7", 0 },
{ &cg_painBlendScale, "cg_painBlendScale", "7.0", 0 },
+ { &cg_painBlendZoom, "cg_painBlendZoom", "0.18", 0 },
{ &ui_currentClass, "ui_currentClass", "0", 0 },
{ &ui_carriage, "ui_carriage", "", 0 },
@@ -757,7 +759,7 @@ static void CG_RegisterGraphics( void )
for( i = 0; i < 11; i++ )
cgs.media.numberShaders[ i ] = trap_R_RegisterShader( sb_nums[ i ] );
- cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" ); //FIXME
+ cgs.media.viewBloodShader = trap_R_RegisterShader( "gfx/damage/fullscreen_painblend" ); //FIXME
cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" ); //FIXME?
diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c
index 24a869a0..71fbaac9 100644
--- a/src/cgame/cg_servercmds.c
+++ b/src/cgame/cg_servercmds.c
@@ -800,6 +800,18 @@ void CG_Menu( int menu )
break;
+ case MN_A_HOVEL:
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "There can only be one Hovel. Destroy the existing one if you "
+ "wish to move it." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "There can only be one Hovel\n" );
+
+ break;
+
case MN_A_NOASSERT:
if( !cg_disableWarningDialogs.integer )
{
diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c
index ec296c04..324646c9 100644
--- a/src/cgame/cg_view.c
+++ b/src/cgame/cg_view.c
@@ -532,7 +532,7 @@ static void CG_OffsetFirstPersonView( void )
AngleVectors( angles, forward, NULL, NULL );
VectorNormalize( forward );
- fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_TIME;
+ fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME;
if( fraction1 > 1.0f )
fraction1 = 1.0f;
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 4fc2ffc0..727190af 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -304,7 +304,7 @@ buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean creepTest;
HOVEL_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
- qfalse //qboolean reactorTest;
+ qtrue //qboolean reactorTest;
},
{
BA_H_SPAWN, //int buildNum;
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 25f5a90d..fa84b440 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -593,6 +593,7 @@ typedef enum
MN_A_NOOVMND,
MN_A_NOROOM,
MN_A_NORMAL,
+ MN_A_HOVEL,
MN_A_HOVEL_EXIT,
//human stuff
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 54ae33e8..fc66ccff 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -521,7 +521,7 @@ void ClientTimerActions( gentity_t *ent, int msec )
pounceSpeed = LEVEL3_POUNCE_UPG_SPEED;
if( client->ps.stats[ STAT_MISC ] < pounceSpeed && ucmd->buttons & BUTTON_ATTACK2 )
- client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL3_POUNCE_TIME ) * pounceSpeed;
+ client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL3_POUNCE_CHARGE_TIME ) * pounceSpeed;
if( !( ucmd->buttons & BUTTON_ATTACK2 ) )
{
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 5d014a22..083e0662 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -2508,9 +2508,23 @@ itemBuildError_t G_itemFits( gentity_t *ent, buildable_t buildable, int distance
if( tempent->s.eType != ET_BUILDABLE )
continue;
- if( tempent->s.modelindex == BA_A_OVERMIND )
+ if( tempent->s.modelindex == buildable )
{
- reason = IBE_OVERMIND;
+ switch( buildable )
+ {
+ case BA_A_OVERMIND:
+ reason = IBE_OVERMIND;
+ break;
+
+ case BA_A_HOVEL:
+ reason = IBE_HOVEL;
+ break;
+
+ default:
+ Com_Error( ERR_FATAL, "No reason for denying build of %d\n", buildable );
+ break;
+ }
+
break;
}
}
@@ -2832,6 +2846,10 @@ qboolean G_ValidateBuild( gentity_t *ent, buildable_t buildable )
G_TriggerMenu( ent->client->ps.clientNum, MN_A_OVERMIND );
return qfalse;
+ case IBE_HOVEL:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL );
+ return qfalse;
+
case IBE_HOVELEXIT:
G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL_EXIT );
return qfalse;
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index e869c046..d98f74c3 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -718,7 +718,29 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
hitRotation = hitRotation % 360; // Keep it in the 0-359 range
- if( !( dflags & DAMAGE_NO_LOCDAMAGE ) )
+ if( dflags & DAMAGE_NO_LOCDAMAGE )
+ {
+ for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
+ {
+ float totalModifier = 0.0f;
+ float averageModifier = 1.0f;
+
+ //average all of this upgrade's armour regions together
+ if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
+ {
+ for( j = 0; j < g_numArmourRegions[ i ]; j++ )
+ totalModifier += g_armourRegions[ i ][ j ].modifier;
+
+ if( g_numArmourRegions[ i ] )
+ averageModifier = totalModifier / g_numArmourRegions[ i ];
+ else
+ averageModifier = 1.0f;
+ }
+
+ modifier *= averageModifier;
+ }
+ }
+ else
{
for( i = 0; i < g_numDamageRegions[ class ]; i++ )
{
@@ -744,35 +766,35 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
( targ->client->ps.pm_flags & PMF_DUCKED ) ) )
modifier *= g_damageRegions[ class ][ i ].modifier;
}
- }
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
+ for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
- for( j = 0; j < g_numArmourRegions[ i ]; j++ )
+ if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
{
- qboolean rotationBound;
-
- if( g_armourRegions[ i ][ j ].minAngle >
- g_armourRegions[ i ][ j ].maxAngle )
- {
- rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle &&
- hitRotation <= 360 ) || ( hitRotation >= 0 &&
- hitRotation <= g_armourRegions[ i ][ j ].maxAngle );
- }
- else
+ for( j = 0; j < g_numArmourRegions[ i ]; j++ )
{
- rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle &&
- hitRotation <= g_armourRegions[ i ][ j ].maxAngle );
- }
+ qboolean rotationBound;
- if( rotationBound &&
- hitRatio >= g_armourRegions[ i ][ j ].minHeight &&
- hitRatio <= g_armourRegions[ i ][ j ].maxHeight &&
- ( g_armourRegions[ i ][ j ].crouch ==
- ( targ->client->ps.pm_flags & PMF_DUCKED ) ) )
- modifier *= g_armourRegions[ i ][ j ].modifier;
+ if( g_armourRegions[ i ][ j ].minAngle >
+ g_armourRegions[ i ][ j ].maxAngle )
+ {
+ rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle &&
+ hitRotation <= 360 ) || ( hitRotation >= 0 &&
+ hitRotation <= g_armourRegions[ i ][ j ].maxAngle );
+ }
+ else
+ {
+ rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle &&
+ hitRotation <= g_armourRegions[ i ][ j ].maxAngle );
+ }
+
+ if( rotationBound &&
+ hitRatio >= g_armourRegions[ i ][ j ].minHeight &&
+ hitRatio <= g_armourRegions[ i ][ j ].maxHeight &&
+ ( g_armourRegions[ i ][ j ].crouch ==
+ ( targ->client->ps.pm_flags & PMF_DUCKED ) ) )
+ modifier *= g_armourRegions[ i ][ j ].modifier;
+ }
}
}
}
diff --git a/src/game/g_local.h b/src/game/g_local.h
index ee8a8a57..d9997d49 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -639,6 +639,7 @@ typedef enum
IBE_NOASSERT,
IBE_SPWNWARN,
IBE_NOCREEP,
+ IBE_HOVEL,
IBE_HOVELEXIT,
IBE_REACTOR,
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 8f204ef5..a18a8c39 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -1253,6 +1253,9 @@ qboolean CheckPounceAttack( gentity_t *ent )
return qfalse;
}
+ if( ent->client->ps.weaponTime )
+ return qfalse;
+
// set aiming directions
AngleVectors( ent->client->ps.viewangles, forward, right, up );
@@ -1289,6 +1292,7 @@ qboolean CheckPounceAttack( gentity_t *ent )
G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage,
DAMAGE_NO_KNOCKBACK|DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE );
+ ent->client->ps.weaponTime += LEVEL3_POUNCE_TIME;
ent->client->allowedToPounce = qfalse;
return qtrue;
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index ab9db16c..93a85ba0 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -75,12 +75,13 @@
#define LEVEL3_CLAW_REPEAT 700
#define LEVEL3_CLAW_U_REPEAT 600
#define LEVEL3_POUNCE_DMG ADM(100)
-#define LEVEL3_POUNCE_RANGE 96.0f
+#define LEVEL3_POUNCE_RANGE 64.0f
#define LEVEL3_POUNCE_WIDTH 16.0f
#define LEVEL3_POUNCE_SPEED 700
#define LEVEL3_POUNCE_UPG_SPEED 800
#define LEVEL3_POUNCE_SPEED_MOD 0.75f
-#define LEVEL3_POUNCE_TIME 700
+#define LEVEL3_POUNCE_CHARGE_TIME 700
+#define LEVEL3_POUNCE_TIME 400
#define LEVEL3_BOUNCEBALL_DMG ADM(110)
#define LEVEL3_BOUNCEBALL_REPEAT 1000
#define LEVEL3_BOUNCEBALL_SPEED 1000.0f
@@ -252,7 +253,7 @@
#define HIVE_SPEED 240.0f
#define HIVE_DIR_CHANGE_PERIOD 500
-#define TRAPPER_BP 10
+#define TRAPPER_BP 8
#define TRAPPER_BT 12000
#define TRAPPER_HEALTH ABHM(50)
#define TRAPPER_REGEN 6
@@ -275,7 +276,7 @@
#define OVERMIND_ATTACK_REPEAT 1000
#define OVERMIND_VALUE 300
-#define HOVEL_BP 8
+#define HOVEL_BP 0
#define HOVEL_BT 15000
#define HOVEL_HEALTH ABHM(375)
#define HOVEL_REGEN 20
@@ -500,7 +501,7 @@
#define TESLAGEN_SPLASHRADIUS 100
#define TESLAGEN_REPEAT 250
#define TESLAGEN_RANGE 250
-#define TESLAGEN_DMG HDM(7)
+#define TESLAGEN_DMG HDM(9)
#define DC_BP 8
#define DC_BT 10000
diff --git a/ui/generate-infopanes.sh b/ui/generate-infopanes.sh
new file mode 100755
index 00000000..d6171992
--- /dev/null
+++ b/ui/generate-infopanes.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+gcc -E infopanes.def.h | grep "^[^#].*" > infopanes.def
diff --git a/ui/infopanes.def.h b/ui/infopanes.def.h
new file mode 100644
index 00000000..d7e6610f
--- /dev/null
+++ b/ui/infopanes.def.h
@@ -0,0 +1,417 @@
+#include "/home/tma/tremulous/src/game/tremulous.h"
+
+#define CREDITS(X) text "Credits: " text X
+#define HUMAN_BCOST(X) text "Power: " text X
+#define ALIEN_BCOST(X) text "Sentience: " text X
+
+//team menu
+
+{
+ name alienteam
+ text "The Alien Team\n\n"
+ text "The Aliens' strengths are in movement "
+ text "and the ability to quickly construct new bases quickly. They possess a "
+ text "range of abilities including basic melee attacks, movement-"
+ text "crippling poisons and more."
+ align left
+}
+
+{
+ name humanteam
+ text "The Human Team\n\n"
+ text "The humans are the masters of technology. Although their bases take "
+ text "long to construct, their automated defense ensures they stay built. "
+ text "A wide range of upgrades and weapons are available to the humans, each "
+ text "contributing to eradicate the alien threat."
+ align left
+}
+
+{
+ name spectateteam
+ text "Watch the game without playing."
+}
+
+{
+ name autoteam
+ text "Join the team with the least players."
+}
+
+
+//human items
+
+{
+ name rifleitem
+ text "Rifle\n\n"
+ text "Basic weapon. Cased projectile weapon, with a slow clip based "
+ text "reload system.\n\n"
+ text "Credits: Free"
+}
+
+{
+ name ckititem
+ text "Construction kit\n\n"
+ text "Used for building all basic structures. This includes "
+ text "spawns, power and basic defense.\n\n"
+ text "Credits: Free"
+}
+
+{
+ name ackititem
+ text "Advanced Construction kit\n\n"
+ text "Used for building advanced structures. This includes "
+ text "combat computers and advanced defense.\n\n"
+ text "Credits: Free"
+}
+
+{
+ name shotgunitem
+ text "Shotgun\n\n"
+ text "Close range weapon that is useful against larger foes. "
+ text "It has a slow repeat rate, but can be devastatingly "
+ text "effective.\n\n"
+ CREDITS( SHOTGUN_PRICE )
+}
+
+{
+ name chaingunitem
+ text "Chain Gun\n\n"
+ text "Belt drive, cased projectile weapon. It has a high "
+ text "repeat rate but a wide firing angle and is therefore relatively "
+ text "inaccurate.\n\n"
+ CREDITS( CHAINGUN_PRICE )
+}
+
+{
+ name flameritem
+ text "Flamethrower\n\n"
+ text "Sprays fire at its target. It is powered by compressed "
+ text "gas. The relatively low rate of fire means this weapon is most "
+ text "effective against static targets.\n\n"
+ CREDITS( FLAMER_PRICE )
+}
+
+{
+ name mdriveritem
+ text "Mass Driver\n\n"
+ text "A portable particle accelerator which causes minor "
+ text "nuclear reactions at the point of impact. It has a very large "
+ text "payload, but fires slowly.\n\n"
+ CREDITS( MDRIVER_PRICE )
+}
+
+{
+ name prifleitem
+ text "Pulse Rifle\n\n"
+ text "An energy weapon that fires pulses of concentrated energy at a fast "
+ text "rate. It requires re-energising every 50 pulses.\n\n"
+ CREDITS( PRIFLE_PRICE )
+}
+
+{
+ name lcannonitem
+ text "Lucifer Cannon\n\n"
+ text "Similar to the pulse rifle, but more powerful. "
+ text "Additionally, it has a secondary attack where energy can be charged "
+ text "up to shoot a devastating ball of energy.\n\n"
+ CREDITS( LCANNON_PRICE )
+}
+
+{
+ name lgunitem
+ text "Las Gun\n\n"
+ text "Slightly more powerful than the basic rifle, but "
+ text "instead of bullets it fires small packets of energy.\n\n"
+ CREDITS( LASGUN_PRICE )
+}
+
+{
+ name psawitem
+ text "Pain Saw\n\n"
+ text "Similar to a chainsaw, but instead of a chain "
+ text "it has an electric arc capable of dealing a great deal of damage at "
+ text "close range.\n\n"
+ CREDITS( PAINSAW_PRICE )
+}
+
+{
+ name grenitem
+ text "Grenade\n\n"
+ text "A small incendinary device ideal for damaging tightly packed "
+ text "alien structures. Has a five second timer.\n\n"
+ CREDITS( GRENADE_PRICE )
+}
+
+{
+ name larmouritem
+ text "Light Armour\n\n"
+ text "Protective armour that helps to defend against light alien melee "
+ text "attacks.\n\n"
+ CREDITS( LIGHTARMOUR_PRICE )
+}
+
+{
+ name helmetitem
+ text "Helmet\n\n"
+ text "In addition to protecting your head, the helmet provides a "
+ text "scanner indicating the presence of any non-human lifeforms in your "
+ text "immediate vicinity.\n\n"
+ CREDITS( HELMET_PRICE )
+}
+
+{
+ name battpackitem
+ text "Battery Pack\n\n"
+ text "Back-mounted battery pack that permits storage of one and a half "
+ text "times the normal energy capacity for energy weapons.\n\n"
+ CREDITS( BATTPACK_PRICE )
+}
+
+{
+ name jetpackitem
+ text "Jet Pack\n\n"
+ text "Back-mounted jet pack that enables the user to fly to remote "
+ text "locations. It is very useful against alien spawns in hard to reach "
+ text "spots.\n\n"
+ CREDITS( JETPACK_PRICE )
+}
+
+{
+ name bsuititem
+ text "Battle Suit\n\n"
+ text "A full body armour that is highly effective at repelling alien attacks. "
+ text "It allows the user to enter hostile situations with a greater degree "
+ text "of confidence.\n\n"
+ CREDITS( BSUIT_PRICE )
+}
+
+{
+ name ammoitem
+ text "Ammunition\n\n"
+ text "Ammunition for the currently held weapon.\n\n"
+ text "Credits: Free"
+}
+
+
+//human structures
+
+{
+ name telenodebuild
+ text "Telenode\n\n"
+ text "The most basic human structure. It provides a means for "
+ text "humans to enter the battle arena. Without any of these the humans "
+ text "cannot spawn and defeat is imminent.\n\n"
+ HUMAN_BCOST( HSPAWN_BP )
+}
+
+{
+ name mgturretbuild
+ text "Machine Gun Turret\n\n"
+ text "Automated base defense that is effective against fast moving targets, but "
+ text "does not cause much damage on its own and should "
+ text "always be backed up by physical support.\n\n"
+ HUMAN_BCOST( MGTURRET_BP )
+}
+
+{
+ name armbuild
+ text "Armoury\n\n"
+ text "An essential part of the human base, providing a means "
+ text "to upgrade the basic human. A range of upgrades and weapons are "
+ text "available from the armoury, each with a price.\n\n"
+ HUMAN_BCOST( ARMOURY_BP )
+}
+
+{
+ name medistatbuild
+ text "Medistation\n\n"
+ text "A structure providing an automated healing energy that restores "
+ text "the health of any human that stands inside it. It may only be used "
+ text "by one person at a time.\n\n"
+ HUMAN_BCOST( MEDISTAT_BP )
+}
+
+{
+ name reactorbuild
+ text "Reactor\n\n"
+ text "All structures except the telenode rely on a reactor to operate."
+ text "The reactor provides power for all the human structures either "
+ text "directly or via repeaters. There can only be a single reactor.\n\n"
+}
+
+{
+ name dccbuild
+ text "Defense Computer\n\n"
+ text "A structure coordinating the action of base defense so that "
+ text "defense is distributed evenly among the enemy. "
+ text "This structure is required for building the Tesla Generator.\n\n"
+ HUMAN_BCOST( DC_BP )
+}
+
+{
+ name teslabuild
+ text "Tesla Generator\n\n"
+ text "A structure equipped with a strong electrical attack that always "
+ text "hits its target. It is useful against larger aliens "
+ text "and for consolidating basic defense.\n\n"
+ HUMAN_BCOST( TESLAGEN_BP )
+}
+
+{
+ name repeaterbuild
+ text "Repeater\n\n"
+ text "A power distributor that transmits power from the reactor "
+ text "to remote locations, so that bases may be built far from the reactor.\n\n"
+}
+
+//alien structures
+
+{
+ name eggpodbuild
+ text "Egg\n\n"
+ text "The most basic alien structure. It allows aliens to spawn "
+ text "and protect the Overmind. Without any of these, the Overmind is left "
+ text "nearly defenseless and defeat is imminent.\n\n"
+ ALIEN_BCOST( ASPAWN_BP )
+}
+
+{
+ name overmindbuild
+ text "Overmind\n\n"
+ text "A collective consciousness that controls all the "
+ text "alien structures in its vicinity. It must be protected at all costs, "
+ text "since its death will render alien structures defenseless."
+}
+
+{
+ name barricadebuild
+ text "Barricade\n\n"
+ text "Used to obstruct corridors and doorways, "
+ text "hindering humans from threatening the spawns and Overmind.\n\n"
+ ALIEN_BCOST( BARRICADE_BP )
+}
+
+{
+ name acid_tubebuild
+ text "Acid Tube\n\n"
+ text "Ejects lethal poisonous "
+ text "acid at an approaching human. These are highly effective when used in "
+ text "conjunction with a trapper to hold the victim in place.\n\n"
+ ALIEN_BCOST( ACIDTUBE_BP )
+}
+
+{
+ name hivebuild
+ text "Hive\n\n"
+ text "Houses millions of tiny "
+ text "insectoid aliens. When a human approaches this structure, the "
+ text "insectoids attack.\n\n"
+ ALIEN_BCOST( HIVE_BP )
+}
+
+{
+ name trapperbuild
+ text "Trapper\n\n"
+ text "Fires a blob of adhesive spit at any non-alien in its "
+ text "line of sight. This hinders their movement, making them an easy target "
+ text "for other defensive structures or aliens.\n\n"
+ ALIEN_BCOST( TRAPPER_BP )
+}
+
+{
+ name boosterbuild
+ text "Booster\n\n"
+ text "Provides any alien with a poison ability on all its "
+ text "attacks. In addition to the default attack damage, the victim loses "
+ text "health over time unless they heal themselves with a medkit."
+ text "The booster also increases the rate of health regeneration for "
+ text "any nearby aliens.\n\n"
+ ALIEN_BCOST( BOOSTER_BP )
+}
+
+{
+ name hovelbuild
+ text "Hovel\n\n"
+ text "An armoured shell used by the builder class to "
+ text "hide in, while the alien base is under attack. It may be entered or "
+ text "exited at any time."
+}
+
+//alien classes
+
+{
+ name builderclass
+ text "Granger\n\n"
+ text "Responsible for building and maintaining all "
+ text "the alien structures."
+}
+
+{
+ name builderupgclass
+ text "Advanced Granger\n\n"
+ text "Similar to the base Granger, "
+ text "except that in addition to being able to build structures it has a "
+ text "melee attack and the ability to crawl on walls."
+}
+
+{
+ name level0class
+ text "Dretch\n\n"
+ text "Has a lethal bite and the ability to crawl "
+ text "on walls and ceilings."
+}
+
+{
+ name level1class
+ text "Basilisk\n\n"
+ text "Able to crawl on walls and ceilings. "
+ text "Its melee attack is most effective when combined with the ability to "
+ text "grab its foe."
+}
+
+{
+ name level1upgclass
+ text "Advanced Basilisk\n\n"
+ text "In addition to the basic Basilisk abilities, the Advanced "
+ text "Basilisk sprays a poisonous gas which disorientaits any "
+ text "nearby humans."
+}
+
+{
+ name level2class
+ text "Marauder\n\n"
+ text "Has a melee attack and the ability to jump off walls."
+ text "This allows the Marauder to gather great speed in enclosed areas."
+}
+
+{
+ name level2upgclass
+ text "Advanced Marauder\n\n"
+ text "The Advanced Marauder has all the abilities of the base Marauder "
+ text "including an area effect electric shock attack."
+}
+
+{
+ name level3class
+ text "Dragoon\n\n"
+ text "Possesses a melee attack and the pounce ability, which may "
+ text "be used as an attack, or a means to reach a remote location inaccessible "
+ text "from the ground."
+}
+
+{
+ name level3upgclass
+ text "Advanced Dragoon\n\n"
+ text "In addition to the basic Dragoon abilities, the Dragoon Upgrade has "
+ text "3 barbs which may be used to attack humans from a distance."
+}
+
+{
+ name level4class
+ text "Tyrant\n\n"
+ text "Provides a healing aura in which nearby aliens regenerate health "
+ text "faster than usual. As well as a melee attack, this class can charge "
+ text "at enemy humans and structures, inflicting great damage."
+}
+
+// graphic <top|bottom|left|right> <center|some numerical offset> <shadername> <width> <height>
+// graphic left center "gfx/blah" 64 128