Descent3/manage/weaponpage.cpp
2024-04-17 00:25:04 +03:00

1760 lines
61 KiB
C++

/*
* $Logfile: /DescentIII/Main/manage/weaponpage.cpp $
* $Revision: 71 $
* $Date: 10/08/01 4:20p $
* $Author: Matt $
*
* For loading/saving of weapon types
*
* $Log: /DescentIII/Main/manage/weaponpage.cpp $
*
* 71 10/08/01 4:20p Matt
* Added system to check for errors when reading in add-on data.
*
* 69 9/06/01 10:32a Matt
* Added code to fix problem poping add-on pages when the original pages
* were in the extra.gam file.
*
* 68 10/26/99 4:26p Jeff
* handle extra.gam
*
* 67 10/26/99 3:31p Jeff
* handle extra.gam addon tablefile
*
* 66 9/18/99 8:49p Jeff
* fixed bug with addon pages that have dependencies on other pages in the
* addon tablefile
*
* 65 8/11/99 5:32p Jeff
* changes to fix addon tablefile support so it works correctly
*
* 64 7/22/99 4:38p Jason
* made EMD time out faster to help balance it out
*
* 63 4/14/99 1:34a Jeff
* fixed case mismatched #includes
*
* 62 4/12/99 12:49p Jeff
* added recoil_force to weapon's page
*
* 61 3/08/99 7:48p Jeff
* oem hack for napalm barrel
*
* 60 3/04/99 4:47p Jason
* temp fix (ie BAD HACK) for OEM table file woes
*
* 59 3/04/99 1:47p Jason
* fixed some manage problems
*
* 58 2/22/99 2:03p Jason
* added different damages for players and generics
*
* 57 1/13/99 7:05a Jeff
* put #ifdef around #include <windows.h>
*
* 56 12/29/98 4:30p Jason
* added add-on data functionality
*
* 55 11/06/98 12:35p Jason
* more speedups for manage system
*
* 54 11/05/98 7:55p Jason
* changes for new manage system
*
* 53 11/02/98 6:02p Jason
* made yes network updates much faster
*
* 52 10/15/98 6:46p Chris
* Added custom size for weapons
*
* 51 10/09/98 2:55p Jason
* fixed bug with my last rev
*
* 50 10/09/98 2:27p Jason
* reorganized table file system
*
* 49 10/08/98 10:03p Jason
* more filtered table file stuff
*
* 48 9/18/98 3:58p Jason
* change weapon reordering to do countermeasure weapons after generics
*
* 47 9/01/98 4:41p Matt
* Removed obsolete fields in the weapon structure
*
* 46 8/24/98 2:37p Jason
* made table file more efficient with regards to invalid names
*
* 45 8/06/98 1:00p Chris
* Added new homing flags
*
* 44 7/30/98 11:09a Jason
* added weapons that freeze and deform terrain
*
* 43 7/28/98 12:29p Jason
* chagned text string
*
* 42 7/01/98 12:11p Jason
* added countermeasures
*
* 41 6/26/98 5:26p Sean
* fixed some remaining weapons issues
*
* 40 6/22/98 6:26p Jason
* added gravity field effect for weapons
*
* 39 6/19/98 12:04p Jason
*
* 38 6/12/98 1:06p Jason
* added smart loading from local table file
*
* 37 5/25/98 8:36p Matt
* Added code to set different sizes for different weapon scorch marks.
* Also, don't leave scorch marks on lights.
*
* 36 5/25/98 6:39p Jason
* got icons working for weapons
*
* 35 5/25/98 4:16p Jason
* added more verbose mprintfs
*
* 34 5/22/98 12:34p Matt
* Added scorch mark/bullet hole system.
*
* 33 5/19/98 5:09a Chris
* Initial values are better
*
* 32 5/19/98 5:02a Chris
* More adjustments
*
* 31 5/19/98 4:42a Chris
* Added shockwave's -- enjoy. :)
*
* 30 5/13/98 6:35p Chris
* Fixed problems with hit die dot
*
* 29 5/07/98 1:41p Chris
* Added hit_death_dot
*
* 28 5/04/98 6:08p Jason
* sped up predictive pagefile loading
*
* 27 4/07/98 3:31p Jason
* got particle effects working with weapons
*
* 26 4/02/98 3:54p Jason
* first pass in getting polymodel paging to work
*
* 25 2/23/98 1:22p Jason
* made FindSpecific* read from the local drive, not the net drive - when
* starting the editor
*
* 24 2/16/98 11:42a Jason
* added better error checking for checking out files
*
* 23 2/11/98 3:52p Jason
*
* 22 2/11/98 2:04p Jason
* got spawning weapons working
*
* 21 2/05/98 6:29p Jason
* added user settable explode time/size
*
* 20 2/04/98 9:28p Jason
* added some new weapons effects
*
* 19 1/23/98 6:25p Jason
* Got spray weapons working
*
* 18 1/15/98 6:22p Jason
* added safety checks so the network won't copy over a primitive you have
* held locally
*
* 17 12/22/97 6:19p Chris
* Moved weapon battery firing sound off the projectile (weapon) and into
* the weapon battery.
*
* 16 12/11/97 11:55a Jason
* better error checking for dependant weapon pages
*
* 15 12/04/97 6:59p Jason
* fixed stupid off-by-one bug in cf_ReadString
*
* 14 12/04/97 12:15p Jason
* gave designers the ability to set their own weapon-to-wall hit vclips
*
* 13 12/03/97 11:54a Jason
* added designer-settable smoketrails
*
* 12 12/01/97 9:54a Chris
* Added support for concussive forces, generalized robot collisions to
* generic collisions
*
* 11 11/14/97 9:55p Jason
* took out size fix because we changed out minds
*
* 10 11/14/97 9:31p Jason
* automatically adjust size of weapon polymodels
*
* 9 10/30/97 5:00p Jason
* Made weapons use generic lighting code
*
* 8 10/20/97 4:46p Jason
* changes for explosions
*
* 7 10/15/97 5:20p Jason
* did a HUGE overhaul of the bitmap system
*
* 6 9/10/97 11:44a Chris
* Added major functionality for wb info
* FIXED a big remapping bug
*
* 5 9/03/97 3:54p Jason
* got objects to cast light
*
* 4 8/08/97 11:44a Jason
* got rid of annoying sound loading of a blank string
*
* 3 8/07/97 5:27p Chris
* Expanded the weapon system
*
* 2 8/06/97 4:34p Chris
* Expanded the weapons page
*
* 14 5/15/97 6:24p Mark
* fixed small bugs with sound loading invalid names
*
* 13 5/08/97 12:41p Jason
* made manage system work with device dependant path names
*
* 12 4/28/97 6:46p Jason
* made ships have multiple gun points
*
* 11 4/25/97 6:16p Jason
* added switcheroo function
*
* 10 4/25/97 2:18p Jason
* added fire_delay functionality
*
* 9 4/24/97 5:42p Jason
* got fireball vclips working
*
* 8 4/23/97 3:04p Jason
* added more stuff to weapon pages
*
* 7 4/16/97 11:50a Jason
* finally got weapons to fire
*
* 6 4/14/97 5:09p Jason
* fixed dumb bug with weapon flags
*
* 5 4/14/97 4:35p Jason
* added thrust field to page file
*
* 4 4/14/97 1:50p Jason
* first pass at getting weapons to fire
*
* 3 4/08/97 2:25a Chris
* Fixed a problem with uninitialized data. In addition it
* fixed a problem with the .used flag that would happen
* 1 out of 2^(sizeof(used_flag)) times (it would be zero
* when it was supposed to be non-zero)
*
* 2 3/31/97 4:35p Jason
* added weapon page functionality
*
* 1 3/31/97 3:40p Jason
* weaponpage implementation file
*
* $NoKeywords: $
*/
#if defined(WIN32)
#include <windows.h>
#endif
#include "CFILE.H"
#include "manage.h"
#include "weapon.h"
#include "weaponpage.h"
#include "mono.h"
#include "pserror.h"
#include "vclip.h"
#include "polymodel.h"
#include "soundpage.h"
#include "soundload.h"
#include "ddio.h"
#include "gametexture.h"
#include "texpage.h"
#include <string.h>
#include "sounds.h"
#include "genericpage.h"
#include "args.h"
// weaponpage commands that are read/written
// A command is followed by a byte count describing how many bytes
// are in the data for the command
#define WEAPONPAGE_COMMAND_NAME 1
#define WEAPONPAGE_COMMAND_END 2
#define WEAPONPAGE_COMMAND_HUD_IMAGE_NAME 3
#define WEAPONPAGE_COMMAND_VERSION 4
#define WEAPONPAGE_COMMAND_MASS 5
#define WEAPONPAGE_COMMAND_DRAG 6
#define WEAPONPAGE_COMMAND_FLAGS 7
#define WEAPONPAGE_COMMAND_FIRE_IMAGE_NAME 8
// #define WEAPONPAGE_COMMAND_THRUST 9 // not used anymore
#define WEAPONPAGE_COMMAND_FULL_THRUST 10
#define WEAPONPAGE_COMMAND_SOUND_NAME 11
#define WEAPONPAGE_COMMAND_AMMO_USAGE 12
#define WEAPONPAGE_COMMAND_ENERGY_USAGE 13
// #define WEAPONPAGE_COMMAND_EXPLODE_NAME 14 // exploding vclip name (not used anymore)
#define WEAPONPAGE_COMMAND_FIRE_DELAY 15
#define WEAPONPAGE_COMMAND_NUM_SHOTS 16
#define WEAPONPAGE_COMMAND_PHYS_FLAGS 17
#define WEAPONPAGE_COMMAND_SIZE 18
#define WEAPONPAGE_COMMAND_IMPACT_SIZE 19
#define WEAPONPAGE_COMMAND_FLASH_SIZE 20
#define WEAPONPAGE_COMMAND_ROT_DRAG 21
#define WEAPONPAGE_COMMAND_FULL_ROT_THRUST 22
#define WEAPONPAGE_COMMAND_MAX_BOUNCES 23
#define WEAPONPAGE_COMMAND_INIT_VELOCITY 24
#define WEAPONPAGE_COMMAND_INIT_ROT_VEL_X 25
#define WEAPONPAGE_COMMAND_INIT_ROT_VEL_Y 26
#define WEAPONPAGE_COMMAND_INIT_ROT_VEL_Z 27
#define WEAPONPAGE_COMMAND_LIFE_TIME 28
#define WEAPONPAGE_COMMAND_THRUST_TIME 29
#define WEAPONPAGE_COMMAND_WIGGLE_AMP 30
#define WEAPONPAGE_COMMAND_WIGGLE_FREQ 31
#define WEAPONPAGE_COMMAND_COEFF_RESTITUTION 32
#define WEAPONPAGE_COMMAND_LIGHT_CAST 33
#define WEAPONPAGE_COMMAND_DAMAGE 34
#define WEAPONPAGE_COMMAND_BETTER_LIGHT_CAST 35
#define WEAPONPAGE_COMMAND_IMPACT_TIME 36
#define WEAPONPAGE_COMMAND_SMOKE_NAME 37
#define WEAPONPAGE_COMMAND_EXPLOSION_NAME 38 // Wall hit vclip
#define WEAPONPAGE_COMMAND_ALPHA 39
#define WEAPONPAGE_COMMAND_EXPLODE_TIME 40
#define WEAPONPAGE_COMMAND_EXPLODE_SIZE 41
#define WEAPONPAGE_COMMAND_SPAWN_COUNT 42
#define WEAPONPAGE_COMMAND_SPAWN_NAME 43
#define WEAPONPAGE_COMMAND_FIRE_IMAGE_NULL 44
#define WEAPONPAGE_COMMAND_HUD_IMAGE_NULL 45
#define WEAPONPAGE_COMMAND_NAME_NULL 46
#define WEAPONPAGE_COMMAND_PARTICLE_NAME 47
#define WEAPONPAGE_COMMAND_PARTICLE_DATA 48
#define WEAPONPAGE_COMMAND_HIT_DIE_DOT 49
#define WEAPONPAGE_COMMAND_IMPACT_FORCE 50
#define WEAPONPAGE_COMMAND_IMPACT_DAMAGE 51
#define WEAPONPAGE_COMMAND_SCORCH_NAME 52
#define WEAPONPAGE_COMMAND_ICON_NAME 53
#define WEAPONPAGE_COMMAND_SCORCH_SIZE 54
#define WEAPONPAGE_COMMAND_ALT_SPAWN_NAME 55
#define WEAPONPAGE_COMMAND_ALT_CHANCE 56
#define WEAPONPAGE_COMMAND_GRAVITY_FIELD 57
#define WEAPONPAGE_COMMAND_ROBOT_SPAWN_NAME 58
#define WEAPONPAGE_COMMAND_TERRAIN_DAMAGE 59
#define WEAPONPAGE_COMMAND_HOMING_FOV 60
#define WEAPONPAGE_COMMAND_CUSTOM_SIZE 61
#define WEAPONPAGE_VERSION 8
void mng_WriteLightingChunk(light_info *lighting_info, CFILE *outfile);
void mng_ReadLightingChunk(light_info *lighting_info, CFILE *infile);
extern char *TablefileNameOverride;
// Sets a page structure to default values
void mng_InitWeaponPage(mngs_weapon_page *weaponpage) {
int i;
memset(weaponpage, 0, sizeof(mngs_weapon_page));
strcpy(weaponpage->hud_image_name, "");
strcpy(weaponpage->fire_image_name, "");
strcpy(weaponpage->explode_image_name, "");
strcpy(weaponpage->spawn_name, "");
strcpy(weaponpage->alternate_spawn_name, "");
strcpy(weaponpage->robot_spawn_name, "");
strcpy(weaponpage->smoke_image_name, "");
strcpy(weaponpage->scorch_image_name, "");
strcpy(weaponpage->icon_name, "");
strcpy(weaponpage->particle_name, "");
weaponpage->weapon_struct.alpha = 1.0;
weaponpage->weapon_struct.alternate_chance = 0;
weaponpage->weapon_struct.explode_time = 1.0;
weaponpage->weapon_struct.explode_size = 1.0;
weaponpage->weapon_struct.particle_count = 0;
weaponpage->weapon_struct.scorch_size = 1.0;
weaponpage->weapon_struct.terrain_damage_size = 0;
weaponpage->weapon_struct.terrain_damage_depth = 0;
weaponpage->weapon_struct.homing_fov = 0.4f;
weaponpage->weapon_struct.custom_size = 0.0f;
weaponpage->weapon_struct.recoil_force = 0.0f;
weaponpage->weapon_struct.phys_info.hit_die_dot = 1.0f;
for (i = 0; i < MAX_WEAPON_SOUNDS; i++)
strcpy(weaponpage->sound_name[i], "");
}
// Given an open file pointer and a weapon_page struct, writes that weapon page out
void mng_WriteWeaponPage(CFILE *outfile, mngs_weapon_page *weaponpage) {
int i;
ASSERT(outfile != NULL);
ASSERT(weaponpage != NULL);
cf_WriteByte(outfile, PAGETYPE_WEAPON);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_VERSION);
cf_WriteByte(outfile, 1);
cf_WriteByte(outfile, WEAPONPAGE_VERSION);
if ((strlen(weaponpage->weapon_struct.name)) < 2)
Int3(); // Get Jason, right now
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_NAME_NULL); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->weapon_struct.name)) + 1);
cf_WriteString(outfile, weaponpage->weapon_struct.name);
// Write out its image name
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_EXPLOSION_NAME); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->explode_image_name)) + 1);
cf_WriteString(outfile, weaponpage->explode_image_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_PARTICLE_NAME); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->particle_name)) + 1);
cf_WriteString(outfile, weaponpage->particle_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_PARTICLE_DATA);
cf_WriteByte(outfile, 9);
cf_WriteByte(outfile, weaponpage->weapon_struct.particle_count);
cf_WriteFloat(outfile, weaponpage->weapon_struct.particle_life);
cf_WriteFloat(outfile, weaponpage->weapon_struct.particle_size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SPAWN_NAME); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->spawn_name)) + 1);
cf_WriteString(outfile, weaponpage->spawn_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SPAWN_COUNT);
cf_WriteByte(outfile, 1);
cf_WriteByte(outfile, weaponpage->weapon_struct.spawn_count);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_ROBOT_SPAWN_NAME); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->robot_spawn_name)) + 1);
cf_WriteString(outfile, weaponpage->robot_spawn_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_ALT_SPAWN_NAME); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->alternate_spawn_name)) + 1);
cf_WriteString(outfile, weaponpage->alternate_spawn_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_ALT_CHANCE);
cf_WriteByte(outfile, 1);
cf_WriteByte(outfile, weaponpage->weapon_struct.alternate_chance);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_HUD_IMAGE_NULL); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->hud_image_name)) + 1);
cf_WriteString(outfile, weaponpage->hud_image_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_FIRE_IMAGE_NULL); // get ready to write out name
cf_WriteByte(outfile, (strlen(weaponpage->fire_image_name)) + 1);
cf_WriteString(outfile, weaponpage->fire_image_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_HOMING_FOV);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.homing_fov);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_CUSTOM_SIZE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.custom_size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_GRAVITY_FIELD);
cf_WriteByte(outfile, 8);
cf_WriteFloat(outfile, weaponpage->weapon_struct.gravity_time);
cf_WriteFloat(outfile, weaponpage->weapon_struct.gravity_size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_MASS);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.mass);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_DRAG);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.drag);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_FULL_THRUST);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.full_thrust);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_FLAGS);
cf_WriteByte(outfile, 4);
cf_WriteInt(outfile, weaponpage->weapon_struct.flags);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_PHYS_FLAGS);
cf_WriteByte(outfile, 4);
cf_WriteInt(outfile, weaponpage->weapon_struct.phys_info.flags);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SIZE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_TERRAIN_DAMAGE);
cf_WriteByte(outfile, 5);
cf_WriteFloat(outfile, weaponpage->weapon_struct.terrain_damage_size);
cf_WriteByte(outfile, weaponpage->weapon_struct.terrain_damage_depth);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_ALPHA);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.alpha);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_EXPLODE_TIME);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.explode_time);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_EXPLODE_SIZE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.explode_size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_DAMAGE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.player_damage);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_IMPACT_SIZE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_IMPACT_TIME);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_time);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_IMPACT_DAMAGE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_player_damage);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_IMPACT_FORCE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_force);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_ROT_DRAG);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.rotdrag);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_FULL_ROT_THRUST);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.full_rotthrust);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_MAX_BOUNCES);
cf_WriteByte(outfile, 4);
cf_WriteInt(outfile, weaponpage->weapon_struct.phys_info.num_bounces);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_INIT_VELOCITY);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.velocity.z);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_INIT_ROT_VEL_X);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.rotvel.x);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_INIT_ROT_VEL_Y);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.rotvel.y);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_INIT_ROT_VEL_Z);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.rotvel.z);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_LIFE_TIME);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.life_time);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_THRUST_TIME);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.thrust_time);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_WIGGLE_AMP);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.wiggle_amplitude);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_WIGGLE_FREQ);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.wiggles_per_sec);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_COEFF_RESTITUTION);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.coeff_restitution);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_HIT_DIE_DOT);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.phys_info.hit_die_dot);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_BETTER_LIGHT_CAST);
cf_WriteByte(outfile, (10 * 4) + 2);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.light_distance);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.red_light1);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.green_light1);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.blue_light1);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.time_interval);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.red_light2);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.green_light2);
cf_WriteFloat(outfile, weaponpage->weapon_struct.lighting_info.blue_light2);
cf_WriteInt(outfile, weaponpage->weapon_struct.lighting_info.flags);
cf_WriteInt(outfile, weaponpage->weapon_struct.lighting_info.timebits);
cf_WriteByte(outfile, weaponpage->weapon_struct.lighting_info.angle);
cf_WriteByte(outfile, weaponpage->weapon_struct.lighting_info.lighting_render_type);
// Write out its sounds name
for (i = 0; i < MAX_WEAPON_SOUNDS; i++) {
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SOUND_NAME);
cf_WriteByte(outfile, strlen(weaponpage->sound_name[i]) + 2); // 1 for sound index, 1 for null term
cf_WriteByte(outfile, i);
cf_WriteString(outfile, weaponpage->sound_name[i]);
}
// Write smoke name
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SMOKE_NAME);
cf_WriteByte(outfile, strlen(weaponpage->smoke_image_name) + 1); // 1 for null term
cf_WriteString(outfile, weaponpage->smoke_image_name);
// Write scorch name
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SCORCH_NAME);
cf_WriteByte(outfile, strlen(weaponpage->scorch_image_name) + 1); // 1 for null term
cf_WriteString(outfile, weaponpage->scorch_image_name);
// Write icon name
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_ICON_NAME);
cf_WriteByte(outfile, strlen(weaponpage->icon_name) + 1); // 1 for null term
cf_WriteString(outfile, weaponpage->icon_name);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_SCORCH_SIZE);
cf_WriteByte(outfile, 4);
cf_WriteFloat(outfile, weaponpage->weapon_struct.scorch_size);
cf_WriteByte(outfile, WEAPONPAGE_COMMAND_END); // we're all done
cf_WriteByte(outfile, 0);
}
// Given an open file pointer and a weapon_page struct, writes that weapon page out
void mng_WriteNewWeaponPage(CFILE *outfile, mngs_weapon_page *weaponpage) {
int i;
ASSERT(outfile != NULL);
ASSERT(weaponpage != NULL);
int offset = StartManagePage(outfile, PAGETYPE_WEAPON);
cf_WriteShort(outfile, WEAPONPAGE_VERSION);
if ((strlen(weaponpage->weapon_struct.name)) < 2)
Int3(); // Get Jason, right now
cf_WriteString(outfile, weaponpage->weapon_struct.name);
// Write hud image name
cf_WriteString(outfile, weaponpage->hud_image_name);
// Write fire image
cf_WriteString(outfile, weaponpage->fire_image_name);
// Write out particle data
cf_WriteString(outfile, weaponpage->particle_name);
cf_WriteByte(outfile, weaponpage->weapon_struct.particle_count);
cf_WriteFloat(outfile, weaponpage->weapon_struct.particle_life);
cf_WriteFloat(outfile, weaponpage->weapon_struct.particle_size);
// Write flags
cf_WriteInt(outfile, weaponpage->weapon_struct.flags);
// Write spawn data
cf_WriteString(outfile, weaponpage->spawn_name);
cf_WriteByte(outfile, weaponpage->weapon_struct.spawn_count);
cf_WriteString(outfile, weaponpage->robot_spawn_name);
cf_WriteString(outfile, weaponpage->alternate_spawn_name);
cf_WriteByte(outfile, weaponpage->weapon_struct.alternate_chance);
// Write gravity stuff
cf_WriteFloat(outfile, weaponpage->weapon_struct.gravity_time);
cf_WriteFloat(outfile, weaponpage->weapon_struct.gravity_size);
// Write misc stuff
cf_WriteFloat(outfile, weaponpage->weapon_struct.homing_fov);
cf_WriteFloat(outfile, weaponpage->weapon_struct.custom_size);
cf_WriteFloat(outfile, weaponpage->weapon_struct.size);
cf_WriteFloat(outfile, weaponpage->weapon_struct.thrust_time);
// Write physics stuff
mng_WritePhysicsChunk(&weaponpage->weapon_struct.phys_info, outfile);
// Write terrain damage
cf_WriteFloat(outfile, weaponpage->weapon_struct.terrain_damage_size);
cf_WriteByte(outfile, weaponpage->weapon_struct.terrain_damage_depth);
// Write alpha
cf_WriteFloat(outfile, weaponpage->weapon_struct.alpha);
// Write explosion data
cf_WriteString(outfile, weaponpage->explode_image_name);
cf_WriteFloat(outfile, weaponpage->weapon_struct.explode_time);
cf_WriteFloat(outfile, weaponpage->weapon_struct.explode_size);
// Write damage data
cf_WriteFloat(outfile, weaponpage->weapon_struct.player_damage);
cf_WriteFloat(outfile, weaponpage->weapon_struct.generic_damage);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_size);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_time);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_player_damage);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_generic_damage);
cf_WriteFloat(outfile, weaponpage->weapon_struct.impact_force);
// Write lifetime
cf_WriteFloat(outfile, weaponpage->weapon_struct.life_time);
// Write lighting
mng_WriteLightingChunk(&weaponpage->weapon_struct.lighting_info, outfile);
// Write recoil force
cf_WriteFloat(outfile, weaponpage->weapon_struct.recoil_force);
// Write out its sounds name
for (i = 0; i < MAX_WEAPON_SOUNDS; i++)
cf_WriteString(outfile, weaponpage->sound_name[i]);
// Write smoke name
cf_WriteString(outfile, weaponpage->smoke_image_name);
// Write scorch data
cf_WriteString(outfile, weaponpage->scorch_image_name);
cf_WriteFloat(outfile, weaponpage->weapon_struct.scorch_size);
// Write icon name
cf_WriteString(outfile, weaponpage->icon_name);
EndManagePage(outfile, offset);
}
#ifdef OEM
void DoOEMNapalmBarrelHack(mngs_weapon_page *weaponpage) {
if (!strcmp(weaponpage->weapon_struct.name, "NapalmBarrelPart2")) {
mprintf((0, "BASHING NAPALMBARRELPART2!!!!!!\n"));
weaponpage->weapon_struct.flags |= (WF_SATURATE | WF_NO_ROTATE | WF_CUSTOM_SIZE | WF_NAPALM);
weaponpage->weapon_struct.custom_size = 6.0f;
weaponpage->weapon_struct.phys_info.mass = 0.6f;
weaponpage->weapon_struct.phys_info.drag = 0.01f;
weaponpage->weapon_struct.phys_info.rotdrag = 0.001f;
weaponpage->weapon_struct.phys_info.velocity.x = 0;
weaponpage->weapon_struct.phys_info.velocity.y = 0;
weaponpage->weapon_struct.phys_info.velocity.z = 50.0f;
} else {
mprintf((0, "BASHING NAPALMBARREL!!!!!!\n"));
weaponpage->weapon_struct.flags |= (WF_INVISIBLE | WF_CUSTOM_SIZE | WF_NAPALM);
weaponpage->weapon_struct.custom_size = 1.0f;
weaponpage->weapon_struct.phys_info.flags |= PF_USES_PARENT_VELOCITY;
weaponpage->weapon_struct.phys_info.velocity.x = 0;
weaponpage->weapon_struct.phys_info.velocity.y = 0;
weaponpage->weapon_struct.phys_info.velocity.z = 110.0f;
}
}
#endif
// Given an open file pointer and a weapon_page struct, reads a weapon page
int mng_ReadNewWeaponPage(CFILE *infile, mngs_weapon_page *weaponpage) {
int i;
mng_InitWeaponPage(weaponpage);
int version = cf_ReadShort(infile);
cf_ReadString(weaponpage->weapon_struct.name, PAGENAME_LEN, infile);
// Read hud image name
cf_ReadString(weaponpage->hud_image_name, PAGENAME_LEN, infile);
// Read fire image
cf_ReadString(weaponpage->fire_image_name, PAGENAME_LEN, infile);
// Read particle data
cf_ReadString(weaponpage->particle_name, PAGENAME_LEN, infile);
weaponpage->weapon_struct.particle_count = cf_ReadByte(infile);
weaponpage->weapon_struct.particle_life = cf_ReadFloat(infile);
weaponpage->weapon_struct.particle_size = cf_ReadFloat(infile);
// Read flags
weaponpage->weapon_struct.flags = cf_ReadInt(infile);
// Read spawn data
cf_ReadString(weaponpage->spawn_name, PAGENAME_LEN, infile);
weaponpage->weapon_struct.spawn_count = cf_ReadByte(infile);
cf_ReadString(weaponpage->robot_spawn_name, PAGENAME_LEN, infile);
cf_ReadString(weaponpage->alternate_spawn_name, PAGENAME_LEN, infile);
weaponpage->weapon_struct.alternate_chance = cf_ReadByte(infile);
// Read gravity stuff
weaponpage->weapon_struct.gravity_time = cf_ReadFloat(infile);
weaponpage->weapon_struct.gravity_size = cf_ReadFloat(infile);
// Read size and homing data
weaponpage->weapon_struct.homing_fov = cf_ReadFloat(infile);
weaponpage->weapon_struct.custom_size = cf_ReadFloat(infile);
weaponpage->weapon_struct.size = cf_ReadFloat(infile);
weaponpage->weapon_struct.thrust_time = cf_ReadFloat(infile);
// Read physics info
mng_ReadPhysicsChunk(&weaponpage->weapon_struct.phys_info, infile);
// Read terrain damage
weaponpage->weapon_struct.terrain_damage_size = cf_ReadFloat(infile);
weaponpage->weapon_struct.terrain_damage_depth = cf_ReadByte(infile);
// Read alpha
weaponpage->weapon_struct.alpha = cf_ReadFloat(infile);
// Read explosion data
cf_ReadString(weaponpage->explode_image_name, PAGENAME_LEN, infile);
weaponpage->weapon_struct.explode_time = cf_ReadFloat(infile);
weaponpage->weapon_struct.explode_size = cf_ReadFloat(infile);
// Read damage data
weaponpage->weapon_struct.player_damage = cf_ReadFloat(infile);
if (version >= 7)
weaponpage->weapon_struct.generic_damage = cf_ReadFloat(infile);
else
weaponpage->weapon_struct.generic_damage = weaponpage->weapon_struct.player_damage;
weaponpage->weapon_struct.impact_size = cf_ReadFloat(infile);
weaponpage->weapon_struct.impact_time = cf_ReadFloat(infile);
weaponpage->weapon_struct.impact_player_damage = cf_ReadFloat(infile);
if (version >= 7)
weaponpage->weapon_struct.impact_generic_damage = cf_ReadFloat(infile);
else
weaponpage->weapon_struct.impact_generic_damage = weaponpage->weapon_struct.impact_player_damage;
weaponpage->weapon_struct.impact_force = cf_ReadFloat(infile);
// Read lifetime
weaponpage->weapon_struct.life_time = cf_ReadFloat(infile);
// read lighting
mng_ReadLightingChunk(&weaponpage->weapon_struct.lighting_info, infile);
// read recoil force
if (version >= 8)
weaponpage->weapon_struct.recoil_force = cf_ReadFloat(infile);
else
weaponpage->weapon_struct.recoil_force = 0.0f;
// Read its sound names
for (i = 0; i < MAX_WEAPON_SOUNDS; i++)
cf_ReadString(weaponpage->sound_name[i], PAGENAME_LEN, infile);
// Read smoke name
cf_ReadString(weaponpage->smoke_image_name, PAGENAME_LEN, infile);
// Read scorch data
cf_ReadString(weaponpage->scorch_image_name, PAGENAME_LEN, infile);
weaponpage->weapon_struct.scorch_size = cf_ReadFloat(infile);
// Read icon name
cf_ReadString(weaponpage->icon_name, PAGENAME_LEN, infile);
weaponpage->weapon_struct.used = 1;
#ifdef OEM
if (!strcmp(weaponpage->weapon_struct.name, "NapalmBarrelPart2") ||
!strcmp(weaponpage->weapon_struct.name, "NapalmBarrel")) {
// Do OEM hack
DoOEMNapalmBarrelHack(weaponpage);
}
#endif
if (!stricmp(weaponpage->weapon_struct.name, "EMDBlob")) {
weaponpage->weapon_struct.life_time = 1.7f;
}
return 1; // successfully read
}
// Reads a weapon page from an open file. Returns 0 on error.
int mng_ReadWeaponPage(CFILE *infile, mngs_weapon_page *weaponpage) {
int done = 0;
char command;
ubyte len;
int i, t;
int version = 0;
if (!Old_table_method)
return mng_ReadNewWeaponPage(infile, weaponpage);
ASSERT(infile != NULL);
mng_InitWeaponPage(weaponpage);
while (!done) {
// Read in command byte then read in the length of that commands data
command = cf_ReadByte(infile);
len = cf_ReadByte(infile);
switch (command) {
case WEAPONPAGE_COMMAND_END:
done = 1;
break;
case WEAPONPAGE_COMMAND_VERSION:
version = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_HUD_IMAGE_NAME: // the name of the weapon model
for (i = 0; i < PAGENAME_LEN; i++)
weaponpage->hud_image_name[i] = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_FIRE_IMAGE_NAME: // the name of the weapon model
for (i = 0; i < PAGENAME_LEN; i++)
weaponpage->fire_image_name[i] = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_NAME_NULL:
cf_ReadString(weaponpage->weapon_struct.name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_FIRE_IMAGE_NULL:
cf_ReadString(weaponpage->fire_image_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_HUD_IMAGE_NULL:
cf_ReadString(weaponpage->hud_image_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_SPAWN_NAME:
cf_ReadString(weaponpage->spawn_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_SPAWN_COUNT:
weaponpage->weapon_struct.spawn_count = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_ALT_SPAWN_NAME:
cf_ReadString(weaponpage->alternate_spawn_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_ROBOT_SPAWN_NAME:
cf_ReadString(weaponpage->robot_spawn_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_ALT_CHANCE:
weaponpage->weapon_struct.alternate_chance = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_NAME:
for (i = 0; i < PAGENAME_LEN; i++)
weaponpage->weapon_struct.name[i] = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_EXPLOSION_NAME:
cf_ReadString(weaponpage->explode_image_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_PARTICLE_NAME:
cf_ReadString(weaponpage->particle_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_FLAGS:
weaponpage->weapon_struct.flags = cf_ReadInt(infile);
break;
case WEAPONPAGE_COMMAND_MASS:
weaponpage->weapon_struct.phys_info.mass = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_HOMING_FOV:
weaponpage->weapon_struct.homing_fov = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_CUSTOM_SIZE:
weaponpage->weapon_struct.custom_size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_GRAVITY_FIELD:
weaponpage->weapon_struct.gravity_time = cf_ReadFloat(infile);
weaponpage->weapon_struct.gravity_size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_FULL_THRUST:
weaponpage->weapon_struct.phys_info.full_thrust = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_DRAG:
weaponpage->weapon_struct.phys_info.drag = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_TERRAIN_DAMAGE:
weaponpage->weapon_struct.terrain_damage_size = cf_ReadFloat(infile);
weaponpage->weapon_struct.terrain_damage_depth = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_SOUND_NAME:
t = cf_ReadByte(infile);
cf_ReadString(weaponpage->sound_name[t], len, infile);
break;
case WEAPONPAGE_COMMAND_PHYS_FLAGS:
weaponpage->weapon_struct.phys_info.flags = cf_ReadInt(infile);
break;
case WEAPONPAGE_COMMAND_SIZE:
weaponpage->weapon_struct.size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_ALPHA:
weaponpage->weapon_struct.alpha = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_EXPLODE_TIME:
weaponpage->weapon_struct.explode_time = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_EXPLODE_SIZE:
weaponpage->weapon_struct.explode_size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_PARTICLE_DATA:
weaponpage->weapon_struct.particle_count = cf_ReadByte(infile);
weaponpage->weapon_struct.particle_life = cf_ReadFloat(infile);
weaponpage->weapon_struct.particle_size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_DAMAGE:
weaponpage->weapon_struct.player_damage = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_IMPACT_SIZE:
weaponpage->weapon_struct.impact_size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_IMPACT_TIME:
weaponpage->weapon_struct.impact_time = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_IMPACT_DAMAGE:
weaponpage->weapon_struct.impact_player_damage = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_IMPACT_FORCE:
weaponpage->weapon_struct.impact_force = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_ROT_DRAG:
weaponpage->weapon_struct.phys_info.rotdrag = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_FULL_ROT_THRUST:
weaponpage->weapon_struct.phys_info.full_rotthrust = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_MAX_BOUNCES:
weaponpage->weapon_struct.phys_info.num_bounces = cf_ReadInt(infile);
break;
case WEAPONPAGE_COMMAND_INIT_VELOCITY:
weaponpage->weapon_struct.phys_info.velocity.z = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_INIT_ROT_VEL_X:
weaponpage->weapon_struct.phys_info.rotvel.x = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_INIT_ROT_VEL_Y:
weaponpage->weapon_struct.phys_info.rotvel.y = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_INIT_ROT_VEL_Z:
weaponpage->weapon_struct.phys_info.rotvel.z = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_LIFE_TIME:
weaponpage->weapon_struct.life_time = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_THRUST_TIME:
weaponpage->weapon_struct.thrust_time = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_WIGGLE_AMP:
weaponpage->weapon_struct.phys_info.wiggle_amplitude = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_WIGGLE_FREQ:
weaponpage->weapon_struct.phys_info.wiggles_per_sec = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_COEFF_RESTITUTION:
weaponpage->weapon_struct.phys_info.coeff_restitution = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_HIT_DIE_DOT:
weaponpage->weapon_struct.phys_info.hit_die_dot = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_LIGHT_CAST:
weaponpage->weapon_struct.lighting_info.light_distance = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.red_light1 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.green_light1 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.blue_light1 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.timebits = 0xFFFFFFFF;
break;
case WEAPONPAGE_COMMAND_BETTER_LIGHT_CAST:
weaponpage->weapon_struct.lighting_info.light_distance = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.red_light1 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.green_light1 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.blue_light1 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.time_interval = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.red_light2 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.green_light2 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.blue_light2 = cf_ReadFloat(infile);
weaponpage->weapon_struct.lighting_info.flags = cf_ReadInt(infile);
weaponpage->weapon_struct.lighting_info.timebits = cf_ReadInt(infile);
weaponpage->weapon_struct.lighting_info.angle = cf_ReadByte(infile);
weaponpage->weapon_struct.lighting_info.lighting_render_type = cf_ReadByte(infile);
break;
case WEAPONPAGE_COMMAND_SMOKE_NAME:
cf_ReadString(weaponpage->smoke_image_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_SCORCH_NAME:
cf_ReadString(weaponpage->scorch_image_name, len + 1, infile);
break;
case WEAPONPAGE_COMMAND_SCORCH_SIZE:
weaponpage->weapon_struct.scorch_size = cf_ReadFloat(infile);
break;
case WEAPONPAGE_COMMAND_ICON_NAME:
cf_ReadString(weaponpage->icon_name, len + 1, infile);
break;
default:
// Ignore the ones we don't know
for (i = 0; i < len; i++)
cf_ReadByte(infile);
break;
}
}
if (version < 2) {
weaponpage->weapon_struct.impact_player_damage = weaponpage->weapon_struct.player_damage;
weaponpage->weapon_struct.impact_force = weaponpage->weapon_struct.player_damage * 100.0f;
if (weaponpage->weapon_struct.impact_size > 0.0) {
weaponpage->weapon_struct.impact_time = weaponpage->weapon_struct.explode_time;
weaponpage->weapon_struct.impact_size = weaponpage->weapon_struct.explode_size * 1.5;
}
}
// Clear out old strings
if (!strnicmp("INVALID", weaponpage->explode_image_name, 7))
strcpy(weaponpage->explode_image_name, "");
if (!strnicmp("INVALID", weaponpage->smoke_image_name, 7))
strcpy(weaponpage->smoke_image_name, "");
if (!strnicmp("INVALID", weaponpage->scorch_image_name, 7))
strcpy(weaponpage->scorch_image_name, "");
if (!strnicmp("INVALID", weaponpage->icon_name, 7))
strcpy(weaponpage->icon_name, "");
if (!strnicmp("INVALID", weaponpage->spawn_name, 7))
strcpy(weaponpage->spawn_name, "");
if (!strnicmp("INVALID", weaponpage->alternate_spawn_name, 7))
strcpy(weaponpage->alternate_spawn_name, "");
if (!strnicmp("INVALID", weaponpage->robot_spawn_name, 7))
strcpy(weaponpage->robot_spawn_name, "");
if (!strnicmp("INVALID", weaponpage->particle_name, 7))
strcpy(weaponpage->particle_name, "");
for (i = 0; i < MAX_WEAPON_SOUNDS; i++) {
if (!strnicmp("INVALID", weaponpage->sound_name[i], 7))
strcpy(weaponpage->sound_name[i], "");
}
// This is a valid new page
weaponpage->weapon_struct.used = 1;
return 1; // successfully read
}
// Reads in the weapon named "name" into weaponpage struct
// Returns 0 on error or couldn't find, else 1 if all is good
int mng_FindSpecificWeaponPage(char *name, mngs_weapon_page *weaponpage) {
CFILE *infile;
ubyte pagetype;
int done = 0, found = 0;
int first_try = 1;
char tablename[TABLE_NAME_LEN];
if (Loading_locals) {
infile = cfopen(LocalTableFilename, "rb");
} else if (Loading_addon_table != -1) {
infile = cfopen(AddOnDataTables[Loading_addon_table].AddOnTableFilename, "rb");
} else {
if (Network_up && Starting_editor) {
int farg = FindArg("-filter");
if (farg)
strcpy(tablename, GameArgs[farg + 1]);
else
ddio_MakePath(tablename, LocalTableDir, NET_TABLE, NULL);
infile = cfopen(tablename, "rb");
} else {
infile = NULL;
if (TablefileNameOverride) {
infile = cfopen(TablefileNameOverride, "rb");
}
if (!infile)
infile = cfopen(TableFilename, "rb");
}
}
if (!infile) {
mprintf((0, "Couldn't open table file to find weapon!\n"));
Int3();
return 0;
}
try_again:;
// Read in the entire page file until we find the page we want
while (!done) {
if (cfeof(infile)) {
done = 1;
continue;
}
pagetype = cf_ReadByte(infile);
int len = cf_ReadInt(infile);
// If not a weapon page, just read it in and ignore it
if (pagetype != PAGETYPE_WEAPON) {
cfseek(infile, len - 4, SEEK_CUR);
continue;
}
mng_ReadNewWeaponPage(infile, weaponpage);
if (!stricmp(name, weaponpage->weapon_struct.name)) {
// This is the page we want
found = 1;
done = 1;
}
}
cfclose(infile);
if (!found && first_try) {
done = first_try = 0;
infile = cfopen("extra.gam", "rb");
if (infile)
goto try_again;
}
return found; // successful!
}
// Reads in the weapon named "name" into weaponpage struct
// Returns 0 on error or couldn't find, else 1 if all is good
int mng_FindSpecificWeaponPage(char *name, mngs_weapon_page *weaponpage, int offset) {
CFILE *infile;
ubyte pagetype;
int done = 0, found = 0;
if (Loading_locals) {
infile = cfopen(LocalTableFilename, "rb");
} else if (Loading_addon_table != -1) {
infile = cfopen(AddOnDataTables[Loading_addon_table].AddOnTableFilename, "rb");
} else {
if (Network_up && Starting_editor) {
char tablename[TABLE_NAME_LEN];
int farg = FindArg("-filter");
if (farg)
strcpy(tablename, GameArgs[farg + 1]);
else
ddio_MakePath(tablename, LocalTableDir, NET_TABLE, NULL);
infile = cfopen(tablename, "rb");
} else {
infile = NULL;
if (TablefileNameOverride) {
infile = cfopen(TablefileNameOverride, "rb");
}
if (!infile)
infile = cfopen(TableFilename, "rb");
}
}
if (!infile) {
mprintf((0, "Couldn't open table file to find weapon!\n"));
Int3();
return 0;
}
if (offset)
cfseek(infile, offset, SEEK_SET);
// Read in the entire page file until we find the page we want
while (!done) {
if (cfeof(infile)) {
done = 1;
continue;
}
pagetype = cf_ReadByte(infile);
int len = cf_ReadInt(infile);
// If not a weapon page, just read it in and ignore it
if (pagetype != PAGETYPE_WEAPON) {
cfseek(infile, len - 4, SEEK_CUR);
continue;
}
mng_ReadNewWeaponPage(infile, weaponpage);
if (!stricmp(name, weaponpage->weapon_struct.name)) {
// This is the page we want
found = 1;
done = 1;
}
}
cfclose(infile);
return found; // successful!
}
char *Weapon_error = NULL, *Weapon_error_filename = NULL;
// First searches through the weapon index to see if the weapon is already
// loaded. If not, searches in the table file and loads it.
// Returns index of weapon found, -1 if not
int mng_GetGuaranteedWeaponPage(char *name, CFILE *infile) {
int i;
mngs_weapon_page weaponpage;
// See if its in memory
i = FindWeaponName(name);
if (i != -1)
return i;
// Not in memory. Load it from the table file. Start searching from the
// current spot in the open table file
int ret = mng_FindSpecificWeaponPage(name, &weaponpage, infile ? infile->position : 0);
if (!ret)
return -1;
// We've found it in the table file, now load it.
ret = mng_SetAndLoadWeapon(&weaponpage, infile);
// ASSERT (ret>=0);
if (ret < 0)
DataError("Error loading weapon <%s>: %s, file <%s>\n", weaponpage.weapon_struct.name, Weapon_error,
Weapon_error_filename);
if (Loading_addon_table != -1) {
// we're loading addon table pages, this will not overlay anything
mng_PushAddonPage(PAGETYPE_WEAPON, weaponpage.weapon_struct.name, 0);
}
return ret;
}
// Given a weapon page, allocs a weapon and calls AssignWeaponPageToWeapon to actually
// load models and values. Rturns weapon handle on success, -1 if fail
int mng_SetAndLoadWeapon(mngs_weapon_page *weaponpage, CFILE *infile) {
int n;
Weapon_error = Weapon_error_filename = "";
n = AllocWeapon();
if (n < 0) {
Weapon_error = "No free weapon slots";
return -1;
}
if (!mng_AssignWeaponPageToWeapon(weaponpage, n, infile))
return -1;
return n;
}
// Given a weaponpage and a weapon handle, attempts to make weapon n correspond to
// to the weaponpage.
// Returns 1 on success, 0 otherwise
int mng_AssignWeaponPageToWeapon(mngs_weapon_page *weaponpage, int n, CFILE *infile) {
weapon *weaponpointer = &Weapons[n];
int img_handle, i, sound_handle;
// copy our values
memcpy(weaponpointer, &weaponpage->weapon_struct, sizeof(weapon));
strcpy(weaponpointer->name, weaponpage->weapon_struct.name);
// First see if our image differs from the one on the net
// If it is, make a copy
// If its a release version, don't do any of this
#ifndef RELEASE
if (Network_up) {
char str[200];
char netstr[200];
ddio_MakePath(str, LocalManageGraphicsDir, weaponpage->hud_image_name, NULL);
ddio_MakePath(netstr, ManageGraphicsDir, weaponpage->hud_image_name, NULL);
UpdatePrimitive(str, netstr, weaponpage->hud_image_name, PAGETYPE_WEAPON, weaponpointer->name);
// Now copy the discharge image, depending on whether or not its a model
if ((weaponpage->weapon_struct.flags & WF_IMAGE_BITMAP) || (weaponpage->weapon_struct.flags & WF_IMAGE_VCLIP)) {
ddio_MakePath(str, LocalManageGraphicsDir, weaponpage->fire_image_name, NULL);
ddio_MakePath(netstr, ManageGraphicsDir, weaponpage->fire_image_name, NULL);
} else {
ddio_MakePath(str, LocalModelsDir, weaponpage->fire_image_name, NULL);
ddio_MakePath(netstr, NetModelsDir, weaponpage->fire_image_name, NULL);
}
UpdatePrimitive(str, netstr, weaponpage->fire_image_name, PAGETYPE_WEAPON, weaponpointer->name);
}
#endif
// Try and load our weapon model from the disk
if (weaponpointer->flags & WF_HUD_ANIMATED)
img_handle = AllocLoadVClip(weaponpage->hud_image_name, NOT_TEXTURE, 0);
else
img_handle = bm_AllocLoadFileBitmap(weaponpage->hud_image_name, 0);
if (img_handle < 0) {
mprintf((0, "Couldn't load bitmap '%s' in AssignWeaponPage...\n", weaponpage->hud_image_name));
weaponpointer->hud_image_handle = -1;
Weapon_error = "Can't load HUD image";
Weapon_error_filename = weaponpage->hud_image_name;
return 0;
} else
weaponpointer->hud_image_handle = img_handle;
if (weaponpointer->flags & WF_IMAGE_BITMAP)
img_handle = bm_AllocLoadFileBitmap(weaponpage->fire_image_name, 0);
else if (weaponpointer->flags & WF_IMAGE_VCLIP)
img_handle = AllocLoadVClip(weaponpage->fire_image_name, NOT_TEXTURE, 0);
else
img_handle = LoadPolyModel(weaponpage->fire_image_name, 1);
if (img_handle < 0) {
mprintf((0, "Couldn't load bitmap/model '%s' in AssignWeaponPage...\n", weaponpage->fire_image_name));
weaponpointer->fire_image_handle = -1;
Weapon_error = "Can't load fire image";
Weapon_error_filename = weaponpage->fire_image_name;
return 0;
} else {
weaponpointer->fire_image_handle = img_handle;
/*// Fix size
if (!(weaponpointer->flags & WF_IMAGE_BITMAP))
{
if (Poly_models[img_handle].new_style && Poly_models[img_handle].flags & PMF_TIMED)
{
weaponpointer->size=ComputeDefaultSize(img_handle);
}
}*/
}
if (stricmp(weaponpage->explode_image_name, "INVALID NAME") && weaponpage->explode_image_name[0] != 0) {
img_handle = mng_GetGuaranteedTexturePage(weaponpage->explode_image_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load bitmap/model '%s' in AssignWeaponPage...\n", weaponpage->explode_image_name));
weaponpointer->explode_image_handle = -1;
} else
weaponpointer->explode_image_handle = img_handle;
} else
weaponpointer->explode_image_handle = -1;
// Try to load particle texture
if (stricmp(weaponpage->particle_name, "INVALID NAME") && weaponpage->particle_name[0] != 0) {
img_handle = mng_GetGuaranteedTexturePage(weaponpage->particle_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load bitmap/model '%s' in AssignWeaponPage...\n", weaponpage->particle_name));
weaponpointer->particle_handle = -1;
} else
weaponpointer->particle_handle = img_handle;
} else
weaponpointer->particle_handle = -1;
// Try to load spawn weapons
if (stricmp(weaponpage->spawn_name, "INVALID NAME") && weaponpage->spawn_name[0] != 0) {
img_handle = mng_GetGuaranteedWeaponPage(weaponpage->spawn_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load spawn weapon '%s' in AssignWeaponPage...\n", weaponpage->spawn_name));
weaponpointer->spawn_handle = -1;
} else
weaponpointer->spawn_handle = img_handle;
} else
weaponpointer->spawn_handle = -1;
if (stricmp(weaponpage->alternate_spawn_name, "INVALID NAME") && weaponpage->alternate_spawn_name[0] != 0) {
img_handle = mng_GetGuaranteedWeaponPage(weaponpage->alternate_spawn_name, infile);
if (img_handle < 0) {
mprintf(
(0, "Couldn't load alternate spawn weapon '%s' in AssignWeaponPage...\n", weaponpage->alternate_spawn_name));
weaponpointer->alternate_spawn_handle = -1;
} else
weaponpointer->alternate_spawn_handle = img_handle;
} else
weaponpointer->alternate_spawn_handle = -1;
// Try to load robot spawn
if (stricmp(weaponpage->robot_spawn_name, "INVALID NAME") && weaponpage->robot_spawn_name[0] != 0) {
img_handle = mng_GetGuaranteedGenericPage(weaponpage->robot_spawn_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load robot spawn weapon '%s' in AssignWeaponPage...\n", weaponpage->robot_spawn_name));
weaponpointer->robot_spawn_handle = -1;
} else
weaponpointer->robot_spawn_handle = img_handle;
} else
weaponpointer->robot_spawn_handle = -1;
// Try to load smoke
if (stricmp(weaponpage->smoke_image_name, "INVALID NAME") && weaponpage->smoke_image_name[0] != 0) {
img_handle = mng_GetGuaranteedTexturePage(weaponpage->smoke_image_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load smoke trail file '%s' in AssignWeaponPage...\n", weaponpage->smoke_image_name));
weaponpointer->flags &= ~WF_SMOKE;
weaponpointer->smoke_handle = -1;
} else
weaponpointer->smoke_handle = img_handle;
} else {
weaponpointer->flags &= ~WF_SMOKE;
weaponpointer->smoke_handle = -1;
}
// Try to load scorch
if (stricmp(weaponpage->scorch_image_name, "INVALID NAME") && weaponpage->scorch_image_name[0] != 0) {
img_handle = mng_GetGuaranteedTexturePage(weaponpage->scorch_image_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load scorch file '%s' in AssignWeaponPage...\n", weaponpage->scorch_image_name));
weaponpointer->scorch_handle = -1;
} else
weaponpointer->scorch_handle = img_handle;
} else {
weaponpointer->scorch_handle = -1;
}
// Try to load icone
if (stricmp(weaponpage->icon_name, "INVALID NAME") && weaponpage->icon_name[0] != 0) {
img_handle = mng_GetGuaranteedTexturePage(weaponpage->icon_name, infile);
if (img_handle < 0) {
mprintf((0, "Couldn't load icon file '%s' in AssignWeaponPage...\n", weaponpage->icon_name));
weaponpointer->icon_handle = -1;
} else
weaponpointer->icon_handle = img_handle;
} else {
weaponpointer->icon_handle = -1;
}
// Try and load the various sounds
for (i = 0; i < MAX_WEAPON_SOUNDS; i++) {
if (stricmp(weaponpage->sound_name[i], "INVALID NAME") && (strlen(weaponpage->sound_name[i]) > 3)) {
sound_handle = mng_GetGuaranteedSoundPage(weaponpage->sound_name[i]);
if (sound_handle < 0) {
mprintf((0, "Couldn't load sound file '%s' in AssignWeaponPage. Weapon=%s\n", weaponpage->sound_name[i],
weaponpage->weapon_struct.name));
weaponpointer->sounds[i] = SOUND_NONE_INDEX;
} else
weaponpointer->sounds[i] = sound_handle;
} else
weaponpointer->sounds[i] = SOUND_NONE_INDEX;
}
return 1;
}
// Copies values from a weapon into a weapon_page
void mng_AssignWeaponToWeaponPage(int n, mngs_weapon_page *weaponpage) {
weapon *weaponpointer = &Weapons[n];
int i;
// Assign the values
memcpy(&weaponpage->weapon_struct, weaponpointer, sizeof(weapon));
strcpy(weaponpage->weapon_struct.name, weaponpointer->name);
if (weaponpointer->hud_image_handle != -1) {
if (weaponpointer->flags & WF_HUD_ANIMATED)
strcpy(weaponpage->hud_image_name, GameVClips[weaponpointer->hud_image_handle].name);
else
strcpy(weaponpage->hud_image_name, GameBitmaps[weaponpointer->hud_image_handle].name);
} else
strcpy(weaponpage->hud_image_name, "");
if (weaponpointer->fire_image_handle != -1) {
if (weaponpointer->flags & WF_IMAGE_BITMAP)
strcpy(weaponpage->fire_image_name, GameBitmaps[weaponpointer->fire_image_handle].name);
else if (weaponpointer->flags & WF_IMAGE_VCLIP)
strcpy(weaponpage->fire_image_name, GameVClips[weaponpointer->fire_image_handle].name);
else
strcpy(weaponpage->fire_image_name, Poly_models[weaponpointer->fire_image_handle].name);
} else
strcpy(weaponpage->fire_image_name, "");
// do explosion name
if (weaponpointer->explode_image_handle != -1)
strcpy(weaponpage->explode_image_name, GameTextures[weaponpointer->explode_image_handle].name);
else
strcpy(weaponpage->explode_image_name, "");
// Do particle name
if (weaponpointer->particle_handle != -1)
strcpy(weaponpage->particle_name, GameTextures[weaponpointer->particle_handle].name);
else
strcpy(weaponpage->particle_name, "");
// Do spawn name
if (weaponpointer->spawn_handle != -1)
strcpy(weaponpage->spawn_name, Weapons[weaponpointer->spawn_handle].name);
else
strcpy(weaponpage->spawn_name, "");
// Do spawn name
if (weaponpointer->alternate_spawn_handle != -1)
strcpy(weaponpage->alternate_spawn_name, Weapons[weaponpointer->alternate_spawn_handle].name);
else
strcpy(weaponpage->alternate_spawn_name, "");
// Do robot spawn name
if (weaponpointer->robot_spawn_handle != -1)
strcpy(weaponpage->robot_spawn_name, Object_info[weaponpointer->robot_spawn_handle].name);
else
strcpy(weaponpage->robot_spawn_name, "");
if ((weaponpointer->flags & WF_SMOKE) && weaponpointer->smoke_handle >= 0 &&
GameTextures[weaponpointer->smoke_handle].used) {
strcpy(weaponpage->smoke_image_name, GameTextures[weaponpointer->smoke_handle].name);
} else
strcpy(weaponpage->smoke_image_name, "");
if (weaponpointer->scorch_handle >= 0 && GameTextures[weaponpointer->scorch_handle].used) {
strcpy(weaponpage->scorch_image_name, GameTextures[weaponpointer->scorch_handle].name);
} else
strcpy(weaponpage->scorch_image_name, "");
if (weaponpointer->icon_handle >= 0 && GameTextures[weaponpointer->icon_handle].used) {
strcpy(weaponpage->icon_name, GameTextures[weaponpointer->icon_handle].name);
} else
strcpy(weaponpage->icon_name, "");
for (i = 0; i < MAX_WEAPON_SOUNDS; i++) {
if (weaponpointer->sounds[i] != SOUND_NONE_INDEX)
strcpy(weaponpage->sound_name[i], Sounds[weaponpointer->sounds[i]].name);
else
strcpy(weaponpage->sound_name[i], "");
}
}
// Loads a weapon found in the net table file. It then allocs a weapon and
// then calls SetAndLoadWeapon to actually load in any images/models associated
// with it
void mng_LoadNetWeaponPage(CFILE *infile, bool overlay) {
mngs_weapon_page weaponpage;
memset(&weaponpage, 0, sizeof(mngs_weapon_page));
if (mng_ReadNewWeaponPage(infile, &weaponpage)) {
int n = FindWeaponName(weaponpage.weapon_struct.name);
if (n != -1) {
if (overlay) {
mprintf((0, "OVERLAYING WEAPON %s\n", weaponpage.weapon_struct.name));
mng_FreePagetypePrimitives(PAGETYPE_WEAPON, weaponpage.weapon_struct.name, 0);
mng_AssignWeaponPageToWeapon(&weaponpage, n);
}
// mprintf ((0,"Found weapon dependency! You probably should reorder the netpages.\n"));
return;
}
int ret = mng_SetAndLoadWeapon(&weaponpage, infile);
ASSERT(ret >= 0);
} else
mprintf((0, "Could not load weaponpage named %s!\n", weaponpage.weapon_struct.name));
}
// Reads a weapon page from a local table file. It then allocs a weapon and
// loads any images/models associated with that weapon
void mng_LoadLocalWeaponPage(CFILE *infile) {
mngs_weapon_page weaponpage;
int ok = 0;
memset(&weaponpage, 0, sizeof(mngs_weapon_page));
if (mng_ReadNewWeaponPage(infile, &weaponpage)) {
// Check to see if this is a local copy that is supposed
// to go over a network copy (supersede the net copy)
int i = FindWeaponName(weaponpage.weapon_struct.name);
if (i != -1) {
// Make sure we really have this page checked out
mngs_Pagelock pl;
strcpy(pl.name, weaponpage.weapon_struct.name);
pl.pagetype = PAGETYPE_WEAPON;
/*if (Network_up && Stand_alone==0)
{
int locked=mng_CheckIfPageOwned(&pl,TableUser);
if (locked!=1)
Int3(); // Your local vs net copies of the lock file do not match
}*/
ok = 1;
bool need_to_load_page = true;
if (Loading_addon_table != -1) {
AddOnTablefile *addon;
int tidx;
// see if we really need to load this page
// check to see if we already have loaded this page (because it was
// a dependancy of another)
addon = &AddOnDataTables[Loading_addon_table];
for (tidx = 0; tidx < addon->Num_addon_tracklocks; tidx++) {
if (addon->Addon_tracklocks[tidx].pagetype == PAGETYPE_WEAPON &&
!stricmp(addon->Addon_tracklocks[tidx].name, weaponpage.weapon_struct.name)) {
// found it!!
mprintf((0, "WeaponPage: %s previously loaded\n", weaponpage.weapon_struct.name));
need_to_load_page = false;
break;
}
}
}
if (need_to_load_page) {
mng_FreePagetypePrimitives(PAGETYPE_WEAPON, weaponpage.weapon_struct.name, 0);
mng_AssignWeaponPageToWeapon(&weaponpage, i);
// For addon data
if (ok && Loading_addon_table != -1) {
// this is an overlay of some sort..see which we are overlaying
int overlay = 1;
int addidx, tidx;
bool found = false;
for (addidx = Num_addon_tables - 1; addidx >= 0; addidx--) {
if (addidx == Loading_addon_table)
continue;
AddOnTablefile *addon = &AddOnDataTables[addidx];
// look for the page in this table file
for (tidx = 0; tidx < addon->Num_addon_tracklocks; tidx++) {
if (addon->Addon_tracklocks[tidx].pagetype == PAGETYPE_WEAPON &&
!stricmp(addon->Addon_tracklocks[tidx].name, weaponpage.weapon_struct.name)) {
// found it!!
found = true;
overlay = addidx + 2;
break;
}
}
if (found)
break;
}
mng_PushAddonPage(PAGETYPE_WEAPON, weaponpage.weapon_struct.name, overlay);
}
}
} else {
// This is a local weapon that has never been checked in
if ((i = mng_SetAndLoadWeapon(&weaponpage, infile)) < 0)
ok = 0;
else
ok = 1;
// For addon data
if (ok && Loading_addon_table != -1)
mng_PushAddonPage(PAGETYPE_WEAPON, weaponpage.weapon_struct.name, 0);
}
// ASSERT (ok==1);
if (ok != 1)
DataError("Error loading weapon <%s>: %s, file <%s>\n", weaponpage.weapon_struct.name, Weapon_error,
Weapon_error_filename);
if (Loading_addon_table == -1)
mng_AllocTrackLock(weaponpage.weapon_struct.name, PAGETYPE_WEAPON);
} else
mprintf((0, "Could not load weaponpage named %s!\n", weaponpage.weapon_struct.name));
}