/* * Descent 3 * Copyright (C) 2024 Parallax Software * * 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 3 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, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/manage/generic.cpp $ * $Revision: 100 $ * $Date: 9/06/01 10:32a $ * $Author: Matt $ * * * $Log: /DescentIII/Main/manage/generic.cpp $ * * 100 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. * * 99 4/19/00 5:27p Matt * From Duane for 1.4 * Mac file extension change * * 98 10/26/99 3:30p Jeff * handle extra.gam addon tablefile * * 97 10/22/99 10:41p Jeff * correctly merged and handle this mac code merge stuff * * 96 10/22/99 6:04p Jeff * fixed bugs and compiler errors resulting from mac code merge * * 95 10/22/99 2:56p Kevin * Mac merge w/memory savings * * 94 9/18/99 8:49p Jeff * fixed bug with addon pages that have dependencies on other pages in the * addon tablefile * * 93 8/11/99 5:32p Jeff * changes to fix addon tablefile support so it works correctly * * 92 4/25/99 10:19p Matt * Fixed multiplayer and demo problems will killing an object from script, * and cleaned up the death code a bit in the process. * * 91 4/22/99 7:08p Matt * Reduced the number of object sounds from 3 to 2, since we were only * using two. * * 90 4/19/99 3:57p Matt * Took out guidebot velocity hack. * * 89 4/18/99 4:49p Matt * Took out code that hacked in ammo amounts for weapon powerups, and * added code to set the counts on the page and read and write to the * table file. * * 88 4/15/99 5:21p Jason * sped up table file loading * * 87 4/14/99 1:33a Jeff * fixed case mismatched #includes * * 86 4/10/99 5:56p Matt * Cleaned up object initialization code, including create object & load * object. * * 85 4/06/99 6:02p Matt * Added score system * * 84 3/29/99 11:20a Matt * Added more flexibility to death delays, and added fade away deaths. * * 83 3/27/99 2:15p Jason * took out bashing of hangturret * * 82 3/09/99 1:44p Kevin * Bashed the aiming point value for the hangturret. * * 81 3/04/99 4:47p Jason * temp fix (ie BAD HACK) for OEM table file woes * * 80 2/28/99 6:20p Matt * Added the ability to set death types for generic objects. * * 79 2/23/99 12:39p Jason * added more options for generic objects * * 78 2/23/99 11:02a Matt * Changed generic object spew info to use -1 for none * * 77 2/23/99 10:19a Matt * Temporary fix * * 76 2/16/99 12:38a Matt * Took out gunboy sound hack * * 75 2/02/99 8:44a Chris * I made buildings with AI work correctly (ie really big robots should be * buildings) * anim to and from states are now shorts instead of bytes * * 74 1/21/99 11:16p Jeff * pulled out some structs and defines from header files and moved them * into separate header files so that multiplayer dlls don't require major * game headers, just those new headers. Side effect is a shorter build * time. Also cleaned up some header file #includes that weren't needed. * This affected polymodel.h, object.h, player.h, vecmat.h, room.h, * manage.h and multi.h * * 73 1/13/99 7:04a Jeff * put #ifdef around #include * * 72 12/30/98 5:17p Jeff * changes made to handle script name override, to override the name of * the script to use in a module. * * 71 12/29/98 4:30p Jason * added add-on data functionality * * 70 12/17/98 7:26p Jeff * new script system data * * 69 12/01/98 4:31p Chris * * 68 12/01/98 4:31p Chris * Checked in a massive amount of AI work. Improved flocking code. :) * (Still hacked lightly). In addition, I am moving toward using the * composite dir. :) * * 67 11/19/98 8:36p Chris * Tweaked * * 66 11/19/98 8:26p Chris * Starting to add generic team avoidance code * * 65 11/13/98 12:30p Jason * changes for weapons * * 64 11/06/98 12:35p Jason * more speedups for manage system * * 63 11/05/98 7:54p Jason * changes for new manage system * * 62 11/02/98 6:02p Jason * made yes network updates much faster * * 61 10/23/98 6:43p Matt * Kill the gunboy's sounds (for the demo). * * 60 10/12/98 11:38p Jeff * wrapped all the Object_info[].description whenever freed...trying to * find an obscure bug. Added icon_name to manage page of Generic * * 59 10/09/98 2:27p Jason * reorganized table file system * * 58 10/08/98 10:03p Jason * more filtered table file stuff * * 57 9/22/98 2:29p Kevin * moved ships allowed code out of dll and into main app. Also added * powerup exclusions * * 56 8/26/98 8:07p Jason * added directional lights to objects * * 55 8/25/98 3:42p Jason * fixed generic object problems * * 54 8/24/98 2:37p Jason * made table file more efficient with regards to invalid names * * 53 8/19/98 6:29p Chris * * 52 8/16/98 6:17p Chris * Added generic object spewing code * * 51 8/15/98 6:12p Chris * Added 13 new AI fields * * 50 8/14/98 4:56p Jeff * added quad fire mask for weapon battery * * 49 6/12/98 1:06p Jason * added smart loading from local table file * * 48 6/04/98 6:44p Jason * implemented smart FindGenericPage function * * 47 6/01/98 10:37a Matt * Added system to spew powerups when the player dies. Still needs Jason * to deal with mng_FindSpecificGenericPage(). * * 46 5/18/98 8:06p Chris * Removed an unused AI value * * 45 5/07/98 1:41p Chris * Added hit_death_dot * * 44 5/03/98 5:38p Chris * Added sounds to anim page * * 43 4/30/98 12:22p Jason * did some lo-res model optimizations * * 42 4/03/98 10:07a Chris * Added support for objects getting their size computed when the * polymodel is paged in the first time as an object * * 41 4/02/98 3:54p Jason * first pass in getting polymodel paging to work * * 40 3/31/98 3:49p Jason * added memory lib * * 39 3/23/98 10:03a Chris * Added independent wb animations * * 38 3/13/98 5:55p Chris * Added the new collision spheres * * 37 3/11/98 4:59p Chris * Changed the ComputeDefualtSize function call * * 36 3/10/98 6:54p Chris * All start and end frame for ComputeDefaultSize * * 35 3/02/98 6:56p Chris * Changed melee_dist to melee_damage * * 34 3/02/98 6:43p Chris * * 33 3/02/98 4:16p Chris * Added 14 new fields to the AI Settings Dialog/page. * * 32 2/23/98 1:22p Jason * made FindSpecific* read from the local drive, not the net drive - when * starting the editor * * 31 2/06/98 2:15a Chris * Activated the max_velocity, max_delta_velocity, and max_turn_rate * fields for AI objects. * * 30 2/04/98 11:47a Jason * added dynamic description field to generic pages * * 29 1/29/98 3:29p Chris * Major update to the AI system. * * 28 1/23/98 6:25p Jason * Got spray weapons working * * 27 1/15/98 6:22p Jason * added safety checks so the network won't copy over a primitive you have * held locally * * 26 1/05/98 3:55p Chris * Added explosion and ambient sounds * * 25 12/22/97 6:19p Chris * Moved weapon battery firing sound off the projectile (weapon) and into * the weapon battery. * * 24 12/01/97 9:54a Chris * Added support for concussive forces, generalized robot collisions to * generic collisions * * 23 11/25/97 1:16p Jason * added lod system for certain objects * * 22 11/17/97 10:47p Jason * fixed loading/saving of flicker_distance * * 21 11/05/97 12:22p Chris * Fixed size of wb_info in the page file * * 20 11/06/97 11:09a Jason * added extra assert to catch errors * * 19 10/28/97 12:23p Chris * We now save out more AI info * * 18 10/01/97 11:01a Chris * Added new support for additional physics items * * 17 9/24/97 6:18p Samir * Use script names instead of script id values to identify scripts. * * 16 9/17/97 10:59a Chris * Added a new way to compute radi * * 15 9/10/97 5:26p Jason * fixed stupid off by one bug * * 14 9/10/97 5:17p Jason * more lighting improvements * * 13 9/10/97 11:44a Chris * Added support for weapon batteries * * 12 9/08/97 11:51a Chris * Extended the weapon system * * 11 9/05/97 1:29p Jason * revamped generic object lighting * * 10 9/04/97 5:49p Jason * made generic pages read/write pulse time for lighting * * 9 9/04/97 3:21p Jason * added pulse timing for lit objects * * 8 9/03/97 6:18p Jason * added code to support powerups/robots/etc that cast light * * 7 9/03/97 2:12p Chris * Added new weapon battery system and made the animation system usable. * * 6 8/13/97 4:54p Matt * Added destroyable flag & hitpoints * * 5 8/11/97 6:47p Matt * Fixed read/write size mismatches in generic page * * 4 8/11/97 1:53p Matt * Ripped out robot & powerup pages, and added generic page * * 3 8/08/97 5:25p Matt * Type was writing as byte but reading as int * * 2 8/08/97 3:44p Jason * added code to support new generic page * * 1 8/08/97 1:29p Jason * file for object_info pages * * $NoKeywords: $ */ #include #include #include "cfile.h" #include "manage.h" #include "genericpage.h" #include "soundpage.h" #include "weaponpage.h" #include "log.h" #include "pserror.h" #include "polymodel.h" #include "ddio.h" #include "robotfire.h" #include "weapon.h" #include "sounds.h" #include "mem.h" #include "args.h" #define GENERICFILE_VERSION 27 // genericpage 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 GENERICPAGE_COMMAND_NAME 1 #define GENERICPAGE_COMMAND_END 2 #define GENERICPAGE_COMMAND_IMAGE_NAME 3 #define GENERICPAGE_COMMAND_VERSION 4 #define GENERICPAGE_COMMAND_PHYS_MASS 5 #define GENERICPAGE_COMMAND_PHYS_DRAG 6 #define GENERICPAGE_COMMAND_SIZE 7 #define GENERICPAGE_COMMAND_ANIM_STATES 8 #define GENERICPAGE_COMMAND_FLAGS 9 #define GENERICPAGE_COMMAND_PHYS_FLAGS 10 // AI info #define GENERICPAGE_COMMAND_AI_INFO 11 #define GENERICPAGE_COMMAND_TYPE 12 #define GENERICPAGE_COMMAND_SCORE 13 #define GENERICPAGE_COMMAND_SCRIPT 14 #define GENERICPAGE_COMMAND_SOUND_NAME 15 #define GENERICPAGE_COMMAND_HITPOINTS 16 #define GENERICPAGE_COMMAND_LIGHT_CAST 17 #define GENERICPAGE_COMMAND_WB_INFO 18 #define GENERICPAGE_COMMAND_WB_WEAPON 19 #define GENERICPAGE_COMMAND_SCRIPTNAME 20 #define GENERICPAGE_COMMAND_ROT_DRAG 21 #define GENERICPAGE_COMMAND_FULL_THRUST 22 #define GENERICPAGE_COMMAND_FULL_ROTTHRUST 23 #define GENERICPAGE_COMMAND_TURNROLL_RATE 24 #define GENERICPAGE_COMMAND_TURNROLL_RATIO 25 #define GENERICPAGE_COMMAND_WIGGLE_AMP 26 #define GENERICPAGE_COMMAND_WIGGLE_FREQ 27 #define GENERICPAGE_COMMAND_INT_VELOCITY 28 #define GENERICPAGE_COMMAND_INT_ROTVEL 29 #define GENERICPAGE_COMMAND_NUM_BOUNCES 30 #define GENERICPAGE_COMMAND_COEFF_REST 31 #define GENERICPAGE_COMMAND_FLICKER_DISTANCE 32 #define GENERICPAGE_COMMAND_LOD_MODELS 33 // Impact stuff #define GENERICPAGE_COMMAND_IMPACT 34 #define GENERICPAGE_COMMAND_WB_FIRE_SOUND 35 #define GENERICPAGE_COMMAND_WB_FLAGS 36 #define GENERICPAGE_COMMAND_DESCRIPTION 37 #define GENERICPAGE_COMMAND_AI_SOUND_NAME 38 #define GENERICPAGE_COMMAND_LOD_DISTANCE 39 #define GENERICPAGE_COMMAND_ANIM_SOUND_NAME 40 #define GENERICPAGE_COMMAND_HIT_DIE_DOT 41 #define GENERICPAGE_COMMAND_WB_QUADMASK 42 #define GENERICPAGE_COMMAND_AI_INFO2 43 #define GENERICPAGE_COMMAND_DSPEW_INFO 44 #define GENERICPAGE_COMMAND_DIRECTION_DOT 45 #define GENERICPAGE_COMMAND_ICON_NAME 46 void mng_WriteLightingChunk(light_info *lighting_info, CFILE *outfile); void mng_ReadLightingChunk(light_info *lighting_info, CFILE *infile); extern bool Running_editor; // in init.cpp extern char *TablefileNameOverride; // Sets a page structure to default values void mng_InitGenericPage(mngs_generic_page *genericpage) { int i; memset(genericpage, 0, sizeof(mngs_generic_page)); strcpy(genericpage->image_name, ""); strcpy(genericpage->med_image_name, ""); strcpy(genericpage->lo_image_name, ""); for (i = 0; i < MAX_OBJ_SOUNDS; i++) strcpy(genericpage->sound_name[i], ""); for (i = 0; i < MAX_AI_SOUNDS; i++) strcpy(genericpage->ai_sound_name[i], ""); for (i = 0; i < MAX_DSPEW_TYPES; i++) { strcpy(genericpage->dspew_name[i], "\0"); } genericpage->objinfo_struct.description = NULL; genericpage->objinfo_struct.icon_name[0] = '\0'; for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) for (int j = 0; j < NUM_ANIMS_PER_CLASS; j++) strcpy(genericpage->anim_sound_name[i][j], ""); genericpage->objinfo_struct.med_lod_distance = DEFAULT_MED_LOD_DISTANCE; genericpage->objinfo_struct.lo_lod_distance = DEFAULT_LO_LOD_DISTANCE; genericpage->objinfo_struct.phys_info.hit_die_dot = 1.0f; genericpage->objinfo_struct.respawn_scalar = 1.0f; genericpage->ai_info.curiousity = .5f; genericpage->ai_info.night_vision = .7f; genericpage->ai_info.fog_vision = .7f; genericpage->ai_info.lead_accuracy = 1.0f; genericpage->ai_info.lead_varience = 0.0f; genericpage->ai_info.fire_spread = 0.0f; genericpage->ai_info.fight_team = 0.15f; genericpage->ai_info.fight_same = 0.8f; genericpage->ai_info.aggression = 0.5f; genericpage->ai_info.hearing = 1.0f; genericpage->ai_info.frustration = 0.5f; genericpage->ai_info.roaming = 0.5f; genericpage->ai_info.life_preservation = 0.0f; genericpage->objinfo_struct.module_name[0] = '\0'; for (i = 0; i < MAX_DEATH_TYPES; i++) { genericpage->objinfo_struct.death_types[i].flags = 0; genericpage->objinfo_struct.death_types[i].delay_min = 0.0; genericpage->objinfo_struct.death_types[i].delay_max = 0.0; genericpage->objinfo_struct.death_probabilities[i] = 0; } } // Given an open file pointer and a generic_page struct, writes that generic page out void mng_WriteGenericPage(CFILE *outfile, mngs_generic_page *genericpage) { int i, size; ASSERT(outfile != NULL); ASSERT(genericpage != NULL); ASSERT((strlen(genericpage->image_name)) > 2); cf_WriteByte(outfile, PAGETYPE_GENERIC); cf_WriteByte(outfile, GENERICPAGE_COMMAND_VERSION); cf_WriteByte(outfile, 1); cf_WriteByte(outfile, GENERICFILE_VERSION); cf_WriteByte(outfile, GENERICPAGE_COMMAND_TYPE); cf_WriteByte(outfile, 1); cf_WriteByte(outfile, genericpage->objinfo_struct.type); // Write the name cf_WriteByte(outfile, GENERICPAGE_COMMAND_NAME); cf_WriteByte(outfile, strlen(genericpage->objinfo_struct.name) + 1); cf_WriteString(outfile, genericpage->objinfo_struct.name); // Write the model name cf_WriteByte(outfile, GENERICPAGE_COMMAND_IMAGE_NAME); cf_WriteByte(outfile, strlen(genericpage->image_name) + 1); cf_WriteString(outfile, genericpage->image_name); cf_WriteByte(outfile, GENERICPAGE_COMMAND_IMPACT); cf_WriteByte(outfile, 3 * sizeof(float)); cf_WriteFloat(outfile, genericpage->objinfo_struct.impact_size); cf_WriteFloat(outfile, genericpage->objinfo_struct.impact_time); cf_WriteFloat(outfile, genericpage->objinfo_struct.damage); // Write the LOD model names cf_WriteByte(outfile, GENERICPAGE_COMMAND_LOD_MODELS); size = strlen(genericpage->med_image_name) + 1; size += strlen(genericpage->lo_image_name) + 1; cf_WriteByte(outfile, size); cf_WriteString(outfile, genericpage->med_image_name); cf_WriteString(outfile, genericpage->lo_image_name); cf_WriteByte(outfile, GENERICPAGE_COMMAND_SCORE); cf_WriteByte(outfile, 1); cf_WriteByte(outfile, genericpage->objinfo_struct.score); cf_WriteByte(outfile, GENERICPAGE_COMMAND_SCRIPTNAME); cf_WriteByte(outfile, strlen("") + 1); // genericpage->objinfo_struct.script_name cf_WriteString(outfile, ""); if (genericpage->objinfo_struct.description != NULL) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_DESCRIPTION); cf_WriteByte(outfile, strlen(genericpage->objinfo_struct.description) + 1); cf_WriteString(outfile, genericpage->objinfo_struct.description); } if (genericpage->objinfo_struct.icon_name[0] != '\0') { cf_WriteByte(outfile, GENERICPAGE_COMMAND_ICON_NAME); cf_WriteByte(outfile, strlen(genericpage->objinfo_struct.icon_name) + 1); cf_WriteString(outfile, genericpage->objinfo_struct.icon_name); } cf_WriteByte(outfile, GENERICPAGE_COMMAND_LOD_DISTANCE); cf_WriteByte(outfile, 8); cf_WriteFloat(outfile, genericpage->objinfo_struct.med_lod_distance); cf_WriteFloat(outfile, genericpage->objinfo_struct.lo_lod_distance); cf_WriteByte(outfile, GENERICPAGE_COMMAND_PHYS_MASS); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.mass); cf_WriteByte(outfile, GENERICPAGE_COMMAND_PHYS_DRAG); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.drag); cf_WriteByte(outfile, GENERICPAGE_COMMAND_SIZE); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.size); cf_WriteByte(outfile, GENERICPAGE_COMMAND_LIGHT_CAST); cf_WriteByte(outfile, (10 * 4) + 2); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.light_distance); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.red_light1); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.green_light1); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.blue_light1); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.time_interval); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.red_light2); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.green_light2); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.blue_light2); cf_WriteInt(outfile, genericpage->objinfo_struct.lighting_info.flags); cf_WriteInt(outfile, genericpage->objinfo_struct.lighting_info.timebits); cf_WriteByte(outfile, genericpage->objinfo_struct.lighting_info.angle); cf_WriteByte(outfile, genericpage->objinfo_struct.lighting_info.lighting_render_type); cf_WriteByte(outfile, GENERICPAGE_COMMAND_FLICKER_DISTANCE); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.flicker_distance); cf_WriteByte(outfile, GENERICPAGE_COMMAND_DIRECTION_DOT); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.lighting_info.directional_dot); cf_WriteByte(outfile, GENERICPAGE_COMMAND_HITPOINTS); cf_WriteByte(outfile, 4); cf_WriteInt(outfile, genericpage->objinfo_struct.hit_points); cf_WriteByte(outfile, GENERICPAGE_COMMAND_FLAGS); cf_WriteByte(outfile, 4); cf_WriteInt(outfile, genericpage->objinfo_struct.flags); cf_WriteByte(outfile, GENERICPAGE_COMMAND_PHYS_FLAGS); cf_WriteByte(outfile, 4); cf_WriteInt(outfile, genericpage->objinfo_struct.phys_info.flags); cf_WriteByte(outfile, GENERICPAGE_COMMAND_ROT_DRAG); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.rotdrag); cf_WriteByte(outfile, GENERICPAGE_COMMAND_FULL_THRUST); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.full_thrust); cf_WriteByte(outfile, GENERICPAGE_COMMAND_FULL_ROTTHRUST); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.full_rotthrust); cf_WriteByte(outfile, GENERICPAGE_COMMAND_TURNROLL_RATE); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.max_turnroll_rate); cf_WriteByte(outfile, GENERICPAGE_COMMAND_TURNROLL_RATIO); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.turnroll_ratio); cf_WriteByte(outfile, GENERICPAGE_COMMAND_WIGGLE_AMP); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.wiggle_amplitude); cf_WriteByte(outfile, GENERICPAGE_COMMAND_WIGGLE_FREQ); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.wiggles_per_sec); cf_WriteByte(outfile, GENERICPAGE_COMMAND_INT_VELOCITY); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.velocity.z); cf_WriteByte(outfile, GENERICPAGE_COMMAND_INT_ROTVEL); cf_WriteByte(outfile, 12); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.rotvel.x); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.rotvel.y); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.rotvel.z); cf_WriteByte(outfile, GENERICPAGE_COMMAND_NUM_BOUNCES); cf_WriteByte(outfile, 4); cf_WriteInt(outfile, genericpage->objinfo_struct.phys_info.num_bounces); cf_WriteByte(outfile, GENERICPAGE_COMMAND_COEFF_REST); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.coeff_restitution); cf_WriteByte(outfile, GENERICPAGE_COMMAND_HIT_DIE_DOT); cf_WriteByte(outfile, 4); cf_WriteFloat(outfile, genericpage->objinfo_struct.phys_info.hit_die_dot); cf_WriteByte(outfile, GENERICPAGE_COMMAND_AI_INFO); cf_WriteByte(outfile, 76); cf_WriteInt(outfile, genericpage->ai_info.flags); cf_WriteByte(outfile, genericpage->ai_info.ai_class); cf_WriteByte(outfile, genericpage->ai_info.ai_type); cf_WriteByte(outfile, genericpage->ai_info.movement_type); cf_WriteByte(outfile, genericpage->ai_info.movement_subtype); cf_WriteFloat(outfile, genericpage->ai_info.fov); cf_WriteFloat(outfile, genericpage->ai_info.max_velocity); cf_WriteFloat(outfile, genericpage->ai_info.max_delta_velocity); cf_WriteFloat(outfile, genericpage->ai_info.max_turn_rate); cf_WriteFloat(outfile, genericpage->ai_info.avoid_friends_distance); // Makes sure there are no bugs as things are added and removed -- ask chris genericpage->ai_info.notify_flags &= ~AI_NOTIFIES_ALWAYS_ON; cf_WriteInt(outfile, genericpage->ai_info.notify_flags); genericpage->ai_info.notify_flags |= AI_NOTIFIES_ALWAYS_ON; cf_WriteFloat(outfile, genericpage->ai_info.max_delta_turn_rate); cf_WriteFloat(outfile, genericpage->ai_info.circle_distance); cf_WriteFloat(outfile, genericpage->ai_info.attack_vel_percent); cf_WriteFloat(outfile, genericpage->ai_info.dodge_percent); cf_WriteFloat(outfile, genericpage->ai_info.dodge_vel_percent); cf_WriteFloat(outfile, genericpage->ai_info.flee_vel_percent); cf_WriteFloat(outfile, genericpage->ai_info.melee_damage[0]); cf_WriteFloat(outfile, genericpage->ai_info.melee_damage[1]); cf_WriteFloat(outfile, genericpage->ai_info.melee_latency[0]); cf_WriteFloat(outfile, genericpage->ai_info.melee_latency[1]); for (i = 0; i < MAX_OBJ_SOUNDS; i++) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_SOUND_NAME); cf_WriteByte(outfile, strlen(genericpage->sound_name[i]) + 2); // 1 for sound index, 1 for null term cf_WriteByte(outfile, i); cf_WriteString(outfile, genericpage->sound_name[i]); } for (i = 0; i < MAX_AI_SOUNDS; i++) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_AI_SOUND_NAME); cf_WriteByte(outfile, strlen(genericpage->ai_sound_name[i]) + 2); // 1 for sound index, 1 for null term cf_WriteByte(outfile, i); cf_WriteString(outfile, genericpage->ai_sound_name[i]); } for (i = 0; i < MAX_DSPEW_TYPES; i++) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_DSPEW_INFO); cf_WriteByte(outfile, strlen(genericpage->dspew_name[i]) + 9); // 1 for null character cf_WriteByte(outfile, i); cf_WriteByte(outfile, genericpage->objinfo_struct.f_dspew); cf_WriteFloat(outfile, genericpage->objinfo_struct.dspew_percent[i]); cf_WriteShort(outfile, genericpage->objinfo_struct.dspew_number[i]); cf_WriteString(outfile, genericpage->dspew_name[i]); } cf_WriteByte(outfile, GENERICPAGE_COMMAND_AI_INFO2); cf_WriteByte(outfile, 13 * sizeof(float)); cf_WriteFloat(outfile, genericpage->ai_info.curiousity); cf_WriteFloat(outfile, genericpage->ai_info.night_vision); cf_WriteFloat(outfile, genericpage->ai_info.fog_vision); cf_WriteFloat(outfile, genericpage->ai_info.lead_accuracy); cf_WriteFloat(outfile, genericpage->ai_info.lead_varience); cf_WriteFloat(outfile, genericpage->ai_info.fire_spread); cf_WriteFloat(outfile, genericpage->ai_info.fight_team); cf_WriteFloat(outfile, genericpage->ai_info.fight_same); cf_WriteFloat(outfile, genericpage->ai_info.aggression); cf_WriteFloat(outfile, genericpage->ai_info.hearing); cf_WriteFloat(outfile, genericpage->ai_info.frustration); cf_WriteFloat(outfile, genericpage->ai_info.roaming); cf_WriteFloat(outfile, genericpage->ai_info.life_preservation); for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { int j; cf_WriteByte(outfile, GENERICPAGE_COMMAND_ANIM_STATES); size = sizeof(anim_entry) * NUM_ANIMS_PER_CLASS; size++; // add a byte to tell which class this is for cf_WriteByte(outfile, size); cf_WriteByte(outfile, i); for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { cf_WriteShort(outfile, genericpage->anim[i].elem[j].from); cf_WriteShort(outfile, genericpage->anim[i].elem[j].to); cf_WriteFloat(outfile, genericpage->anim[i].elem[j].spc); } } cf_WriteByte(outfile, GENERICPAGE_COMMAND_WB_FLAGS); cf_WriteByte(outfile, sizeof(int) * MAX_WBS_PER_OBJ); for (i = 0; i < MAX_WBS_PER_OBJ; i++) cf_WriteByte(outfile, genericpage->static_wb[i].flags); for (i = 0; i < MAX_WBS_PER_OBJ; i++) { int j; cf_WriteByte(outfile, GENERICPAGE_COMMAND_WB_INFO); size = 202; cf_WriteByte(outfile, size); cf_WriteByte(outfile, i); for (j = 0; j < MAX_WB_GUNPOINTS; j++) cf_WriteShort(outfile, genericpage->static_wb[i].gp_weapon_index[j]); cf_WriteShort(outfile, genericpage->static_wb[i].aiming_gp_index); cf_WriteByte(outfile, genericpage->static_wb[i].num_masks); for (j = 0; j < MAX_WB_FIRING_MASKS; j++) cf_WriteByte(outfile, genericpage->static_wb[i].gp_fire_masks[j]); for (j = 0; j < MAX_WB_FIRING_MASKS; j++) cf_WriteFloat(outfile, genericpage->static_wb[i].gp_fire_wait[j]); for (j = 0; j < MAX_WB_FIRING_MASKS; j++) { cf_WriteFloat(outfile, genericpage->static_wb[i].anim_time[j]); cf_WriteFloat(outfile, genericpage->static_wb[i].anim_start_frame[j]); cf_WriteFloat(outfile, genericpage->static_wb[i].anim_fire_frame[j]); cf_WriteFloat(outfile, genericpage->static_wb[i].anim_end_frame[j]); } cf_WriteByte(outfile, genericpage->static_wb[i].aiming_flags); cf_WriteFloat(outfile, genericpage->static_wb[i].aiming_3d_dot); cf_WriteFloat(outfile, genericpage->static_wb[i].aiming_3d_dist); cf_WriteFloat(outfile, genericpage->static_wb[i].aiming_XZ_dot); } for (i = 0; i < MAX_WBS_PER_OBJ; i++) { int j; for (j = 0; j < MAX_WB_GUNPOINTS; j++) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_WB_WEAPON); size = strlen(genericpage->weapon_name[i][j]) + 1 + 2; // 1 for the null character and 2 for the 2 indices cf_WriteByte(outfile, size); cf_WriteByte(outfile, i); cf_WriteByte(outfile, j); cf_WriteString(outfile, genericpage->weapon_name[i][j]); } } cf_WriteByte(outfile, GENERICPAGE_COMMAND_WB_QUADMASK); cf_WriteByte(outfile, MAX_WBS_PER_OBJ); for (i = 0; i < MAX_WBS_PER_OBJ; i++) { cf_WriteByte(outfile, genericpage->static_wb[i].gp_quad_fire_mask); } for (i = 0; i < MAX_WBS_PER_OBJ; i++) { int j; for (j = 0; j < MAX_WB_FIRING_MASKS; j++) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_WB_FIRE_SOUND); size = strlen(genericpage->fire_sound_name[i][j]) + 1 + 2; // 1 for the null character and 2 for the 2 indices cf_WriteByte(outfile, size); cf_WriteByte(outfile, i); cf_WriteByte(outfile, j); cf_WriteString(outfile, genericpage->fire_sound_name[i][j]); } } for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { int j; for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { cf_WriteByte(outfile, GENERICPAGE_COMMAND_ANIM_SOUND_NAME); size = strlen(genericpage->anim_sound_name[i][j]) + 1 + 2; // 1 for the null character and 2 for the 2 indices cf_WriteByte(outfile, size); cf_WriteByte(outfile, i); cf_WriteByte(outfile, j); cf_WriteString(outfile, genericpage->anim_sound_name[i][j]); } } cf_WriteByte(outfile, GENERICPAGE_COMMAND_END); // we're all done cf_WriteByte(outfile, 0); } // Given an open file pointer and a generic_page struct, writes that generic page out void mng_WriteNewGenericPage(CFILE *outfile, mngs_generic_page *genericpage) { int i, j; ASSERT(outfile != NULL); ASSERT(genericpage != NULL); ASSERT((strlen(genericpage->image_name)) > 2); int offset = StartManagePage(outfile, PAGETYPE_GENERIC); cf_WriteShort(outfile, GENERICFILE_VERSION); cf_WriteByte(outfile, genericpage->objinfo_struct.type); // Write out object name cf_WriteString(outfile, genericpage->objinfo_struct.name); // Write out model names cf_WriteString(outfile, genericpage->image_name); cf_WriteString(outfile, genericpage->med_image_name); cf_WriteString(outfile, genericpage->lo_image_name); // Write out impact data cf_WriteFloat(outfile, genericpage->objinfo_struct.impact_size); cf_WriteFloat(outfile, genericpage->objinfo_struct.impact_time); cf_WriteFloat(outfile, genericpage->objinfo_struct.damage); // Write score cf_WriteShort(outfile, genericpage->objinfo_struct.score); // Write ammo if (genericpage->objinfo_struct.type == OBJ_POWERUP) cf_WriteShort(outfile, genericpage->objinfo_struct.ammo_count); // Write script name cf_WriteString(outfile, ""); // genericpage->objinfo_struct.script_name // Write module name cf_WriteString(outfile, genericpage->objinfo_struct.module_name); // Write scriptname override cf_WriteString(outfile, genericpage->objinfo_struct.script_name_override); if (genericpage->objinfo_struct.description != NULL) { // Write description if there is one cf_WriteByte(outfile, 1); cf_WriteString(outfile, genericpage->objinfo_struct.description); } else cf_WriteByte(outfile, 0); // Write icon name cf_WriteString(outfile, genericpage->objinfo_struct.icon_name); // Write LOD distances cf_WriteFloat(outfile, genericpage->objinfo_struct.med_lod_distance); cf_WriteFloat(outfile, genericpage->objinfo_struct.lo_lod_distance); // Write physics stuff mng_WritePhysicsChunk(&genericpage->objinfo_struct.phys_info, outfile); // Write size cf_WriteFloat(outfile, genericpage->objinfo_struct.size); // Write light info mng_WriteLightingChunk(&genericpage->objinfo_struct.lighting_info, outfile); // Write hit points cf_WriteInt(outfile, genericpage->objinfo_struct.hit_points); // Write flags cf_WriteInt(outfile, genericpage->objinfo_struct.flags); // Write AI info cf_WriteInt(outfile, genericpage->ai_info.flags); cf_WriteByte(outfile, genericpage->ai_info.ai_class); cf_WriteByte(outfile, genericpage->ai_info.ai_type); cf_WriteByte(outfile, genericpage->ai_info.movement_type); cf_WriteByte(outfile, genericpage->ai_info.movement_subtype); cf_WriteFloat(outfile, genericpage->ai_info.fov); cf_WriteFloat(outfile, genericpage->ai_info.max_velocity); cf_WriteFloat(outfile, genericpage->ai_info.max_delta_velocity); cf_WriteFloat(outfile, genericpage->ai_info.max_turn_rate); // Makes sure there are no bugs as things are added and removed -- ask chris genericpage->ai_info.notify_flags &= ~AI_NOTIFIES_ALWAYS_ON; cf_WriteInt(outfile, genericpage->ai_info.notify_flags); genericpage->ai_info.notify_flags |= AI_NOTIFIES_ALWAYS_ON; cf_WriteFloat(outfile, genericpage->ai_info.max_delta_turn_rate); cf_WriteFloat(outfile, genericpage->ai_info.circle_distance); cf_WriteFloat(outfile, genericpage->ai_info.attack_vel_percent); cf_WriteFloat(outfile, genericpage->ai_info.dodge_percent); cf_WriteFloat(outfile, genericpage->ai_info.dodge_vel_percent); cf_WriteFloat(outfile, genericpage->ai_info.flee_vel_percent); cf_WriteFloat(outfile, genericpage->ai_info.melee_damage[0]); cf_WriteFloat(outfile, genericpage->ai_info.melee_damage[1]); cf_WriteFloat(outfile, genericpage->ai_info.melee_latency[0]); cf_WriteFloat(outfile, genericpage->ai_info.melee_latency[1]); cf_WriteFloat(outfile, genericpage->ai_info.curiousity); cf_WriteFloat(outfile, genericpage->ai_info.night_vision); cf_WriteFloat(outfile, genericpage->ai_info.fog_vision); cf_WriteFloat(outfile, genericpage->ai_info.lead_accuracy); cf_WriteFloat(outfile, genericpage->ai_info.lead_varience); cf_WriteFloat(outfile, genericpage->ai_info.fire_spread); cf_WriteFloat(outfile, genericpage->ai_info.fight_team); cf_WriteFloat(outfile, genericpage->ai_info.fight_same); cf_WriteFloat(outfile, genericpage->ai_info.aggression); cf_WriteFloat(outfile, genericpage->ai_info.hearing); cf_WriteFloat(outfile, genericpage->ai_info.frustration); cf_WriteFloat(outfile, genericpage->ai_info.roaming); cf_WriteFloat(outfile, genericpage->ai_info.life_preservation); cf_WriteFloat(outfile, genericpage->ai_info.avoid_friends_distance); cf_WriteFloat(outfile, genericpage->ai_info.biased_flight_importance); cf_WriteFloat(outfile, genericpage->ai_info.biased_flight_min); cf_WriteFloat(outfile, genericpage->ai_info.biased_flight_max); // Write out objects spewed for (i = 0; i < MAX_DSPEW_TYPES; i++) { cf_WriteByte(outfile, genericpage->objinfo_struct.f_dspew); cf_WriteFloat(outfile, genericpage->objinfo_struct.dspew_percent[i]); cf_WriteShort(outfile, genericpage->objinfo_struct.dspew_number[i]); cf_WriteString(outfile, genericpage->dspew_name[i]); } // Write out animation info for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { cf_WriteShort(outfile, genericpage->anim[i].elem[j].from); cf_WriteShort(outfile, genericpage->anim[i].elem[j].to); cf_WriteFloat(outfile, genericpage->anim[i].elem[j].spc); } } // Write out weapon batteries for (i = 0; i < MAX_WBS_PER_OBJ; i++) mng_WriteWeaponBatteryChunk(&genericpage->static_wb[i], outfile); // Write out weapon names for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_GUNPOINTS; j++) cf_WriteString(outfile, genericpage->weapon_name[i][j]); } // Write out sounds for (i = 0; i < MAX_OBJ_SOUNDS; i++) cf_WriteString(outfile, genericpage->sound_name[i]); for (i = 0; i < MAX_AI_SOUNDS; i++) cf_WriteString(outfile, genericpage->ai_sound_name[i]); for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_FIRING_MASKS; j++) cf_WriteString(outfile, genericpage->fire_sound_name[i][j]); } for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) cf_WriteString(outfile, genericpage->anim_sound_name[i][j]); } // Write out respawn scalar cf_WriteFloat(outfile, genericpage->objinfo_struct.respawn_scalar); // Write out death information cf_WriteShort(outfile, MAX_DEATH_TYPES); for (i = 0; i < MAX_DEATH_TYPES; i++) { cf_WriteInt(outfile, genericpage->objinfo_struct.death_types[i].flags); cf_WriteFloat(outfile, genericpage->objinfo_struct.death_types[i].delay_min); cf_WriteFloat(outfile, genericpage->objinfo_struct.death_types[i].delay_max); cf_WriteByte(outfile, genericpage->objinfo_struct.death_probabilities[i]); } EndManagePage(outfile, offset); } // Old delay types #define OLD_DF_DELAY_NONE 0x0000000 #define OLD_DF_DELAY_MIN_MAX 0x0000001 #define OLD_DF_DELAY_FROM_ANIM 0x0000002 #define OLD_DF_DELAY_MASK 0x0000003 #define OLD_DF_DELAY_SHIFT 0 void GenericPageSetPowerupDefaultAmmo(object_info *ip) { // Default is zero ip->ammo_count = 0; // Set for specific types if (!stricmp(ip->name, "Vauss")) ip->ammo_count = 5000; if (!stricmp(ip->name, "Napalm")) ip->ammo_count = 500; if (!stricmp(ip->name, "MassDriver")) ip->ammo_count = 20; if (!stricmp(ip->name, "Frag")) ip->ammo_count = 1; if (!stricmp(ip->name, "ImpactMortar")) ip->ammo_count = 1; if (!stricmp(ip->name, "NapalmRocket")) ip->ammo_count = 1; if (!stricmp(ip->name, "Cyclone")) ip->ammo_count = 1; if (!stricmp(ip->name, "BlackShark")) ip->ammo_count = 1; if (!stricmp(ip->name, "Concussion")) ip->ammo_count = 1; if (!stricmp(ip->name, "Homing")) ip->ammo_count = 1; if (!stricmp(ip->name, "Smart")) ip->ammo_count = 1; if (!stricmp(ip->name, "Mega")) ip->ammo_count = 1; if (!stricmp(ip->name, "Guided")) ip->ammo_count = 1; if (!stricmp(ip->name, "4PackHoming")) ip->ammo_count = 4; if (!stricmp(ip->name, "4PackConc")) ip->ammo_count = 4; if (!stricmp(ip->name, "4PackFrag")) ip->ammo_count = 4; if (!stricmp(ip->name, "4PackGuided")) ip->ammo_count = 4; if (!stricmp(ip->name, "Vauss clip")) ip->ammo_count = 1250; if (!stricmp(ip->name, "MassDriverAmmo")) ip->ammo_count = 5; if (!stricmp(ip->name, "NapalmTank")) ip->ammo_count = 100; } // Reads a generic page from an open file. Returns 0 on error. int mng_ReadNewGenericPage(CFILE *infile, mngs_generic_page *genericpage) { int i, j; ASSERT(infile != NULL); mng_InitGenericPage(genericpage); int version = cf_ReadShort(infile); genericpage->objinfo_struct.type = cf_ReadByte(infile); // Read object name cf_ReadString(genericpage->objinfo_struct.name, PAGENAME_LEN, infile); // Read model names cf_ReadString(genericpage->image_name, PAGENAME_LEN, infile); cf_ReadString(genericpage->med_image_name, PAGENAME_LEN, infile); cf_ReadString(genericpage->lo_image_name, PAGENAME_LEN, infile); // Read out impact data genericpage->objinfo_struct.impact_size = cf_ReadFloat(infile); genericpage->objinfo_struct.impact_time = cf_ReadFloat(infile); genericpage->objinfo_struct.damage = cf_ReadFloat(infile); // Read score if (version >= 24) genericpage->objinfo_struct.score = cf_ReadShort(infile); else genericpage->objinfo_struct.score = cf_ReadByte(infile); // Read ammo if (genericpage->objinfo_struct.type == OBJ_POWERUP) { if (version >= 25) genericpage->objinfo_struct.ammo_count = cf_ReadShort(infile); else GenericPageSetPowerupDefaultAmmo(&genericpage->objinfo_struct); } else genericpage->objinfo_struct.ammo_count = 0; // Read script name char dummy[256]; cf_ReadString(dummy, PAGENAME_LEN, infile); // genericpage->objinfo_struct.script_name if (version >= 18) { cf_ReadString(genericpage->objinfo_struct.module_name, MAX_MODULENAME_LEN, infile); } else { genericpage->objinfo_struct.module_name[0] = '\0'; } if (version >= 19) { cf_ReadString(genericpage->objinfo_struct.script_name_override, PAGENAME_LEN, infile); } else { genericpage->objinfo_struct.script_name_override[0] = '\0'; } int desc = cf_ReadByte(infile); if (desc) { // Read description if there is one char tempbuf[1024]; cf_ReadString(tempbuf, 1024, infile); int slen = strlen(tempbuf) + 1; genericpage->objinfo_struct.description = (char *)mem_malloc(slen); ASSERT(genericpage->objinfo_struct.description); strcpy(genericpage->objinfo_struct.description, tempbuf); } else genericpage->objinfo_struct.description = NULL; // Read icon name cf_ReadString(genericpage->objinfo_struct.icon_name, PAGENAME_LEN, infile); // Read LOD distances genericpage->objinfo_struct.med_lod_distance = cf_ReadFloat(infile); genericpage->objinfo_struct.lo_lod_distance = cf_ReadFloat(infile); // Read physics stuff mng_ReadPhysicsChunk(&genericpage->objinfo_struct.phys_info, infile); // Write size genericpage->objinfo_struct.size = cf_ReadFloat(infile); // Write light info mng_ReadLightingChunk(&genericpage->objinfo_struct.lighting_info, infile); // Read hit points genericpage->objinfo_struct.hit_points = cf_ReadInt(infile); // Read flags genericpage->objinfo_struct.flags = cf_ReadInt(infile); // Write AI info genericpage->ai_info.flags = cf_ReadInt(infile); genericpage->ai_info.ai_class = cf_ReadByte(infile); genericpage->ai_info.ai_type = cf_ReadByte(infile); genericpage->ai_info.movement_type = cf_ReadByte(infile); genericpage->ai_info.movement_subtype = cf_ReadByte(infile); genericpage->ai_info.fov = cf_ReadFloat(infile); genericpage->ai_info.max_velocity = cf_ReadFloat(infile); genericpage->ai_info.max_delta_velocity = cf_ReadFloat(infile); genericpage->ai_info.max_turn_rate = cf_ReadFloat(infile); // Makes sure there are no bugs as things are added and removed -- ask chris genericpage->ai_info.notify_flags &= ~AI_NOTIFIES_ALWAYS_ON; genericpage->ai_info.notify_flags = cf_ReadInt(infile); genericpage->ai_info.notify_flags |= AI_NOTIFIES_ALWAYS_ON; genericpage->ai_info.max_delta_turn_rate = cf_ReadFloat(infile); genericpage->ai_info.circle_distance = cf_ReadFloat(infile); genericpage->ai_info.attack_vel_percent = cf_ReadFloat(infile); genericpage->ai_info.dodge_percent = cf_ReadFloat(infile); genericpage->ai_info.dodge_vel_percent = cf_ReadFloat(infile); genericpage->ai_info.flee_vel_percent = cf_ReadFloat(infile); genericpage->ai_info.melee_damage[0] = cf_ReadFloat(infile); genericpage->ai_info.melee_damage[1] = cf_ReadFloat(infile); genericpage->ai_info.melee_latency[0] = cf_ReadFloat(infile); genericpage->ai_info.melee_latency[1] = cf_ReadFloat(infile); genericpage->ai_info.curiousity = cf_ReadFloat(infile); genericpage->ai_info.night_vision = cf_ReadFloat(infile); genericpage->ai_info.fog_vision = cf_ReadFloat(infile); genericpage->ai_info.lead_accuracy = cf_ReadFloat(infile); genericpage->ai_info.lead_varience = cf_ReadFloat(infile); genericpage->ai_info.fire_spread = cf_ReadFloat(infile); genericpage->ai_info.fight_team = cf_ReadFloat(infile); genericpage->ai_info.fight_same = cf_ReadFloat(infile); genericpage->ai_info.aggression = cf_ReadFloat(infile); genericpage->ai_info.hearing = cf_ReadFloat(infile); genericpage->ai_info.frustration = cf_ReadFloat(infile); genericpage->ai_info.roaming = cf_ReadFloat(infile); genericpage->ai_info.life_preservation = cf_ReadFloat(infile); if (version >= 16) { genericpage->ai_info.avoid_friends_distance = cf_ReadFloat(infile); } else if ((genericpage->objinfo_struct.flags | OIF_USES_PHYSICS) && genericpage->ai_info.max_velocity > 0.0f) { genericpage->ai_info.flags |= AIF_AUTO_AVOID_FRIENDS; genericpage->ai_info.avoid_friends_distance = genericpage->ai_info.circle_distance / 10.f; if (genericpage->ai_info.avoid_friends_distance < 4.0f) genericpage->ai_info.avoid_friends_distance = 4.0f; } else { genericpage->ai_info.avoid_friends_distance = 4.0f; } if (version >= 17) { genericpage->ai_info.biased_flight_importance = cf_ReadFloat(infile); genericpage->ai_info.biased_flight_min = cf_ReadFloat(infile); genericpage->ai_info.biased_flight_max = cf_ReadFloat(infile); } else { genericpage->ai_info.biased_flight_importance = .5f; genericpage->ai_info.biased_flight_min = 10.0f; genericpage->ai_info.biased_flight_max = 50.0f; } // Write out objects spewed for (i = 0; i < MAX_DSPEW_TYPES; i++) { genericpage->objinfo_struct.f_dspew = cf_ReadByte(infile); genericpage->objinfo_struct.dspew_percent[i] = cf_ReadFloat(infile); genericpage->objinfo_struct.dspew_number[i] = cf_ReadShort(infile); // Read spew name cf_ReadString(genericpage->dspew_name[i], PAGENAME_LEN, infile); } // Read out animation info for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { if (version < 20) { genericpage->anim[i].elem[j].from = cf_ReadByte(infile); genericpage->anim[i].elem[j].to = cf_ReadByte(infile); } else { genericpage->anim[i].elem[j].from = cf_ReadShort(infile); genericpage->anim[i].elem[j].to = cf_ReadShort(infile); } genericpage->anim[i].elem[j].spc = cf_ReadFloat(infile); } } // read weapon batteries for (i = 0; i < MAX_WBS_PER_OBJ; i++) { if (version >= 15) mng_ReadWeaponBatteryChunk(&genericpage->static_wb[i], infile, 2); else mng_ReadWeaponBatteryChunk(&genericpage->static_wb[i], infile, 1); } // read weapon names for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_GUNPOINTS; j++) cf_ReadString(genericpage->weapon_name[i][j], PAGENAME_LEN, infile); } // read sounds ASSERT(MAX_OBJ_SOUNDS == 2); for (i = 0; i < MAX_OBJ_SOUNDS; i++) cf_ReadString(genericpage->sound_name[i], PAGENAME_LEN, infile); if (version < 26) { // used to be three sounds char temp_sound_name[PAGENAME_LEN]; cf_ReadString(temp_sound_name, PAGENAME_LEN, infile); } for (i = 0; i < MAX_AI_SOUNDS; i++) cf_ReadString(genericpage->ai_sound_name[i], PAGENAME_LEN, infile); for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_FIRING_MASKS; j++) cf_ReadString(genericpage->fire_sound_name[i][j], PAGENAME_LEN, infile); } for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) cf_ReadString(genericpage->anim_sound_name[i][j], PAGENAME_LEN, infile); } // Read respawn scalar if (version >= 21) genericpage->objinfo_struct.respawn_scalar = cf_ReadFloat(infile); else genericpage->objinfo_struct.respawn_scalar = 1.0; if (version >= 22) { int n_death_types = cf_ReadShort(infile); for (i = 0; i < n_death_types; i++) { int flags = cf_ReadInt(infile); if (version == 22) { // translate death flags Int3(); // this version no longer supported } genericpage->objinfo_struct.death_types[i].flags = flags; genericpage->objinfo_struct.death_types[i].delay_min = cf_ReadFloat(infile); genericpage->objinfo_struct.death_types[i].delay_max = cf_ReadFloat(infile); genericpage->objinfo_struct.death_probabilities[i] = cf_ReadByte(infile); // Fix up for changed flags if (version < 27) { if ((flags & OLD_DF_DELAY_MASK) != OLD_DF_DELAY_MIN_MAX) { genericpage->objinfo_struct.death_types[i].delay_min = 0.0; genericpage->objinfo_struct.death_types[i].delay_max = 0.0; } flags &= ~DF_UNUSED; } } } // Set score from hitpoints if old version if (version < 24) { if ((genericpage->objinfo_struct.type == OBJ_ROBOT) || (genericpage->objinfo_struct.type == OBJ_BUILDING && (genericpage->objinfo_struct.flags & OIF_CONTROL_AI))) if (genericpage->objinfo_struct.flags & OIF_DESTROYABLE) genericpage->objinfo_struct.score = 3 * genericpage->objinfo_struct.hit_points; } ASSERT(genericpage->objinfo_struct.type != OBJ_NONE); return 1; // successfully read } // Reads a generic page from an open file. Returns 0 on error. int mng_ReadGenericPage(CFILE *infile, mngs_generic_page *genericpage) { int done = 0; char command; uint16_t len; int i, temp, version = 0, t; if (!Old_table_method) return mng_ReadNewGenericPage(infile, genericpage); ASSERT(infile != NULL); mng_InitGenericPage(genericpage); 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 GENERICPAGE_COMMAND_END: done = 1; break; case GENERICPAGE_COMMAND_VERSION: version = cf_ReadByte(infile); break; case GENERICPAGE_COMMAND_TYPE: genericpage->objinfo_struct.type = cf_ReadByte(infile); break; case GENERICPAGE_COMMAND_SCORE: genericpage->objinfo_struct.score = cf_ReadByte(infile); break; case GENERICPAGE_COMMAND_SCRIPT: // Obsolete as of 09-24-97 cf_ReadByte(infile); break; case GENERICPAGE_COMMAND_SCRIPTNAME: { char dummy[256]; cf_ReadString(dummy, len + 1, infile); // genericpage->objinfo_struct.script_name } break; case GENERICPAGE_COMMAND_DESCRIPTION: genericpage->objinfo_struct.description = (char *)mem_malloc(len + 1); ASSERT(genericpage->objinfo_struct.description); // out of memory! cf_ReadString(genericpage->objinfo_struct.description, len + 1, infile); break; case GENERICPAGE_COMMAND_ICON_NAME: cf_ReadString(genericpage->objinfo_struct.icon_name, len + 1, infile); break; case GENERICPAGE_COMMAND_IMAGE_NAME: // the name of the generic model cf_ReadString(genericpage->image_name, len + 1, infile); break; case GENERICPAGE_COMMAND_LOD_MODELS: // the name of the lower res models cf_ReadString(genericpage->med_image_name, len + 1, infile); cf_ReadString(genericpage->lo_image_name, len + 1, infile); break; case GENERICPAGE_COMMAND_NAME: cf_ReadString(genericpage->objinfo_struct.name, len + 1, infile); break; case GENERICPAGE_COMMAND_SIZE: genericpage->objinfo_struct.size = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_LOD_DISTANCE: genericpage->objinfo_struct.med_lod_distance = cf_ReadFloat(infile); genericpage->objinfo_struct.lo_lod_distance = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_DSPEW_INFO: { int i = cf_ReadByte(infile); genericpage->objinfo_struct.f_dspew = cf_ReadByte(infile); genericpage->objinfo_struct.dspew_percent[i] = cf_ReadFloat(infile); genericpage->objinfo_struct.dspew_number[i] = cf_ReadShort(infile); cf_ReadString(genericpage->dspew_name[i], len - 7, infile); } break; case GENERICPAGE_COMMAND_WB_FLAGS: { for (int i = 0; i < MAX_WBS_PER_OBJ; i++) genericpage->static_wb[i].flags = cf_ReadByte(infile); } break; case GENERICPAGE_COMMAND_IMPACT: genericpage->objinfo_struct.impact_size = cf_ReadFloat(infile); genericpage->objinfo_struct.impact_time = cf_ReadFloat(infile); genericpage->objinfo_struct.damage = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_FLICKER_DISTANCE: genericpage->objinfo_struct.lighting_info.flicker_distance = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_DIRECTION_DOT: genericpage->objinfo_struct.lighting_info.directional_dot = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_AI_INFO2: genericpage->ai_info.curiousity = cf_ReadFloat(infile); genericpage->ai_info.night_vision = cf_ReadFloat(infile); genericpage->ai_info.fog_vision = cf_ReadFloat(infile); genericpage->ai_info.lead_accuracy = cf_ReadFloat(infile); genericpage->ai_info.lead_varience = cf_ReadFloat(infile); genericpage->ai_info.fire_spread = cf_ReadFloat(infile); genericpage->ai_info.fight_team = cf_ReadFloat(infile); genericpage->ai_info.fight_same = cf_ReadFloat(infile); genericpage->ai_info.aggression = cf_ReadFloat(infile); genericpage->ai_info.hearing = cf_ReadFloat(infile); genericpage->ai_info.frustration = cf_ReadFloat(infile); genericpage->ai_info.roaming = cf_ReadFloat(infile); genericpage->ai_info.life_preservation = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_LIGHT_CAST: genericpage->objinfo_struct.lighting_info.light_distance = cf_ReadFloat(infile); genericpage->objinfo_struct.lighting_info.red_light1 = cf_ReadFloat(infile); genericpage->objinfo_struct.lighting_info.green_light1 = cf_ReadFloat(infile); genericpage->objinfo_struct.lighting_info.blue_light1 = cf_ReadFloat(infile); if (version >= 2) genericpage->objinfo_struct.lighting_info.time_interval = cf_ReadFloat(infile); if (version >= 3) { genericpage->objinfo_struct.lighting_info.red_light2 = cf_ReadFloat(infile); genericpage->objinfo_struct.lighting_info.green_light2 = cf_ReadFloat(infile); genericpage->objinfo_struct.lighting_info.blue_light2 = cf_ReadFloat(infile); genericpage->objinfo_struct.lighting_info.flags = cf_ReadInt(infile); genericpage->objinfo_struct.lighting_info.timebits = cf_ReadInt(infile); genericpage->objinfo_struct.lighting_info.angle = cf_ReadByte(infile); } if (version >= 5) { genericpage->objinfo_struct.lighting_info.lighting_render_type = cf_ReadByte(infile); } else genericpage->objinfo_struct.lighting_info.lighting_render_type = LRT_STATIC; break; case GENERICPAGE_COMMAND_HITPOINTS: genericpage->objinfo_struct.hit_points = cf_ReadInt(infile); break; case GENERICPAGE_COMMAND_PHYS_MASS: genericpage->objinfo_struct.phys_info.mass = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_PHYS_DRAG: genericpage->objinfo_struct.phys_info.drag = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_ANIM_STATES: temp = cf_ReadByte(infile); { int j; for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { if (version < 20) { genericpage->anim[temp].elem[j].from = cf_ReadByte(infile); genericpage->anim[temp].elem[j].to = cf_ReadByte(infile); } else { genericpage->anim[temp].elem[j].from = cf_ReadShort(infile); genericpage->anim[temp].elem[j].to = cf_ReadShort(infile); } if (version <= 3) genericpage->anim[temp].elem[j].spc = 1.0f; else genericpage->anim[temp].elem[j].spc = cf_ReadFloat(infile); } } break; case GENERICPAGE_COMMAND_FLAGS: { int t = cf_ReadInt(infile); genericpage->objinfo_struct.flags = t; break; } case GENERICPAGE_COMMAND_WB_INFO: { int i, j; i = cf_ReadByte(infile); if (version <= 7) { for (j = 0; j < MAX_WB_GUNPOINTS; j++) genericpage->static_wb[i].gp_weapon_index[j] = cf_ReadInt(infile); genericpage->static_wb[i].aiming_gp_index = cf_ReadInt(infile); } else { for (j = 0; j < MAX_WB_GUNPOINTS; j++) genericpage->static_wb[i].gp_weapon_index[j] = cf_ReadShort(infile); genericpage->static_wb[i].aiming_gp_index = cf_ReadShort(infile); } genericpage->static_wb[i].num_masks = cf_ReadByte(infile); for (j = 0; j < MAX_WB_FIRING_MASKS; j++) genericpage->static_wb[i].gp_fire_masks[j] = cf_ReadByte(infile); for (j = 0; j < MAX_WB_FIRING_MASKS; j++) genericpage->static_wb[i].gp_fire_wait[j] = cf_ReadFloat(infile); for (j = 0; j < MAX_WB_FIRING_MASKS; j++) { if (version < 12) { genericpage->static_wb[i].anim_time[j] = 0.0f; genericpage->static_wb[i].anim_start_frame[j] = 0.0f; genericpage->static_wb[i].anim_fire_frame[j] = 0.0f; genericpage->static_wb[i].anim_end_frame[j] = 0.0f; } else { genericpage->static_wb[i].anim_time[j] = cf_ReadFloat(infile); genericpage->static_wb[i].anim_start_frame[j] = cf_ReadFloat(infile); genericpage->static_wb[i].anim_fire_frame[j] = cf_ReadFloat(infile); genericpage->static_wb[i].anim_end_frame[j] = cf_ReadFloat(infile); } } genericpage->static_wb[i].aiming_flags = cf_ReadByte(infile); genericpage->static_wb[i].aiming_3d_dot = cf_ReadFloat(infile); genericpage->static_wb[i].aiming_3d_dist = cf_ReadFloat(infile); genericpage->static_wb[i].aiming_XZ_dot = cf_ReadFloat(infile); break; } case GENERICPAGE_COMMAND_WB_QUADMASK: { for (int i = 0; i < MAX_WBS_PER_OBJ; i++) { genericpage->static_wb[i].gp_quad_fire_mask = cf_ReadByte(infile); } break; } case GENERICPAGE_COMMAND_WB_WEAPON: { int i, j; i = cf_ReadByte(infile); j = cf_ReadByte(infile); cf_ReadString(genericpage->weapon_name[i][j], len - 1, infile); break; } case GENERICPAGE_COMMAND_WB_FIRE_SOUND: { int i, j; i = cf_ReadByte(infile); j = cf_ReadByte(infile); cf_ReadString(genericpage->fire_sound_name[i][j], len - 1, infile); break; } case GENERICPAGE_COMMAND_ANIM_SOUND_NAME: { int i, j; i = cf_ReadByte(infile); j = cf_ReadByte(infile); cf_ReadString(genericpage->anim_sound_name[i][j], len - 1, infile); break; } case GENERICPAGE_COMMAND_SOUND_NAME: { int i; i = cf_ReadByte(infile); cf_ReadString(genericpage->sound_name[i], len, infile); break; } case GENERICPAGE_COMMAND_AI_SOUND_NAME: { int i; i = cf_ReadByte(infile); cf_ReadString(genericpage->ai_sound_name[i], len, infile); break; } case GENERICPAGE_COMMAND_AI_INFO: if (version <= 6) { genericpage->ai_info.flags = cf_ReadInt(infile); } else { // Makes sure there are no bugs as things are added and removed -- ask chris genericpage->ai_info.notify_flags = AI_NOTIFIES_ALWAYS_ON; genericpage->ai_info.flags = cf_ReadInt(infile); genericpage->ai_info.ai_class = cf_ReadByte(infile); genericpage->ai_info.ai_type = cf_ReadByte(infile); if (version < 13) cf_ReadInt(infile); genericpage->ai_info.movement_type = cf_ReadByte(infile); genericpage->ai_info.movement_subtype = cf_ReadByte(infile); genericpage->ai_info.fov = cf_ReadFloat(infile); if (version >= 10) { genericpage->ai_info.max_velocity = cf_ReadFloat(infile); genericpage->ai_info.max_delta_velocity = cf_ReadFloat(infile); genericpage->ai_info.max_turn_rate = cf_ReadFloat(infile); // Makes sure there are no bugs as things are added and removed -- ask chris genericpage->ai_info.notify_flags |= cf_ReadInt(infile); } if (version >= 11) { genericpage->ai_info.max_delta_turn_rate = cf_ReadFloat(infile); genericpage->ai_info.circle_distance = cf_ReadFloat(infile); genericpage->ai_info.attack_vel_percent = cf_ReadFloat(infile); genericpage->ai_info.dodge_percent = cf_ReadFloat(infile); genericpage->ai_info.dodge_vel_percent = cf_ReadFloat(infile); genericpage->ai_info.flee_vel_percent = cf_ReadFloat(infile); genericpage->ai_info.melee_damage[0] = cf_ReadFloat(infile); genericpage->ai_info.melee_damage[1] = cf_ReadFloat(infile); genericpage->ai_info.melee_latency[0] = cf_ReadFloat(infile); genericpage->ai_info.melee_latency[1] = cf_ReadFloat(infile); } else { genericpage->ai_info.max_delta_turn_rate = 16000.0; genericpage->ai_info.circle_distance = 10.0f; genericpage->ai_info.attack_vel_percent = 1.0f; genericpage->ai_info.dodge_percent = .4f; genericpage->ai_info.dodge_vel_percent = .5f; genericpage->ai_info.flee_vel_percent = 1.0f; genericpage->ai_info.melee_damage[0] = 9.0f; genericpage->ai_info.melee_damage[1] = 13.0f; genericpage->ai_info.melee_latency[0] = 3.1f; genericpage->ai_info.melee_latency[1] = 4.5f; } if (version >= 16) { genericpage->ai_info.avoid_friends_distance = cf_ReadFloat(infile); } } break; case GENERICPAGE_COMMAND_PHYS_FLAGS: genericpage->objinfo_struct.phys_info.flags = cf_ReadInt(infile); break; case GENERICPAGE_COMMAND_ROT_DRAG: genericpage->objinfo_struct.phys_info.rotdrag = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_FULL_THRUST: genericpage->objinfo_struct.phys_info.full_thrust = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_FULL_ROTTHRUST: genericpage->objinfo_struct.phys_info.full_rotthrust = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_TURNROLL_RATE: genericpage->objinfo_struct.phys_info.max_turnroll_rate = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_TURNROLL_RATIO: genericpage->objinfo_struct.phys_info.turnroll_ratio = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_WIGGLE_AMP: genericpage->objinfo_struct.phys_info.wiggle_amplitude = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_WIGGLE_FREQ: genericpage->objinfo_struct.phys_info.wiggles_per_sec = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_INT_VELOCITY: genericpage->objinfo_struct.phys_info.velocity.z = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_INT_ROTVEL: genericpage->objinfo_struct.phys_info.rotvel.x = cf_ReadFloat(infile); genericpage->objinfo_struct.phys_info.rotvel.y = cf_ReadFloat(infile); genericpage->objinfo_struct.phys_info.rotvel.z = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_NUM_BOUNCES: genericpage->objinfo_struct.phys_info.num_bounces = cf_ReadInt(infile); break; case GENERICPAGE_COMMAND_COEFF_REST: genericpage->objinfo_struct.phys_info.coeff_restitution = cf_ReadFloat(infile); break; case GENERICPAGE_COMMAND_HIT_DIE_DOT: genericpage->objinfo_struct.phys_info.hit_die_dot = cf_ReadFloat(infile); break; default: // Ignore the ones we don't know for (i = 0; i < len; i++) cf_ReadByte(infile); break; } } ASSERT(genericpage->objinfo_struct.type != OBJ_NONE); if (version < 16) { genericpage->ai_info.flags |= AIF_AUTO_AVOID_FRIENDS; genericpage->ai_info.avoid_friends_distance = genericpage->ai_info.circle_distance / 10.f; if (genericpage->ai_info.avoid_friends_distance < 4.0f) genericpage->ai_info.avoid_friends_distance = 4.0f; } if (!strnicmp("INVALID", genericpage->med_image_name, 7)) strcpy(genericpage->med_image_name, ""); if (!strnicmp("INVALID", genericpage->lo_image_name, 7)) strcpy(genericpage->lo_image_name, ""); for (i = 0; i < MAX_OBJ_SOUNDS; i++) { if (!strnicmp("INVALID", genericpage->sound_name[i], 7)) strcpy(genericpage->sound_name[i], ""); } for (i = 0; i < MAX_DSPEW_TYPES; i++) { if (!strnicmp("INVALID", genericpage->dspew_name[i], 7)) strcpy(genericpage->dspew_name[i], ""); } for (i = 0; i < MAX_AI_SOUNDS; i++) { if (!strnicmp("INVALID", genericpage->ai_sound_name[i], 7)) strcpy(genericpage->ai_sound_name[i], ""); } for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (t = 0; t < MAX_WB_FIRING_MASKS; t++) { if (!strnicmp("INVALID", genericpage->fire_sound_name[i][t], 7)) strcpy(genericpage->fire_sound_name[i][t], ""); } } for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (t = 0; t < NUM_ANIMS_PER_CLASS; t++) { if (!strnicmp("INVALID", genericpage->anim_sound_name[i][t], 7)) strcpy(genericpage->anim_sound_name[i][t], ""); } } return 1; // successfully read } // Reads in the generic named "name" into genericpage struct // Returns 0 on error or couldn't find, else 1 if all is good int mng_FindSpecificGenericPage(char *name, mngs_generic_page *genericpage, int offset) { CFILE *infile; uint8_t pagetype; int done = 0, found = 0; int first_try = 1; std::filesystem::path tablename; 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) tablename = GameArgs[farg + 1]; else tablename = LocalTableDir / NET_TABLE; infile = cfopen(tablename, "rb"); } else { infile = NULL; if (TablefileNameOverride) { infile = cfopen(TablefileNameOverride, "rb"); } if (!infile) infile = cfopen(TableFilename, "rb"); } } if (!infile) { LOG_ERROR << "Couldn't open table file to find generic!"; Int3(); return 0; } try_again:; 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 generic page, just read it in and ignore it if (pagetype != PAGETYPE_GENERIC) { cfseek(infile, len - 4, SEEK_CUR); continue; } mng_ReadNewGenericPage(infile, genericpage); if (!stricmp(name, genericpage->objinfo_struct.name)) { // This is the page we want found = 1; done = 1; } else { if (genericpage->objinfo_struct.description != NULL) { mem_free(genericpage->objinfo_struct.description); genericpage->objinfo_struct.description = NULL; } genericpage->objinfo_struct.icon_name[0] = '\0'; } } cfclose(infile); if (!found && first_try) { done = first_try = 0; infile = cfopen("extra.gam", "rb"); if (infile) goto try_again; } return found; // successful! } // Given a generic page, allocs a generic and calls AssignGenericPageTogeneric to actually // load models and values. Rturns generic handle on success, -1 if fail int mng_SetAndLoadGeneric(mngs_generic_page *genericpage, CFILE *infile) { int i, j, n; bool f_anim = false; bool f_weapons = false; bool f_ai = false; f_ai = (genericpage->objinfo_struct.flags & OIF_CONTROL_AI) ? true : false; if (f_ai) { f_weapons = f_anim = true; } else { if (genericpage->objinfo_struct.type == OBJ_ROBOT || genericpage->objinfo_struct.type == OBJ_BUILDING) { f_anim = true; } else if (genericpage->objinfo_struct.type == OBJ_POWERUP) { if (f_ai) { f_anim = true; } else { for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { if (genericpage->anim[i].elem[j].to != 0 || genericpage->anim[i].elem[j].from != 0) { f_anim = true; break; } } } } } else if (genericpage->objinfo_struct.type == OBJ_CLUTTER) { if (f_ai) { f_anim = true; } else { for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { if (genericpage->anim[i].elem[j].to != 0 || genericpage->anim[i].elem[j].from != 0) { f_anim = true; break; } } } } } for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < genericpage->static_wb[i].num_masks; j++) { if (genericpage->static_wb[i].gp_fire_masks[j] != 0) { f_weapons = true; break; } } } } if (Running_editor) { f_ai = f_weapons = f_anim = true; } n = AllocObjectID(genericpage->objinfo_struct.type, f_anim, f_weapons, f_ai); if (n < 0) return -1; if (!mng_AssignGenericPageToObjInfo(genericpage, n, infile)) return -1; return n; } // Given a genericpage and a generic handle, attempts to make generic n correspond to // to the genericpage. // Returns 1 on success, 0 otherwise int mng_AssignGenericPageToObjInfo(mngs_generic_page *genericpage, int n, CFILE *infile) { object_info *objinfopointer = &Object_info[n]; int img_handle; int i, j; // copy our values // memcpy (objinfopointer,&genericpage->objinfo_struct,sizeof(*objinfopointer)); memcpy(objinfopointer, &genericpage->objinfo_struct, sizeof(*objinfopointer) - sizeof(anim_elem *) - sizeof(otype_wb_info *) - sizeof(t_ai_info *)); strcpy(objinfopointer->name, genericpage->objinfo_struct.name); if (objinfopointer->anim) memcpy(objinfopointer->anim, &genericpage->anim, sizeof(genericpage->anim)); if (objinfopointer->static_wb) memcpy(objinfopointer->static_wb, &genericpage->static_wb, sizeof(genericpage->static_wb)); if (objinfopointer->ai_info) memcpy(objinfopointer->ai_info, &genericpage->ai_info, sizeof(genericpage->ai_info)); objinfopointer->multi_allowed = 1; // since the description pointer was just copied over, no need to malloc mem, copy and then free old, just move ptr genericpage->objinfo_struct.description = NULL; strcpy(objinfopointer->icon_name, genericpage->objinfo_struct.icon_name); // First see if our image differs from the one on the net // If it is, make a copy // If it is a release version, don't do any of this #ifndef RELEASE if (Network_up) { UpdatePrimitive(LocalModelsDir / genericpage->image_name, NetModelsDir / genericpage->image_name, genericpage->image_name, PAGETYPE_GENERIC, objinfopointer->name); if (stricmp(genericpage->med_image_name, "INVALID NAME") != 0 && genericpage->med_image_name[0] != 0) { UpdatePrimitive(LocalModelsDir / genericpage->med_image_name, NetModelsDir / genericpage->med_image_name, genericpage->med_image_name, PAGETYPE_GENERIC, objinfopointer->name); } if (stricmp(genericpage->lo_image_name, "INVALID NAME") != 0 && genericpage->lo_image_name[0] != 0) { UpdatePrimitive(LocalModelsDir / genericpage->lo_image_name, NetModelsDir / genericpage->lo_image_name, genericpage->lo_image_name, PAGETYPE_GENERIC, objinfopointer->name); } } #endif // Try and load our generic model from the disk img_handle = LoadPolyModel(genericpage->image_name, 1); if (img_handle < 0) { LOG_ERROR.printf("Couldn't load file '%s' in AssignGenericPage...", genericpage->image_name); objinfopointer->render_handle = -1; return 0; } else objinfopointer->render_handle = img_handle; if (stricmp(genericpage->med_image_name, "INVALID NAME") && genericpage->med_image_name[0] != 0) { img_handle = LoadPolyModel(genericpage->med_image_name, 1); if (img_handle < 0) { LOG_ERROR.printf("Couldn't load file '%s' in AssignGenericPage...", genericpage->med_image_name); objinfopointer->med_render_handle = -1; return 0; } else objinfopointer->med_render_handle = img_handle; } else objinfopointer->med_render_handle = -1; if (stricmp(genericpage->lo_image_name, "INVALID NAME") && genericpage->lo_image_name[0] != 0) { img_handle = LoadPolyModel(genericpage->lo_image_name, 1); if (img_handle < 0) { LOG_ERROR.printf("Couldn't load file '%s' in AssignGenericPage...", genericpage->lo_image_name); objinfopointer->lo_render_handle = -1; return 0; } else objinfopointer->lo_render_handle = img_handle; } else objinfopointer->lo_render_handle = -1; // Try and load the various sounds for (i = 0; i < MAX_OBJ_SOUNDS; i++) { if (stricmp(genericpage->sound_name[i], "INVALID NAME") && genericpage->sound_name[i][0] != 0) { int sound_handle = mng_GetGuaranteedSoundPage(genericpage->sound_name[i]); if (sound_handle < 0) { LOG_WARNING.printf("Couldn't load sound file '%s' in AssignPowPage %s...", genericpage->sound_name[i], genericpage->objinfo_struct.name); objinfopointer->sounds[i] = SOUND_NONE_INDEX; } else objinfopointer->sounds[i] = sound_handle; } else objinfopointer->sounds[i] = SOUND_NONE_INDEX; } for (i = 0; i < MAX_DSPEW_TYPES; i++) { if (genericpage->dspew_name[i][0] != '\0') { int obj_handle = mng_GetGuaranteedGenericPage(genericpage->dspew_name[i], infile); if (obj_handle < 0) { objinfopointer->dspew[i] = 0; objinfopointer->dspew_number[i] = 0; objinfopointer->dspew_percent[i] = 0.0f; } else { objinfopointer->dspew[i] = obj_handle; } } else { objinfopointer->dspew[i] = -1; objinfopointer->dspew_number[i] = 0; objinfopointer->dspew_percent[i] = 0.0f; } } // Try and load the various sounds if (objinfopointer->ai_info) { for (i = 0; i < MAX_AI_SOUNDS; i++) { if (stricmp(genericpage->ai_sound_name[i], "INVALID NAME") && genericpage->ai_sound_name[i][0] != 0) { int sound_handle = mng_GetGuaranteedSoundPage(genericpage->ai_sound_name[i]); if (sound_handle < 0) { LOG_ERROR.printf("Couldn't load ai sound file '%s' in AssignPowPage %s...", genericpage->ai_sound_name[i], genericpage->objinfo_struct.name); objinfopointer->ai_info->sound[i] = SOUND_NONE_INDEX; } else objinfopointer->ai_info->sound[i] = sound_handle; } else objinfopointer->ai_info->sound[i] = SOUND_NONE_INDEX; } } // Try and load the various weapons if (objinfopointer->static_wb) { for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_GUNPOINTS; j++) { if (genericpage->weapon_name[i][j][0] != '\0') { int weapon_handle = mng_GetGuaranteedWeaponPage(genericpage->weapon_name[i][j]); if (weapon_handle < 0) { LOG_ERROR.printf("Couldn't load weapon file '%s' in AssignPowPage %s...", genericpage->weapon_name[i][j], genericpage->objinfo_struct.name); objinfopointer->static_wb[i].gp_weapon_index[j] = LASER_INDEX; } else objinfopointer->static_wb[i].gp_weapon_index[j] = weapon_handle; } else objinfopointer->static_wb[i].gp_weapon_index[j] = LASER_INDEX; } } // Try and load the various wb sounds for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_FIRING_MASKS; j++) { if (genericpage->fire_sound_name[i][j][0] != '\0') { int fire_sound_handle = mng_GetGuaranteedSoundPage(genericpage->fire_sound_name[i][j]); if (fire_sound_handle < 0) { LOG_ERROR.printf("Couldn't load fire sound file '%s' in AssignPowPage %s...", genericpage->fire_sound_name[i][j], genericpage->objinfo_struct.name); objinfopointer->static_wb[i].fm_fire_sound_index[j] = SOUND_NONE_INDEX; } else objinfopointer->static_wb[i].fm_fire_sound_index[j] = fire_sound_handle; } else objinfopointer->static_wb[i].fm_fire_sound_index[j] = SOUND_NONE_INDEX; } } } // Try and load the various wb sounds if (objinfopointer->anim) { for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { if (stricmp(genericpage->anim_sound_name[i][j], "INVALID NAME") && genericpage->anim_sound_name[i][j][0] != 0) { int anim_sound_handle = mng_GetGuaranteedSoundPage(genericpage->anim_sound_name[i][j]); if (anim_sound_handle < 0) { LOG_ERROR.printf("Couldn't load anim sound file '%s' in AssignPowPage %s...", genericpage->anim_sound_name[i][j], genericpage->objinfo_struct.name); objinfopointer->anim[i].elem[j].anim_sound_index = SOUND_NONE_INDEX; } else objinfopointer->anim[i].elem[j].anim_sound_index = anim_sound_handle; } else objinfopointer->anim[i].elem[j].anim_sound_index = SOUND_NONE_INDEX; } } } // objinfopointer->size=(ComputeDefaultSize(objinfopointer->render_handle, &objinfopointer->size_offset, 0, 0)); return 1; } // Copies values from a generic into a generic_page void mng_AssignObjInfoToGenericPage(int n, mngs_generic_page *genericpage) { object_info *objinfopointer = &Object_info[n]; int i, j; // Assign the values memcpy(&genericpage->objinfo_struct, objinfopointer, sizeof(*objinfopointer)); strcpy(genericpage->objinfo_struct.name, objinfopointer->name); if (objinfopointer->anim) memcpy(&genericpage->anim, objinfopointer->anim, sizeof(genericpage->anim)); if (objinfopointer->static_wb) memcpy(&genericpage->static_wb, objinfopointer->static_wb, sizeof(genericpage->static_wb)); if (objinfopointer->ai_info) memcpy(&genericpage->ai_info, objinfopointer->ai_info, sizeof(genericpage->ai_info)); if (objinfopointer->description != NULL) { int len = strlen(objinfopointer->description); genericpage->objinfo_struct.description = (char *)mem_malloc(len + 1); ASSERT(genericpage->objinfo_struct.description); strcpy(genericpage->objinfo_struct.description, objinfopointer->description); } else genericpage->objinfo_struct.description = NULL; strcpy(genericpage->objinfo_struct.icon_name, objinfopointer->icon_name); if (objinfopointer->render_handle != -1) strcpy(genericpage->image_name, Poly_models[objinfopointer->render_handle].name); else strcpy(genericpage->image_name, ""); if (objinfopointer->med_render_handle != -1) strcpy(genericpage->med_image_name, Poly_models[objinfopointer->med_render_handle].name); else strcpy(genericpage->med_image_name, ""); if (objinfopointer->lo_render_handle != -1) strcpy(genericpage->lo_image_name, Poly_models[objinfopointer->lo_render_handle].name); else strcpy(genericpage->lo_image_name, ""); for (i = 0; i < MAX_OBJ_SOUNDS; i++) { if (objinfopointer->sounds[i] != SOUND_NONE_INDEX) strcpy(genericpage->sound_name[i], Sounds[objinfopointer->sounds[i]].name); else strcpy(genericpage->sound_name[i], ""); } for (i = 0; i < MAX_DSPEW_TYPES; i++) { if ((objinfopointer->dspew[i] != -1) && Object_info[objinfopointer->dspew[i]].type != OBJ_NONE) strcpy(genericpage->dspew_name[i], Object_info[objinfopointer->dspew[i]].name); else strcpy(genericpage->dspew_name[i], "\0"); } for (i = 0; i < MAX_AI_SOUNDS; i++) { if (objinfopointer->ai_info && objinfopointer->ai_info->sound[i] != SOUND_NONE_INDEX) strcpy(genericpage->ai_sound_name[i], Sounds[objinfopointer->ai_info->sound[i]].name); else strcpy(genericpage->ai_sound_name[i], ""); } for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_FIRING_MASKS; j++) { if (objinfopointer->static_wb && objinfopointer->static_wb[i].fm_fire_sound_index[j] >= 0) strcpy(genericpage->fire_sound_name[i][j], Sounds[objinfopointer->static_wb[i].fm_fire_sound_index[j]].name); else strcpy(genericpage->fire_sound_name[i][j], ""); } } for (i = 0; i < NUM_MOVEMENT_CLASSES; i++) { for (j = 0; j < NUM_ANIMS_PER_CLASS; j++) { if (objinfopointer->anim && objinfopointer->anim[i].elem[j].anim_sound_index >= 0) strcpy(genericpage->anim_sound_name[i][j], Sounds[objinfopointer->anim[i].elem[j].anim_sound_index].name); else strcpy(genericpage->anim_sound_name[i][j], ""); } } for (i = 0; i < MAX_WBS_PER_OBJ; i++) { for (j = 0; j < MAX_WB_GUNPOINTS; j++) { if (objinfopointer->static_wb && objinfopointer->static_wb[i].gp_weapon_index[j] >= 0) strcpy(genericpage->weapon_name[i][j], Weapons[objinfopointer->static_wb[i].gp_weapon_index[j]].name); else strcpy(genericpage->weapon_name[i][j], "Laser"); } } } // Loads a generic found in the net table file. It then allocs a generic and // then calls SetAndLoadgeneric to actually load in any images/models associated // with it void mng_LoadNetGenericPage(CFILE *infile, bool overlay) { mngs_generic_page genericpage; memset(&genericpage, 0, sizeof(mngs_generic_page)); if (mng_ReadNewGenericPage(infile, &genericpage)) { int n = FindObjectIDName(genericpage.objinfo_struct.name); if (n != -1) { if (overlay) { LOG_DEBUG.printf("OVERLAYING GENERIC %s", genericpage.objinfo_struct.name); mng_FreePagetypePrimitives(PAGETYPE_GENERIC, genericpage.objinfo_struct.name, 0); mng_AssignGenericPageToObjInfo(&genericpage, n); } return; // A weapon has already loaded this generic } int ret = mng_SetAndLoadGeneric(&genericpage, infile); ASSERT(ret >= 0); } else LOG_ERROR.printf("Could not load genericpage named %s!", genericpage.objinfo_struct.name); } // Reads a generic page from a local table file. It then allocs a generic and // loads any images/models associated with that generic void mng_LoadLocalGenericPage(CFILE *infile) { mngs_generic_page genericpage; int ok = 0; memset(&genericpage, 0, sizeof(mngs_generic_page)); if (mng_ReadNewGenericPage(infile, &genericpage)) { // Check to see if this is a local copy that is supposed // to go over a network copy (supersede the net copy) int i = FindObjectIDName(genericpage.objinfo_struct.name); if (i != -1) { // Make sure we really have this page checked out mngs_Pagelock pl; strcpy(pl.name, genericpage.objinfo_struct.name); pl.pagetype = PAGETYPE_GENERIC; /*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_GENERIC && !stricmp(addon->Addon_tracklocks[tidx].name, genericpage.objinfo_struct.name)) { // found it!! LOG_DEBUG.printf("GenericPage: %s previously loaded", genericpage.objinfo_struct.name); need_to_load_page = false; break; } } } if (need_to_load_page) { mng_FreePagetypePrimitives(PAGETYPE_GENERIC, genericpage.objinfo_struct.name, 0); mng_AssignGenericPageToObjInfo(&genericpage, i); // For addon data if (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_GENERIC && !stricmp(addon->Addon_tracklocks[tidx].name, genericpage.objinfo_struct.name)) { // found it!! found = true; overlay = addidx + 2; break; } } if (found) break; } mng_PushAddonPage(PAGETYPE_GENERIC, genericpage.objinfo_struct.name, overlay); } } } else { // This is a local generic that has never been checked in if ((i = mng_SetAndLoadGeneric(&genericpage)) < 0) ok = 0; else ok = 1; // For addon data if (ok && Loading_addon_table != -1) mng_PushAddonPage(PAGETYPE_GENERIC, genericpage.objinfo_struct.name, 0); } ASSERT(ok == 1); if (Loading_addon_table == -1) mng_AllocTrackLock(genericpage.objinfo_struct.name, PAGETYPE_GENERIC); } else { LOG_ERROR.printf("Could not load genericpage named %s!", genericpage.objinfo_struct.name); } } // First searches through the object index to see if the object is already // loaded. If not, searches in the table file and loads it. // Returns index of object found, -1 if not int mng_GetGuaranteedGenericPage(char *name, CFILE *infile) { int i; mngs_generic_page page; // See if it is in memory i = FindObjectIDName(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_FindSpecificGenericPage(name, &page, infile ? infile->position : 0); if (!ret) return -1; // We've found it in the table file, now load it. ret = mng_SetAndLoadGeneric(&page); ASSERT(ret >= 0); if (Loading_addon_table != -1) { // we're loading addon table pages, this will not overlay anything mng_PushAddonPage(PAGETYPE_GENERIC, page.objinfo_struct.name, 0); } return ret; }