From c068f22329d5cc722622a2183bbb22eef2093df7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 11:16:07 +0200 Subject: initial import --- src/parsec/g_laser.cpp | 612 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 612 insertions(+) create mode 100644 src/parsec/g_laser.cpp (limited to 'src/parsec/g_laser.cpp') diff --git a/src/parsec/g_laser.cpp b/src/parsec/g_laser.cpp new file mode 100644 index 0000000..d56c188 --- /dev/null +++ b/src/parsec/g_laser.cpp @@ -0,0 +1,612 @@ +/* + * PARSEC - Laser Beam Weapon + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:36 $ + * + * Orginally written by: + * Copyright (c) Michael Woegerbauer 1999 + * Copyright (c) Markus Hadwiger 1999 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include +#include +#include +#include +#include + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "aud_defs.h" + +// drawing subsystem +#include "d_iter.h" + +// mathematics header +#include "utl_math.h" + +// model header +#include "utl_model.h" + +// local module header +#include "g_laser.h" + +// proprietary module headers +#include "con_info.h" +#include "e_callbk.h" +#include "e_supp.h" +#include "h_supp.h" +#include "obj_ctrl.h" +#include "obj_cust.h" +#include "obj_expl.h" + + + +// preset laserbeam type properties values ------------------------------------ +// +#define LASERBEAM_LIFETIME 300 +#define LASERBEAM_WIDTH 3.0f +#define LASERBEAM_DELTA_X 0.0f +#define LASERBEAM_DELTA_Y 3.0f +#define LASERBEAM_DELTA_Z 5.0f +#define LASERBEAM_RANGE 10000.0f +#define LASERBEAM_ENERGY_CONSUMPTION 1 +#define LASERBEAM_HITPOINTS_PER_FRAME 1 +#define LASERBEAM_RED 49 +#define LASERBEAM_GREEN 105 +#define LASERBEAM_BLUE 245 +#define LASERBEAM_ALPHA 255 +#define LASERBEAM_TEXNAME "laserb1.3df" +#define MAX_TEX_NAME 128 +#define MIN_LASERBEAM_ENERGY 10 + + +// message strings ------------------------------------------------------------ +// +static char out_of_range_str[] = "target out of range"; +static char laserbeam_downed_ship_str[] = "laserbeam downed ship"; +static char no_target_selected_str[] = "no target selected"; +static char low_energy_str[] = "low energy"; + + + +// laserbeam custom type structure -------------------------------------------- +// +struct LaserBeam : CustomObject { + + dword OwnerObjno; // needed for animation calculation + dword TargetObjno; + char texname[ MAX_TEX_NAME + 1 ]; + TextureMap *texmap; +// int lifetime; + int kill; + int energy_consumption; + int hitpoints_per_frame; + geomv_t width; // width of laserbeam + geomv_t half_width; // half of width of laserbeam + geomv_t delta_x; // relative to owner object + geomv_t delta_y; + geomv_t delta_z; + float range; + int red; + int green; + int blue; + int alpha; +}; + +//#define OFS_LIFETIME offsetof( LaserBeam, lifetime ) +#define OFS_WIDTH offsetof( LaserBeam, width ) +#define OFS_TEXNAME offsetof( LaserBeam, texname ) +#define OFS_DELTA_X offsetof( LaserBeam, delta_x ) +#define OFS_DELTA_Y offsetof( LaserBeam, delta_y ) +#define OFS_DELTA_Z offsetof( LaserBeam, delta_z ) +#define OFS_RANGE offsetof( LaserBeam, range ) +#define OFS_ENERGY offsetof( LaserBeam, energy_consumption ) +#define OFS_HITPOINTS_PER_FRAME offsetof( LaserBeam, hitpoints_per_frame ) +#define OFS_RED offsetof( LaserBeam, red ) +#define OFS_GREEN offsetof( LaserBeam, green ) +#define OFS_BLUE offsetof( LaserBeam, blue ) +#define OFS_ALPHA offsetof( LaserBeam, alpha ) + + +// list of console-accessible properties -------------------------------------- +// +PRIVATE +proplist_s LaserBeam_PropList[] = { + +// { "lifetime", OFS_LIFETIME, 0, 0xffff, PROPTYPE_INT }, + { "width", OFS_WIDTH, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, + { "texname", OFS_TEXNAME, 0, MAX_TEX_NAME, PROPTYPE_STRING }, + { "delta.x", OFS_DELTA_X, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, + { "delta.y", OFS_DELTA_Y, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, + { "delta.z", OFS_DELTA_Z, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, + { "range", OFS_RANGE, 0x0, 0x300000, PROPTYPE_FLOAT }, + { "energyconsumption", OFS_ENERGY, 0, 0xffff, PROPTYPE_INT }, + { "hitpoints", OFS_HITPOINTS_PER_FRAME, 0, 0xffff, PROPTYPE_INT }, + { "red", OFS_RED, 0, 0xff, PROPTYPE_INT }, + { "green", OFS_GREEN, 0, 0xff, PROPTYPE_INT }, + { "blue", OFS_BLUE, 0, 0xff, PROPTYPE_INT }, + { "alpha", OFS_ALPHA, 0, 0xff, PROPTYPE_INT }, + + { NULL, 0, 0, 0, 0 } +}; + + +// assigned type id for laserbeam type ---------------------------------------- +// +static dword laserbeam_type_id; + + +// type template for laserbeam ------------------------------------------------ +// +static LaserBeam *laserbeam_type_template = NULL; + + +// macro to set the properties of a itervertex -------------------------------- +// +#define SET_ITER_VTX( P_ITER_VTX, P_IN_VTX, P_OUT_VTX, P_VTX_U, P_VTX_V, VTX_RED, VTX_GREEN, VTX_BLUE, VTX_ALPHA ) \ + MtxVctMUL( SetIterXmatrx, (P_IN_VTX), (P_OUT_VTX) ); \ + (P_ITER_VTX)->X = (P_OUT_VTX)->X; \ + (P_ITER_VTX)->Y = (P_OUT_VTX)->Y; \ + (P_ITER_VTX)->Z = (P_OUT_VTX)->Z; \ + (P_ITER_VTX)->W = GEOMV_1; \ + (P_ITER_VTX)->U = *(P_VTX_U); \ + (P_ITER_VTX)->V = *(P_VTX_V); \ + (P_ITER_VTX)->R = VTX_RED; \ + (P_ITER_VTX)->G = VTX_GREEN; \ + (P_ITER_VTX)->B = VTX_BLUE; \ + (P_ITER_VTX)->A = VTX_ALPHA; + + +// draw laserbeam ------------------------------------------------------------- +// +PRIVATE +int LaserBeam_Draw( void* param ) +{ + ASSERT( param != NULL ); + LaserBeam *laserbeam = (LaserBeam *) param; + + Vertex3 temp; + Xmatrx SetIterXmatrx; + Vertex3 Pos, ViewPosOwner, ViewPosTarget, ViewPosOwnerScreen, ViewPosTargetScreen; + geomv_t u[ 4 ], v[ 4 ]; + Vertex3 objvtxs[ 4 ]; + Vector3 Diff; + + byte red, green, blue, alpha; + + if ( laserbeam->texmap == NULL ) { +// MSGOUT( "texture '%s' was not found", laserbeam->texname ); + return FALSE; + } + + GenObject *ownerpo = NULL; + if ( laserbeam->OwnerObjno == 0 ) + ownerpo = MyShip; + else + ownerpo = FetchHostObject( laserbeam->OwnerObjno ); + + if ( ownerpo == NULL ) + return FALSE; + + GenObject *targetpo = FetchHostObject( laserbeam->TargetObjno ); + if ( targetpo == NULL ) + return FALSE; + + // set vertex color + red = laserbeam->red; + green = laserbeam->green; + blue = laserbeam->blue; + alpha = laserbeam->alpha; + + // set texture coordinates + u[ 0 ] = GEOMV_0; + v[ 0 ] = GEOMV_0; + + u[ 1 ] = GEOMV_0; + v[ 1 ] = INT_TO_GEOMV( 1L << laserbeam->texmap->Height ); + + u[ 2 ] = INT_TO_GEOMV( 1L << laserbeam->texmap->Width ); + v[ 2 ] = INT_TO_GEOMV( 1L << laserbeam->texmap->Height ); + + u[ 3 ] = INT_TO_GEOMV( 1L << laserbeam->texmap->Width ); + v[ 3 ] = GEOMV_0; + + IterRectangle3 itrect; + + itrect.flags = ITERFLAG_Z_DIV_XYZ | ITERFLAG_Z_DIV_UVW | ITERFLAG_Z_TO_DEPTH; + itrect.itertype = iter_texrgba | iter_specularadd; + itrect.raststate = rast_zcompare | rast_texwrap | rast_chromakeyoff; + itrect.rastmask = rast_nomask; + itrect.texmap = laserbeam->texmap; + + // position of owner in worldspace + MtxMtxMUL( ViewCamera, ownerpo->ObjPosition, DestXmatrx ); + Pos.X = laserbeam->delta_x; + Pos.Y = laserbeam->delta_y; + Pos.Z = laserbeam->delta_z; + MtxVctMUL( DestXmatrx, &Pos, &ViewPosOwner ); + + // position of target in worldspace + FetchTVector( targetpo->ObjPosition, &Pos ); + MtxVctMUL( ViewCamera, &Pos, &ViewPosTarget ); + + //FIXME: + // ------------------------------------------------------- + // integer screen coordinates and geomv_t's are intermixed + // freely here. PROJECT_TO_SCREEN() also only initializes + // fields X and Y (of an SPoint!!), but it is used for + // a Vector3 and Z is used also! Visual C issues a warning + // for the access of the uninitialized Z field. + // has this ever worked??? + // ------------------------------------------------------- + + // get difference vector in screenspace + PROJECT_TO_SCREEN( ViewPosOwner, ViewPosOwnerScreen ); + PROJECT_TO_SCREEN( ViewPosTarget, ViewPosTargetScreen ); + Diff.X = ViewPosTargetScreen.X - ViewPosOwnerScreen.X; + Diff.Y = ViewPosTargetScreen.Y - ViewPosOwnerScreen.Y; + Diff.Z = GEOMV_0; //ViewPosTargetScreen.Z - ViewPosOwnerScreen.Z; + + // norm the x/y part of difference vector + float x = GEOMV_TO_FLOAT( Diff.X ); + float y = GEOMV_TO_FLOAT( Diff.Y ); + + float norm = sqrt( x*x + y*y ); + + Diff.X = FLOAT_TO_GEOMV( x / norm ); + Diff.Y = FLOAT_TO_GEOMV( y / norm ); + + // set rectangle vertices in viewspace + objvtxs[ 0 ].X = ViewPosOwner.X + GEOMV_MUL( Diff.Y, laserbeam->half_width ); + objvtxs[ 0 ].Y = ViewPosOwner.Y - GEOMV_MUL( Diff.X, laserbeam->half_width ); + objvtxs[ 0 ].Z = ViewPosOwner.Z; + objvtxs[ 1 ].X = ViewPosTarget.X + GEOMV_MUL( Diff.Y, laserbeam->half_width ); + objvtxs[ 1 ].Y = ViewPosTarget.Y - GEOMV_MUL( Diff.X, laserbeam->half_width ); + objvtxs[ 1 ].Z = ViewPosTarget.Z; + objvtxs[ 2 ].X = ViewPosTarget.X - GEOMV_MUL( Diff.Y, laserbeam->half_width ); + objvtxs[ 2 ].Y = ViewPosTarget.Y + GEOMV_MUL( Diff.X, laserbeam->half_width ); + objvtxs[ 2 ].Z = ViewPosTarget.Z; + objvtxs[ 3 ].X = ViewPosOwner.X - GEOMV_MUL( Diff.Y, laserbeam->half_width ); + objvtxs[ 3 ].Y = ViewPosOwner.Y + GEOMV_MUL( Diff.X, laserbeam->half_width ); + objvtxs[ 3 ].Z = ViewPosOwner.Z; + + // vertices already in viewspace + MakeIdMatrx( SetIterXmatrx ); + + SET_ITER_VTX( &itrect.Vtxs[ 0 ], &objvtxs[ 0 ], &temp, &u[ 0 ], &v[ 0 ], red, green, blue, alpha ); + SET_ITER_VTX( &itrect.Vtxs[ 1 ], &objvtxs[ 1 ], &temp, &u[ 1 ], &v[ 1 ], red, green, blue, alpha ); + SET_ITER_VTX( &itrect.Vtxs[ 2 ], &objvtxs[ 2 ], &temp, &u[ 2 ], &v[ 2 ], red, green, blue, alpha ); + SET_ITER_VTX( &itrect.Vtxs[ 3 ], &objvtxs[ 3 ], &temp, &u[ 3 ], &v[ 3 ], red, green, blue, alpha ); + + // clip and draw polygon + D_DrawIterRectangle3( &itrect, 0x3f ); + + return TRUE; +} + + +// callback type and flags ---------------------------------------------------- +// +static int callback_type = CBTYPE_DRAW_CUSTOM_ITER | CBFLAG_REMOVE; + + +// laserbeam animation callback ----------------------------------------------- +// +PRIVATE +int LaserBeamAnimate( CustomObject *base ) +{ + ASSERT( base != NULL ); + LaserBeam *laserbeam = (LaserBeam *) base; + + if ( laserbeam->kill == 1 ) { + // stop the laser beam sound + AUD_StopLaserBeam(); + + return FALSE; + } + + ShipObject *ownerpo = (ShipObject *) FetchHostObject( laserbeam->OwnerObjno ); + if ( laserbeam->OwnerObjno == 0 ) + ownerpo = MyShip; + ShipObject *targetpo = (ShipObject *) FetchHostObject( laserbeam->TargetObjno ); + + // check if target destroyed + if ( targetpo == NULL ) { + // stop the laser beam sound + AUD_StopLaserBeam(); + + ownerpo = MyShip; + ownerpo->WeaponsActive &= ~WPMASK_LASER_BEAM; + return FALSE; + } + + Vertex3 OwnerPos, TargetPos, Diff; + geomv_t range; + int cur_energy_consumption; + + // calculate range + FetchTVector( ownerpo->ObjPosition, &OwnerPos ); + FetchTVector( targetpo->ObjPosition, &TargetPos ); + + Diff.X = TargetPos.X - OwnerPos.X; + Diff.Y = TargetPos.Y - OwnerPos.Y; + Diff.Z = TargetPos.Z - OwnerPos.Z; + + range = GEOMV_TO_FLOAT( GEOMV_MUL( Diff.X, Diff.X ) + GEOMV_MUL( Diff.Y, Diff.Y ) + GEOMV_MUL( Diff.Z, Diff.Z ) ); + + // check range + if ( range > ( laserbeam->range * laserbeam->range ) ) { + // stop the laser beam sound + AUD_StopLaserBeam(); + + ownerpo->WeaponsActive &= ~WPMASK_LASER_BEAM; + ShowMessage( out_of_range_str ); + return FALSE; + } + + // check energy consumption + cur_energy_consumption = ( CurScreenRefFrames * laserbeam->energy_consumption ) / 10; + if ( ownerpo->CurEnergy < MIN_LASERBEAM_ENERGY + cur_energy_consumption ) { + // stop the laser beam sound + AUD_StopLaserBeam(); + + ownerpo->WeaponsActive &= ~WPMASK_LASER_BEAM; + ShowMessage( low_energy_str ); + AUD_LowEnergy(); + return FALSE; + } + else { + ownerpo->CurEnergy -= cur_energy_consumption; + } + + // damage if megashield not active + if ( targetpo->MegaShieldAbsorption <= 0 ) { + if ( targetpo == MyShip ) { + targetpo->CurDamage += ( CurScreenRefFrames * laserbeam->hitpoints_per_frame ) / 10; + + } else if ( !NetConnected && ( targetpo->ExplosionCount == 0 ) ) { + + targetpo->CurDamage += ( CurScreenRefFrames * laserbeam->hitpoints_per_frame ) / 10; + if ( targetpo->CurDamage > targetpo->MaxDamage ) { + // schedule explosion + LetShipExplode( targetpo ); + + // needed for explosions caused by particles +// shippo->DelayExplosion = 0; + + ownerpo->WeaponsActive &= ~WPMASK_LASER_BEAM; + ShowMessage( laserbeam_downed_ship_str ); + AUD_ShipDestroyed( targetpo ); + + // stop the laser beam sound + AUD_StopLaserBeam(); + + return FALSE; + } + } + } + + // register the drawing callback for drawing the laserbeam + CALLBACK_RegisterCallback( callback_type, LaserBeam_Draw, (void *) base ); + + return TRUE; +} + + +// ---------------------------------------------------------------------------- +// +PUBLIC +int KillLaserBeam( dword laserbeamobjno ) +{ + LaserBeam *laserbeam = (LaserBeam *) FetchObject( laserbeamobjno ); + if ( laserbeam == NULL) + return FALSE; + + laserbeam->kill = 1; + + return TRUE; +} + + +// ---------------------------------------------------------------------------- +// +PUBLIC +int CreateLaserBeam( GenObject *ownerpo, dword targetobjno, dword *laserbeamobjno ) +{ + ASSERT( ownerpo != NULL ); + + Vertex3 OwnerPos, TargetPos, Diff; + float range, cur_range; + + if ( targetobjno == TARGETID_NO_TARGET ) { + ShowMessage( no_target_selected_str ); + return FALSE; + } + GenObject *targetpo = FetchHostObject( targetobjno ); + if ( targetpo == NULL ) { + ShowMessage( no_target_selected_str ); + return FALSE; + } + + // calculate range + FetchTVector( ownerpo->ObjPosition, &OwnerPos ); + FetchTVector( targetpo->ObjPosition, &TargetPos ); + + Diff.X = TargetPos.X - OwnerPos.X; + Diff.Y = TargetPos.Y - OwnerPos.Y; + Diff.Z = TargetPos.Z - OwnerPos.Z; + + cur_range = GEOMV_TO_FLOAT( GEOMV_MUL( Diff.X, Diff.X ) + GEOMV_MUL( Diff.Y, Diff.Y ) + GEOMV_MUL( Diff.Z, Diff.Z ) ); + + if ( laserbeam_type_template != NULL ) + range = ( laserbeam_type_template->range * laserbeam_type_template->range ); + else + range = LASERBEAM_RANGE * LASERBEAM_RANGE; + + // check range + if ( cur_range > range ) { + ShowMessage( out_of_range_str ); + return FALSE; + } + + LaserBeam *laserbeam = (LaserBeam *) CreateVirtualObject( laserbeam_type_id ); + if ( laserbeam == NULL ) { + return FALSE; + } + laserbeam->OwnerObjno = ownerpo->HostObjNumber; + laserbeam->TargetObjno = targetobjno; + + *laserbeamobjno = laserbeam->ObjectNumber; + + // start the laser beam sound + AUD_StartLaserBeam(); + + return TRUE; +} + + +// init type fields with default values --------------------------------------- +// +PRIVATE +void LaserBeamInitDefaults( LaserBeam *laserbeam ) +{ + ASSERT( laserbeam != NULL ); + +// laserbeam->lifetime = LASERBEAM_LIFETIME; +// laserbeam->kill = 0; + laserbeam->width = FLOAT_TO_GEOMV( LASERBEAM_WIDTH ); + + strncpy( laserbeam->texname, LASERBEAM_TEXNAME, MAX_TEX_NAME ); + laserbeam->texname[ MAX_TEX_NAME ] = 0; + +// laserbeam->half_width = GEOMV_MUL( LASERBEAM_WIDTH, FLOAT_TO_GEOMV( 0.5 ) ); + laserbeam->delta_x = FLOAT_TO_GEOMV( LASERBEAM_DELTA_X ); + laserbeam->delta_y = FLOAT_TO_GEOMV( LASERBEAM_DELTA_Y ); + laserbeam->delta_z = FLOAT_TO_GEOMV( LASERBEAM_DELTA_Z ); + laserbeam->range = LASERBEAM_RANGE; + laserbeam->hitpoints_per_frame = LASERBEAM_HITPOINTS_PER_FRAME; + laserbeam->energy_consumption = LASERBEAM_ENERGY_CONSUMPTION; + laserbeam->red = LASERBEAM_RED; + laserbeam->green = LASERBEAM_GREEN; + laserbeam->blue = LASERBEAM_BLUE; + laserbeam->alpha = LASERBEAM_ALPHA; +} + + +// type fields init function for laserbeam trail --------------------------------- +// +PRIVATE +void LaserBeamInitType( CustomObject *base ) +{ + ASSERT( base != NULL ); + LaserBeam *laserbeam = (LaserBeam *) base; + + // init either from template or default values + if ( !OBJ_InitFromCustomTypeTemplate( laserbeam, laserbeam_type_template ) ) { + LaserBeamInitDefaults( laserbeam ); + } +} + + +// laserbeam constructor (class instantiation) -------------------------------- +// +PRIVATE +void LaserBeamInstantiate( CustomObject *base ) +{ + ASSERT( base != NULL ); + LaserBeam *laserbeam = (LaserBeam *) base; + + // get pointer to texture map + laserbeam->texmap = FetchTextureMap( laserbeam->texname ); + if ( laserbeam->texmap == NULL ) { + MSGOUT( "texture '%s' was not found", laserbeam->texname ); + return; + } + laserbeam->half_width = GEOMV_MUL( laserbeam->width, FLOAT_TO_GEOMV( 0.5 ) ); + laserbeam->kill = 0; +} + + +// laserbeam destructor (instance destruction) -------------------------------- +// +PRIVATE +void LaserBeamDestroy( CustomObject *base ) +{ + ASSERT( base != NULL ); + LaserBeam *laserbeam = (LaserBeam *) base; + + // ensure pending callbacks are destroyed to avoid + // calling them with invalid pointers + int numremoved = CALLBACK_DestroyCallback( callback_type, (void *) base ); + ASSERT( numremoved <= 1 ); +} + + +// register object type for laser beam ---------------------------------------- +// +PRIVATE +void LaserBeamRegisterCustomType() +{ + custom_type_info_s info; + memset( &info, 0, sizeof( info ) ); + + // always try to allocate template + laserbeam_type_template = (LaserBeam *) ALLOCMEM( sizeof( LaserBeam ) ); + if ( laserbeam_type_template != NULL ) { + memset( laserbeam_type_template, 0, sizeof( LaserBeam ) ); + LaserBeamInitDefaults( laserbeam_type_template ); + } + + info.type_name = "laserbeam"; + info.type_id = 0x00000000; + info.type_size = sizeof( LaserBeam ); + info.type_template = laserbeam_type_template; + info.type_flags = CUSTOM_TYPE_DEFAULT; + info.callback_init = LaserBeamInitType; + info.callback_instant = LaserBeamInstantiate; + info.callback_destroy = LaserBeamDestroy; + info.callback_animate = LaserBeamAnimate; + info.callback_collide = NULL; + info.callback_notify = NULL; + info.callback_persist = NULL; + + laserbeam_type_id = OBJ_RegisterCustomType( &info ); + CON_RegisterCustomType( info.type_id, LaserBeam_PropList ); +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( G_LASER ) +{ + // register type + LaserBeamRegisterCustomType(); +} + + + -- cgit v1.2.3