/* * PARSEC - Object Info Commands * * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:34 $ * * Orginally written by: * Copyright (c) Markus Hadwiger 1996-2000 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // C library #include #include #include #include #include // compilation flags/debug support #include "config.h" #include "debug.h" // general definitions #include "general.h" #include "objstruc.h" #include "od_class.h" #include "od_props.h" // global externals #include "globals.h" // local module header #include "con_info.h" // proprietary module headers #include "con_arg.h" #include "con_aux.h" #include "con_int.h" #include "con_main.h" #include "con_std.h" #include "e_supp.h" #include "obj_clas.h" #include "obj_comm.h" #include "obj_ctrl.h" #include "obj_cust.h" // generic string paste area -------------------------------------------------- // #define PASTE_STR_LEN 1023 static char paste_str[ PASTE_STR_LEN + 1 ]; // string constants ----------------------------------------------------------- // static const char prop_syntax[] = "syntax: prop . "; static const char propc_syntax[] = "syntax: propc . "; static const char propo_syntax[] = "syntax: propo . "; static const char prop_wrong_type[] = "invalid type name."; static const char prop_wrong_class[] = "invalid class name."; static const char prop_objid_syntax[] = "object id must be an int."; static const char prop_no_object[] = "no object with this id."; static const char prop_wrong_field[] = "invalid property name."; static const char typeinfo_syntax[] = "syntax: typeinfo "; static const char classinfo_syntax[] = "syntax: classinfo "; static const char objectinfo_syntax[] = "syntax: objectinfo "; static const char class_not_loaded[] = "class is not loaded."; static const char no_objs_of_type[] = "there are no objects of this type."; static const char not_accessible[] = "properties of this type are not accessible."; static const char face_id_invalid[] = "face id invalid."; static const char no_texture_found[] = "texture invalid."; static const char no_face_selected[] = "no face selection specified."; static const char base_object_empty[] = "base object is empty."; // property access type specification ----------------------------------------- // #define ACCESSTYPE_INT 0 // access property value as int #define ACCESSTYPE_FLOAT 1 // access property value as float #define ACCESSTYPE_STRING 2 // access property value as char[] #define ACCESSTYPE_CHARPTR 3 // access property value as char* // property lists for default types ------------------------------------------- // #define Ship1Obj_CurDamage offsetof( ShipObject, CurDamage ) #define Ship1Obj_MaxDamage offsetof( ShipObject, MaxDamage ) #define Ship1Obj_Energy offsetof( ShipObject, CurEnergy ) #define Ship1Obj_MaxEnergy offsetof( ShipObject, MaxEnergy ) #define Ship1Obj_CurSpeed offsetof( ShipObject, CurSpeed ) #define Ship1Obj_MaxSpeed offsetof( ShipObject, MaxSpeed ) #define Ship1Obj_Weapons offsetof( ShipObject, Weapons ) #define Ship1Obj_Specials offsetof( ShipObject, Specials ) #define Ship1Obj_NumMissls offsetof( ShipObject, NumMissls ) #define Ship1Obj_MaxNumMissls offsetof( ShipObject, MaxNumMissls ) #define Ship1Obj_NumHomMissls offsetof( ShipObject, NumHomMissls ) #define Ship1Obj_MaxNumHomMissls offsetof( ShipObject, MaxNumHomMissls ) #define Ship1Obj_NumPartMissls offsetof( ShipObject, NumPartMissls ) #define Ship1Obj_MaxNumPartMissls offsetof( ShipObject, MaxNumPartMissls ) #define Ship1Obj_NumMines offsetof( ShipObject, NumMines ) #define Ship1Obj_MaxNumMines offsetof( ShipObject, MaxNumMines ) #define Ship1Obj_YawPerRefFrame offsetof( ShipObject, YawPerRefFrame ) #define Ship1Obj_PitchPerRefFrame offsetof( ShipObject, PitchPerRefFrame ) #define Ship1Obj_RollPerRefFrame offsetof( ShipObject, RollPerRefFrame ) #define Ship1Obj_XSlidePerRefFrame offsetof( ShipObject, XSlidePerRefFrame ) #define Ship1Obj_YSlidePerRefFrame offsetof( ShipObject, YSlidePerRefFrame ) #define Ship1Obj_SpeedIncPerRefFrame offsetof( ShipObject, SpeedIncPerRefFrame ) #define Ship1Obj_SpeedDecPerRefFrame offsetof( ShipObject, SpeedDecPerRefFrame ) #define Ship1Obj_FireRepeatDelay offsetof( ShipObject, FireRepeatDelay ) #define Ship1Obj_FireDisableDelay offsetof( ShipObject, FireDisableDelay ) #define Ship1Obj_MissileDisableDelay offsetof( ShipObject, MissileDisableDelay ) #define Ship1Obj_Laser1X1 offsetof( ShipObject, Laser1_X ) #define Ship1Obj_Laser1X2 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Laser1X3 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Laser1X4 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Laser2X1 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 4 ) #define Ship1Obj_Laser2X2 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 5 ) #define Ship1Obj_Laser2X3 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 6 ) #define Ship1Obj_Laser2X4 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 7 ) #define Ship1Obj_Laser3X1 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 8 ) #define Ship1Obj_Laser3X2 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 9 ) #define Ship1Obj_Laser3X3 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 10 ) #define Ship1Obj_Laser3X4 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 11 ) #define Ship1Obj_Laser4X1 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 12 ) #define Ship1Obj_Laser4X2 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 13 ) #define Ship1Obj_Laser4X3 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 14 ) #define Ship1Obj_Laser4X4 ( offsetof( ShipObject, Laser1_X ) + sizeof( geomv_t ) * 15 ) #define Ship1Obj_Laser1Y1 offsetof( ShipObject, Laser1_Y ) #define Ship1Obj_Laser1Y2 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Laser1Y3 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Laser1Y4 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Laser2Y1 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 4 ) #define Ship1Obj_Laser2Y2 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 5 ) #define Ship1Obj_Laser2Y3 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 6 ) #define Ship1Obj_Laser2Y4 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 7 ) #define Ship1Obj_Laser3Y1 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 8 ) #define Ship1Obj_Laser3Y2 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 9 ) #define Ship1Obj_Laser3Y3 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 10 ) #define Ship1Obj_Laser3Y4 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 11 ) #define Ship1Obj_Laser4Y1 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 12 ) #define Ship1Obj_Laser4Y2 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 13 ) #define Ship1Obj_Laser4Y3 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 14 ) #define Ship1Obj_Laser4Y4 ( offsetof( ShipObject, Laser1_Y ) + sizeof( geomv_t ) * 15 ) #define Ship1Obj_Laser1Z1 offsetof( ShipObject, Laser1_Z ) #define Ship1Obj_Laser1Z2 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Laser1Z3 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Laser1Z4 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Laser2Z1 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 4 ) #define Ship1Obj_Laser2Z2 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 5 ) #define Ship1Obj_Laser2Z3 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 6 ) #define Ship1Obj_Laser2Z4 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 7 ) #define Ship1Obj_Laser3Z1 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 8 ) #define Ship1Obj_Laser3Z2 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 9 ) #define Ship1Obj_Laser3Z3 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 10 ) #define Ship1Obj_Laser3Z4 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 11 ) #define Ship1Obj_Laser4Z1 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 12 ) #define Ship1Obj_Laser4Z2 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 13 ) #define Ship1Obj_Laser4Z3 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 14 ) #define Ship1Obj_Laser4Z4 ( offsetof( ShipObject, Laser1_Z ) + sizeof( geomv_t ) * 15 ) #define Ship1Obj_Missile1X1 offsetof( ShipObject, Missile1_X ) #define Ship1Obj_Missile1X2 ( offsetof( ShipObject, Missile1_X ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Missile1X3 ( offsetof( ShipObject, Missile1_X ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Missile1X4 ( offsetof( ShipObject, Missile1_X ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Missile1Y1 offsetof( ShipObject, Missile1_Y ) #define Ship1Obj_Missile1Y2 ( offsetof( ShipObject, Missile1_Y ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Missile1Y3 ( offsetof( ShipObject, Missile1_Y ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Missile1Y4 ( offsetof( ShipObject, Missile1_Y ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Missile1Z1 offsetof( ShipObject, Missile1_Z ) #define Ship1Obj_Missile1Z2 ( offsetof( ShipObject, Missile1_Z ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Missile1Z3 ( offsetof( ShipObject, Missile1_Z ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Missile1Z4 ( offsetof( ShipObject, Missile1_Z ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Missile2X1 offsetof( ShipObject, Missile2_X ) #define Ship1Obj_Missile2X2 ( offsetof( ShipObject, Missile2_X ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Missile2X3 ( offsetof( ShipObject, Missile2_X ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Missile2X4 ( offsetof( ShipObject, Missile2_X ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Missile2Y1 offsetof( ShipObject, Missile2_Y ) #define Ship1Obj_Missile2Y2 ( offsetof( ShipObject, Missile2_Y ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Missile2Y3 ( offsetof( ShipObject, Missile2_Y ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Missile2Y4 ( offsetof( ShipObject, Missile2_Y ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Missile2Z1 offsetof( ShipObject, Missile2_Z ) #define Ship1Obj_Missile2Z2 ( offsetof( ShipObject, Missile2_Z ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_Missile2Z3 ( offsetof( ShipObject, Missile2_Z ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_Missile2Z4 ( offsetof( ShipObject, Missile2_Z ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_Mine1X offsetof( ShipObject, Mine1_X ) #define Ship1Obj_Mine1Y offsetof( ShipObject, Mine1_Y ) #define Ship1Obj_Mine1Z offsetof( ShipObject, Mine1_Z ) #define Ship1Obj_BeamX1 offsetof( ShipObject, Beam_X ) #define Ship1Obj_BeamX2 ( offsetof( ShipObject, Beam_X ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_BeamX3 ( offsetof( ShipObject, Beam_X ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_BeamX4 ( offsetof( ShipObject, Beam_X ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_BeamY offsetof( ShipObject, Beam_Y ) #define Ship1Obj_BeamZ offsetof( ShipObject, Beam_Z ) #define Ship1Obj_SpreadX1 offsetof( ShipObject, Spread_X ) #define Ship1Obj_SpreadX2 ( offsetof( ShipObject, Spread_X ) + sizeof( geomv_t ) * 1 ) #define Ship1Obj_SpreadX3 ( offsetof( ShipObject, Spread_X ) + sizeof( geomv_t ) * 2 ) #define Ship1Obj_SpreadX4 ( offsetof( ShipObject, Spread_X ) + sizeof( geomv_t ) * 3 ) #define Ship1Obj_SpreadY offsetof( ShipObject, Spread_Y ) #define Ship1Obj_SpreadZ offsetof( ShipObject, Spread_Z ) #define Ship1Obj_SpreadSpeed offsetof( ShipObject, SpreadSpeed ) #define Ship1Obj_SpreadLifeTime offsetof( ShipObject, SpreadLifeTime ) #define Ship1Obj_HelixX offsetof( ShipObject, Helix_X ) #define Ship1Obj_HelixY offsetof( ShipObject, Helix_Y ) #define Ship1Obj_HelixZ offsetof( ShipObject, Helix_Z ) #define Ship1Obj_HelixSpeed offsetof( ShipObject, HelixSpeed ) #define Ship1Obj_HelixLifeTime offsetof( ShipObject, HelixLifeTime ) #define Ship1Obj_PhotonSpeed offsetof( ShipObject, PhotonSpeed ) #define Ship1Obj_PhotonLifeTime offsetof( ShipObject, PhotonLifeTime ) #define Laser1_LifeTimeCount offsetof( LaserObject, LifeTimeCount ) #define Laser1_Speed offsetof( LaserObject, Speed ) #define Laser1_HitPoints offsetof( LaserObject, HitPoints ) #define Laser1_EnergyNeeded offsetof( LaserObject, EnergyNeeded ) #define Missile1_LifeTimeCount offsetof( MissileObject, LifeTimeCount ) #define Missile1_Speed offsetof( MissileObject, Speed ) #define Missile1_HitPoints offsetof( MissileObject, HitPoints ) #define Missile4_Latency offsetof( TargetMissileObject, Latency ) #define Missile4_MaxRotation offsetof( TargetMissileObject, MaxRotation ) #define Extra1_LifeTimeCount offsetof( ExtraObject, LifeTimeCount ) #define Extra1_SelfRotX offsetof( ExtraObject, SelfRotX ) #define Extra1_SelfRotY offsetof( ExtraObject, SelfRotY ) #define Extra1_SelfRotZ offsetof( ExtraObject, SelfRotZ ) #define Mine1_HitPoints offsetof( MineObject, HitPoints ) //NOTE: // bmin and bmax (value bounds) for all types other than // PROPTYPE_INT have to be specified in fixed-point! //NOTE: // not all fields of struct proplist_s will be set explicitly // in the following arrays. the remaining fields will be NULL. // THEIR OFF-STATES HAVE TO BE NULL/ZERO. PRIVATE proplist_s Ship1_PropList[] = { { "damage", Ship1Obj_CurDamage, 1, 500, PROPTYPE_INT }, { "maxdamage", Ship1Obj_MaxDamage, 1, 500, PROPTYPE_INT }, { "energy", Ship1Obj_Energy, 1, 10000, PROPTYPE_INT }, { "maxenergy", Ship1Obj_MaxEnergy, 1, 10000, PROPTYPE_INT }, { "speed", Ship1Obj_CurSpeed, 1, 100000, PROPTYPE_INT }, { "maxspeed", Ship1Obj_MaxSpeed, 1, 100000, PROPTYPE_INT }, { "weapons", Ship1Obj_Weapons, 0, 0x70007, PROPTYPE_INT }, { "specials", Ship1Obj_Specials, 0, 0xfffff, PROPTYPE_INT }, { "dumb", Ship1Obj_NumMissls, 0, 99, PROPTYPE_INT }, { "maxdumb", Ship1Obj_MaxNumMissls, 0, 99, PROPTYPE_INT }, { "guide", Ship1Obj_NumHomMissls, 0, 99, PROPTYPE_INT }, { "maxguide", Ship1Obj_MaxNumHomMissls, 0, 99, PROPTYPE_INT }, { "swarm", Ship1Obj_NumPartMissls, 0, 99, PROPTYPE_INT }, { "maxswarm", Ship1Obj_MaxNumPartMissls, 0, 99, PROPTYPE_INT }, { "mines", Ship1Obj_NumMines, 0, 99, PROPTYPE_INT }, { "maxmines", Ship1Obj_MaxNumMines, 0, 99, PROPTYPE_INT }, { "yawperref", Ship1Obj_YawPerRefFrame, 0, 100, PROPTYPE_INT }, { "pitchperref", Ship1Obj_PitchPerRefFrame, 0, 100, PROPTYPE_INT }, { "rollperref", Ship1Obj_RollPerRefFrame, 0, 100, PROPTYPE_INT }, { "xslideperref", Ship1Obj_XSlidePerRefFrame, 0, 0x7fffffff, PROPTYPE_GEOMV }, { "yslideperref", Ship1Obj_YSlidePerRefFrame, 0, 0x7fffffff, PROPTYPE_GEOMV }, { "speedincperref", Ship1Obj_SpeedIncPerRefFrame, 0, 0xffff, PROPTYPE_INT }, { "speeddecperref", Ship1Obj_SpeedDecPerRefFrame, 0, 0xffff, PROPTYPE_INT }, { "firerepdelay", Ship1Obj_FireRepeatDelay, 0, 500, PROPTYPE_INT }, { "firedisdelay", Ship1Obj_FireDisableDelay, 0, 500, PROPTYPE_INT }, { "missdisdelay", Ship1Obj_MissileDisableDelay, 0, 500, PROPTYPE_INT }, { "laser1.x1", Ship1Obj_Laser1X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.x2", Ship1Obj_Laser1X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.x3", Ship1Obj_Laser1X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.x4", Ship1Obj_Laser1X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.y1", Ship1Obj_Laser1Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.y2", Ship1Obj_Laser1Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.y3", Ship1Obj_Laser1Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.y4", Ship1Obj_Laser1Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.z1", Ship1Obj_Laser1Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.z2", Ship1Obj_Laser1Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.z3", Ship1Obj_Laser1Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser1.z4", Ship1Obj_Laser1Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.x1", Ship1Obj_Laser2X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.x2", Ship1Obj_Laser2X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.x3", Ship1Obj_Laser2X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.x4", Ship1Obj_Laser2X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.y1", Ship1Obj_Laser2Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.y2", Ship1Obj_Laser2Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.y3", Ship1Obj_Laser2Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.y4", Ship1Obj_Laser2Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.z1", Ship1Obj_Laser2Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.z2", Ship1Obj_Laser2Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.z3", Ship1Obj_Laser2Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser2.z4", Ship1Obj_Laser2Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x1", Ship1Obj_Laser3X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x2", Ship1Obj_Laser3X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x3", Ship1Obj_Laser3X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x4", Ship1Obj_Laser3X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y1", Ship1Obj_Laser3Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y2", Ship1Obj_Laser3Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y3", Ship1Obj_Laser3Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y4", Ship1Obj_Laser3Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z1", Ship1Obj_Laser3Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z2", Ship1Obj_Laser3Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z3", Ship1Obj_Laser3Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z4", Ship1Obj_Laser3Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x1", Ship1Obj_Laser3X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x2", Ship1Obj_Laser3X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x3", Ship1Obj_Laser3X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.x4", Ship1Obj_Laser3X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y1", Ship1Obj_Laser3Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y2", Ship1Obj_Laser3Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y3", Ship1Obj_Laser3Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.y4", Ship1Obj_Laser3Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z1", Ship1Obj_Laser3Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z2", Ship1Obj_Laser3Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z3", Ship1Obj_Laser3Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser3.z4", Ship1Obj_Laser3Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.x1", Ship1Obj_Laser4X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.x2", Ship1Obj_Laser4X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.x3", Ship1Obj_Laser4X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.x4", Ship1Obj_Laser4X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.y1", Ship1Obj_Laser4Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.y2", Ship1Obj_Laser4Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.y3", Ship1Obj_Laser4Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.y4", Ship1Obj_Laser4Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.z1", Ship1Obj_Laser4Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.z2", Ship1Obj_Laser4Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.z3", Ship1Obj_Laser4Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "laser4.z4", Ship1Obj_Laser4Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.x1", Ship1Obj_Missile1X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.x2", Ship1Obj_Missile1X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.x3", Ship1Obj_Missile1X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.x4", Ship1Obj_Missile1X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.y1", Ship1Obj_Missile1Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.y2", Ship1Obj_Missile1Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.y3", Ship1Obj_Missile1Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.y4", Ship1Obj_Missile1Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.z1", Ship1Obj_Missile1Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.z2", Ship1Obj_Missile1Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.z3", Ship1Obj_Missile1Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile1.z4", Ship1Obj_Missile1Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.x1", Ship1Obj_Missile2X1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.x2", Ship1Obj_Missile2X2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.x3", Ship1Obj_Missile2X3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.x4", Ship1Obj_Missile2X4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.y1", Ship1Obj_Missile2Y1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.y2", Ship1Obj_Missile2Y2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.y3", Ship1Obj_Missile2Y3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.y4", Ship1Obj_Missile2Y4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.z1", Ship1Obj_Missile2Z1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.z2", Ship1Obj_Missile2Z2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.z3", Ship1Obj_Missile2Z3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "missile2.z4", Ship1Obj_Missile2Z4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "mine1.x", Ship1Obj_Mine1X, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "mine1.y", Ship1Obj_Mine1Y, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "mine1.z", Ship1Obj_Mine1Z, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "beam.x1", Ship1Obj_BeamX1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "beam.x2", Ship1Obj_BeamX2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "beam.x3", Ship1Obj_BeamX3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "beam.x4", Ship1Obj_BeamX4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "beam.y", Ship1Obj_BeamY, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "beam.z", Ship1Obj_BeamZ, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spread.x1", Ship1Obj_SpreadX1, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spread.x2", Ship1Obj_SpreadX2, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spread.x3", Ship1Obj_SpreadX3, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spread.x4", Ship1Obj_SpreadX4, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spread.y", Ship1Obj_SpreadY, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spread.z", Ship1Obj_SpreadZ, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "spreadspeed", Ship1Obj_SpreadSpeed, 0, 0x1000000, PROPTYPE_INT }, { "spreadlifetime", Ship1Obj_SpreadLifeTime, 0, 0x1000000, PROPTYPE_INT }, { "helix.x", Ship1Obj_HelixX, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "helix.y", Ship1Obj_HelixY, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "helix.z", Ship1Obj_HelixZ, -0x7fffffff, 0x7fffffff, PROPTYPE_GEOMV }, { "helixspeed", Ship1Obj_HelixSpeed, 0, 0x1000000, PROPTYPE_INT }, { "helixlifetime", Ship1Obj_HelixLifeTime, 0, 0x1000000, PROPTYPE_INT }, { "photonspeed", Ship1Obj_PhotonSpeed, 0, 0x1000000, PROPTYPE_INT }, { "photonlifetime", Ship1Obj_PhotonLifeTime, 0, 0x1000000, PROPTYPE_INT }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Laser1_PropList[] = { { "lifetime", Laser1_LifeTimeCount, 100, 100000, 0 }, { "speed", Laser1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Laser1_HitPoints, 0, 100, 0 }, { "energy", Laser1_EnergyNeeded, 0, 100, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Laser2_PropList[] = { { "lifetime", Laser1_LifeTimeCount, 100, 100000, 0 }, { "speed", Laser1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Laser1_HitPoints, 0, 200, 0 }, { "energy", Laser1_EnergyNeeded, 0, 100, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Laser3_PropList[] = { { "lifetime", Laser1_LifeTimeCount, 100, 100000, 0 }, { "speed", Laser1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Laser1_HitPoints, 0, 1000, 0 }, { "energy", Laser1_EnergyNeeded, 0, 100, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Missile1_PropList[] = { { "lifetime", Missile1_LifeTimeCount, 100, 100000, 0 }, { "speed", Missile1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Missile1_HitPoints, 0, 100, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Missile2_PropList[] = { { "lifetime", Missile1_LifeTimeCount, 100, 100000, 0 }, { "speed", Missile1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Missile1_HitPoints, 0, 100, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Missile3_PropList[] = { { "lifetime", Missile1_LifeTimeCount, 100, 100000, 0 }, { "speed", Missile1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Missile1_HitPoints, 0, 100, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Missile4_PropList[] = { { "lifetime", Missile1_LifeTimeCount, 100, 100000, 0 }, { "speed", Missile1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Missile1_HitPoints, 0, 100, 0 }, { "latency", Missile4_Latency, 0, 200, 0 }, { "maxrot", Missile4_MaxRotation, 0, 0x10000, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Missile5_PropList[] = { { "lifetime", Missile1_LifeTimeCount, 100, 100000, 0 }, { "speed", Missile1_Speed, 0, 0xa0000, 0 }, { "hitpoints", Missile1_HitPoints, 0, 100, 0 }, { "latency", Missile4_Latency, 0, 200, 0 }, { "maxrot", Missile4_MaxRotation, 0, 0x10000, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Extra1_PropList[] = { { "lifetime", Extra1_LifeTimeCount, 0, 100000, 0 }, { "rotx", Extra1_SelfRotX, 0, 0x200, 0 }, { "roty", Extra1_SelfRotY, 0, 0x200, 0 }, { "rotz", Extra1_SelfRotZ, 0, 0x200, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Extra2_PropList[] = { { "lifetime", Extra1_LifeTimeCount, 0, 100000, 0 }, { "rotx", Extra1_SelfRotX, 0, 0x200, 0 }, { "roty", Extra1_SelfRotY, 0, 0x200, 0 }, { "rotz", Extra1_SelfRotZ, 0, 0x200, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Extra3_PropList[] = { { "lifetime", Extra1_LifeTimeCount, 0, 100000, 0 }, { "rotx", Extra1_SelfRotX, 0, 0x200, 0 }, { "roty", Extra1_SelfRotY, 0, 0x200, 0 }, { "rotz", Extra1_SelfRotZ, 0, 0x200, 0 }, { NULL, 0, 0, 0, 0 } }; PRIVATE proplist_s Mine1_PropList[] = { { "lifetime", Extra1_LifeTimeCount, 0, 100000, 0 }, { "rotx", Extra1_SelfRotX, 0, 0x200, 0 }, { "roty", Extra1_SelfRotY, 0, 0x200, 0 }, { "rotz", Extra1_SelfRotZ, 0, 0x200, 0 }, { "hitpoints", Mine1_HitPoints, 0, 1000, 0 }, { NULL, 0, 0, 0, 0 } }; // convert default types to proplist_s pointers ------------------------------- // PRIVATE proplist_s *default_types_proplists[ NUM_DISTINCT_OBJTYPES ] = { Ship1_PropList, // SHIP_1 Ship1_PropList, // SHIP_2 Laser1_PropList, // LASER_1 Laser2_PropList, // LASER_2 Laser3_PropList, // LASER_3 Missile1_PropList, // MISSL_1 Missile2_PropList, // MISSL_2 Missile3_PropList, // MISSL_3 Missile4_PropList, // MISSL_4 Missile5_PropList, // MISSL_5 Extra1_PropList, // EXTRA_1 Extra2_PropList, // EXTRA_2 Extra3_PropList, // EXTRA_3 Mine1_PropList, // MINE_1 }; // registered proplists for custom types -------------------------------------- // PRIVATE proplist_s *custom_types_proplists[ MAX_NUM_CUSTOM_TYPES ]; // register proplist for custom type ------------------------------------------ // void CON_RegisterCustomType( dword objtypeid, proplist_s *proplist ) { ASSERT( proplist != NULL ); //NOTE: // a type id of TYPE_ID_INVALID will be ignored silently, // in order to make the id returned by OBJ_RegisterCustomType() // directly useable without explicit error checking. if ( objtypeid == TYPE_ID_INVALID ) return; int typeindx = objtypeid & TYPENUMBERMASK; ASSERT( typeindx >= NUM_DISTINCT_OBJTYPES ); if ( typeindx < NUM_DISTINCT_OBJTYPES ) return; typeindx -= NUM_DISTINCT_OBJTYPES; ASSERT( typeindx < MAX_NUM_CUSTOM_TYPES ); if ( typeindx >= MAX_NUM_CUSTOM_TYPES ) return; // register each type exactly once ASSERT( custom_types_proplists[ typeindx ] == NULL ); if ( custom_types_proplists[ typeindx ] != NULL ) return; custom_types_proplists[ typeindx ] = proplist; } // fetch pointer to property list for specified type id ----------------------- // proplist_s *FetchTypePropertyList( dword objtypeid ) { ASSERT( objtypeid != TYPE_ID_INVALID ); //NOTE: // may return NULL if no proplist is available // for the requested type (especially if custom). int typeindx = objtypeid & TYPENUMBERMASK; // default type if ( typeindx < NUM_DISTINCT_OBJTYPES ) { return default_types_proplists[ typeindx ]; } // custom type typeindx -= NUM_DISTINCT_OBJTYPES; ASSERT( typeindx < MAX_NUM_CUSTOM_TYPES ); if ( typeindx >= MAX_NUM_CUSTOM_TYPES ) return NULL; // return either NULL or registered proplist return custom_types_proplists[ typeindx ]; } // list of alias names for default object types ------------------------------- // struct alias_typename_s { const char* objtypename; dword objtypeid; }; PRIVATE alias_typename_s AliasTypeNames[ NUM_DISTINCT_OBJTYPES ] = { { "ship_1", SHIP1TYPE }, { "ship_2", SHIP2TYPE }, { "laser_1", LASER1TYPE }, { "laser_2", LASER2TYPE }, { "laser_3", LASER3TYPE }, { "missl_1", MISSILE1TYPE }, { "missl_2", MISSILE2TYPE }, { "missl_3", MISSILE3TYPE }, { "missl_4", MISSILE4TYPE }, { "missl_5", MISSILE5TYPE }, { "extra_1", EXTRA1TYPE }, { "extra_2", EXTRA2TYPE }, { "extra_3", EXTRA3TYPE }, { "mine_1", MINE1TYPE }, }; // fetch name for specified type id ------------------------------------------- // PRIVATE const char *FetchTypeName( dword objtypeid ) { // check default type ids for ( int tid = 0; tid < NUM_DISTINCT_OBJTYPES; tid++ ) if ( AliasTypeNames[ tid ].objtypeid == objtypeid ) return (char *) AliasTypeNames[ tid ].objtypename; // check custom type ids dword typeindex = ( objtypeid & TYPENUMBERMASK ) - NUM_DISTINCT_OBJTYPES; ASSERT( typeindex < (dword)num_custom_types ); const char *objtypename = custom_type_info[ typeindex ].type_name; ASSERT( objtypename != NULL ); return objtypename; } // build type info line for type list ----------------------------------------- // char *BuildTypeInfo( int typeindex ) { ASSERT( typeindex >= 0 ); ASSERT( typeindex < NUM_DISTINCT_OBJTYPES + num_custom_types ); if ( typeindex < NUM_DISTINCT_OBJTYPES ) { sprintf( paste_str, "type %d: %s (id %08x)", typeindex, AliasTypeNames[ typeindex ].objtypename, (unsigned int)AliasTypeNames[ typeindex ].objtypeid ); } else { int customindex = typeindex - NUM_DISTINCT_OBJTYPES; sprintf( paste_str, "type %d: %s (id %08x)", typeindex, custom_type_info[ customindex ].type_name, (unsigned int)custom_type_info[ customindex ].type_id ); } return paste_str; } // list of alias names for the default object classes ------------------------- // struct alias_classname_s { const char* objclassname; dword objclassid; }; PRIVATE alias_classname_s AliasClassNames[ NUM_ALTERABLE_CLASSES ] = { { "ship1", SHIP_CLASS_1 }, { "ship2", SHIP_CLASS_2 }, { "ship3", SHIP_CLASS_3 }, { "laser1", LASER0_CLASS_1 }, { "laser2", LASER0_CLASS_2 }, { "laser3", LASER1_CLASS_1 }, { "laser4", LASER2_CLASS_1 }, { "missl1", DUMB_CLASS_1 }, { "missl2", GUIDE_CLASS_1 }, { "missl3", SWARM_CLASS_1 }, { "mine1", MINE_CLASS_1 }, { "extra1", ENERGY_EXTRA_CLASS }, { "extra2", DUMB_PACK_CLASS }, { "extra3", GUIDE_PACK_CLASS }, { "extra4", HELIX_DEVICE_CLASS }, { "extra5", LIGHTNING_DEVICE_CLASS }, { "extra6", MINE_PACK_CLASS }, { "extra7", REPAIR_EXTRA_CLASS }, { "extra8", AFTERBURNER_DEVICE_CLASS }, { "extra9", SWARM_PACK_CLASS }, { "extra10", INVISIBILITY_CLASS }, { "extra11", PHOTON_DEVICE_CLASS }, { "extra12", DECOY_DEVICE_CLASS }, { "extra13", LASERUPGRADE1_CLASS }, { "extra14", LASERUPGRADE2_CLASS }, { "extra15", INVULNERABILITY_CLASS }, }; // build class info line for class list --------------------------------------- // char *BuildClassInfo( int classindex ) { ASSERT( classindex >= 0 ); ASSERT( classindex < NumObjClasses ); ASSERT( NumObjClasses >= NUM_ALTERABLE_CLASSES ); ASSERT( NumObjClasses == NumLoadedObjects ); dword objclassid = classindex; if ( classindex < NUM_ALTERABLE_CLASSES ) { objclassid = AliasClassNames[ classindex ].objclassid; } ASSERT( objclassid < (dword)NumLoadedObjects ); dword objtypeid = ObjectInfo[ objclassid ].type; const char *objtypename = FetchTypeName( objtypeid ); #define MAX_CLASSNAME 31 char classname[ MAX_CLASSNAME + 1 ]; strncpy( classname, ObjectInfo[ objclassid ].name, MAX_CLASSNAME ); classname[ MAX_CLASSNAME ] = 0; if ( classindex < NUM_ALTERABLE_CLASSES ) { sprintf( paste_str, "class id %u [%s] (%s) type %s", (unsigned int)objclassid, AliasClassNames[ classindex ].objclassname, classname, objtypename ); } else { sprintf( paste_str, "class id %u [%s] (%s) type %s", (unsigned int)objclassid, "noalias", classname, objtypename ); } return paste_str; } // object instance to alter when no class and type is specified below --------- // static GenObject *alter_object_instance = NULL; // create a pointer to a property field --------------------------------------- // INLINE char *MakeFieldPointer( dword objclassid, proplist_s *plist ) { ASSERT( plist != NULL ); //NOTE: // ( objclassid == CLASS_ID_INVALID ) means an object // instance should be accessed instead of the class itself. char *fieldpo; if ( objclassid == CLASS_ID_INVALID ) { ASSERT( alter_object_instance != NULL ); fieldpo = plist->propoffset + (char*)alter_object_instance; } else { ASSERT( objclassid < (dword)NumObjClasses ); fieldpo = plist->propoffset + (char*)ObjClasses[ objclassid ]; } return fieldpo; } // get value and access-type of class/type property --------------------------- // PRIVATE int GetPropertyValue( dword objclassid, proplist_s *plist, int *pint, float *pflt, char **pstr ) { ASSERT( plist != NULL ); ASSERT( pint != NULL ); ASSERT( pflt != NULL ); ASSERT( pstr != NULL ); //NOTE: // ( objclassid == CLASS_ID_INVALID ) means an object // instance should be queried instead of the class itself. char *fieldpo = MakeFieldPointer( objclassid, plist ); int accesstype; switch ( plist->fieldtype ) { case PROPTYPE_INT: *pint = *(int *)fieldpo; accesstype = ACCESSTYPE_INT; break; case PROPTYPE_FLOAT: *pflt = *(float *)fieldpo; accesstype = ACCESSTYPE_FLOAT; break; case PROPTYPE_GEOMV: *pflt = GEOMV_TO_FLOAT( *(geomv_t *)fieldpo ); accesstype = ACCESSTYPE_FLOAT; break; case PROPTYPE_FIXED: *pflt = FIXED_TO_FLOAT( *(fixed_t *)fieldpo ); accesstype = ACCESSTYPE_FLOAT; break; case PROPTYPE_STRING: *pstr = fieldpo; accesstype = ACCESSTYPE_STRING; break; case PROPTYPE_CHARPTR: *pstr = *(char**)fieldpo; accesstype = ACCESSTYPE_CHARPTR; break; default: PANIC( 0 ); } return accesstype; } // set value of class/type property after converting to correct type ---------- // PRIVATE void SetPropertyValue( dword objclassid, proplist_s *plist, int pint, float pflt, char *pstr ) { ASSERT( plist != NULL ); //NOTE: // ( objclassid == CLASS_ID_INVALID ) means an object // instance should be altered instead of the class itself. char *fieldpo = MakeFieldPointer( objclassid, plist ); // indicate whether the field content has actually changed // (i.e. was not already set to this value) int fieldchanged = FALSE; switch ( plist->fieldtype ) { case PROPTYPE_INT: fieldchanged = ( *(int *)fieldpo != pint ); *(int *)fieldpo = pint; break; case PROPTYPE_FLOAT: fieldchanged = ( *(float *)fieldpo != pflt ); *(float *)fieldpo = pflt; break; case PROPTYPE_GEOMV: fieldchanged = ( *(geomv_t *)fieldpo != FLOAT_TO_GEOMV( pflt ) ); *(geomv_t *)fieldpo = FLOAT_TO_GEOMV( pflt ); break; case PROPTYPE_FIXED: fieldchanged = ( *(fixed_t *)fieldpo != FLOAT_TO_FIXED( pflt ) ); *(fixed_t *)fieldpo = FLOAT_TO_FIXED( pflt ); break; case PROPTYPE_STRING: ASSERT( pstr != NULL ); if ( strncmp( fieldpo, pstr, plist->bmax ) != 0 ) { strncpy( fieldpo, pstr, plist->bmax ); fieldpo[ plist->bmax ] = 0; fieldchanged = TRUE; } break; case PROPTYPE_CHARPTR: ASSERT( pstr != NULL ); ASSERT( *(char**)fieldpo != NULL ); if ( strncmp( *(char**)fieldpo, pstr, plist->bmax ) != 0 ) { FREEMEM( *(char**)fieldpo ); *(char**)fieldpo = (char *) ALLOCMEM( strlen( pstr ) + 1 ); if ( *(char**)fieldpo == NULL ) OUTOFMEM( 0 ); strcpy( *(char**)fieldpo, pstr ); fieldchanged = TRUE; } break; default: PANIC( 0 ); } if ( fieldchanged ) { // only call the notification callback for changed fields // of object class instances (and type templates) if ( objclassid == CLASS_ID_INVALID ) { ASSERT( alter_object_instance != NULL ); // call notification callback function if ( plist->notify_callback != NULL ) { (*plist->notify_callback)( alter_object_instance ); } } } } // set new int-property value if supplied, otherwise just display current ----- // INLINE int SetObjPropertyValueInt( dword objclassid, dword objtypeid, proplist_s *plist, int *pint, const char *query ) { ASSERT( plist != NULL ); ASSERT( pint != NULL ); ASSERT( query != NULL ); // all properties must be queriable right now! // query/alter intermediate field char *scan = QueryIntArgument( query, pint ); if ( scan != NULL ) { char *errpart; long sval = strtol( scan, &errpart, int_calc_base ); int argvalid = ( *errpart == 0 ); // check for increment/decrement tokens if ( !argvalid ) { if( strcmp( scan, "++" ) == 0 ) { sval = (*pint) + 1; argvalid = TRUE; } else if ( strcmp( scan, "--" ) == 0 ) { sval = (*pint) - 1; argvalid = TRUE; } else if ( strncmp( scan, "+=", 2 ) == 0 ) { char* arg = scan + 2; long argval = strtol( arg, &errpart, int_calc_base ); if ( *errpart == 0 ) { sval = (*pint) + argval; argvalid = TRUE; } } else if ( strncmp( scan, "-=", 2 ) == 0 ) { char* arg = scan + 2; long argval = strtol( arg, &errpart, int_calc_base ); if ( *errpart == 0 ) { sval = (*pint) - argval; argvalid = TRUE; } } } if ( argvalid ) { if ( ( sval >= plist->bmin ) && ( sval <= plist->bmax ) ) { *pint = sval; } else { CON_AddLine( range_error ); return FALSE; } } else { CON_AddLine( invalid_arg ); return FALSE; } // transfer intermediate field into actual property SetPropertyValue( objclassid, plist, *pint, 0, NULL ); // scan other classes of this type and alter also if ( ( objtypeid != TYPE_ID_INVALID ) && ( objclassid != CLASS_ID_INVALID ) ) { for ( int cid = objclassid + 1; cid < NumObjClasses; cid++ ) { if ( ObjClasses[ cid ]->ObjectType == objtypeid ) { SetPropertyValue( cid, plist, *pint, 0, NULL ); } } } } return TRUE; } // set new float-property value if supplied, otherwise just display current --- // INLINE int SetObjPropertyValueFlt( dword objclassid, dword objtypeid, proplist_s *plist, float *pflt, const char *query ) { ASSERT( plist != NULL ); ASSERT( pflt != NULL ); ASSERT( query != NULL ); // all properties must be queriable right now! // query/alter intermediate field char *scan = QueryFltArgument( query, pflt ); if ( scan != NULL ) { char *errpart; float sval = strtod( scan, &errpart ); int argvalid = ( *errpart == 0 ); // check for increment/decrement tokens if ( !argvalid ) { if( strcmp( scan, "++" ) == 0 ) { sval = (*pflt) + 1.0f; argvalid = TRUE; } else if ( strcmp( scan, "--" ) == 0 ) { sval = (*pflt) - 1.0f; argvalid = TRUE; } else if ( strncmp( scan, "+=", 2 ) == 0 ) { char* arg = scan + 2; float argval = strtod( arg, &errpart ); if ( *errpart == 0 ) { sval = (*pflt) + argval; argvalid = TRUE; } } else if ( strncmp( scan, "-=", 2 ) == 0 ) { char* arg = scan + 2; float argval = strtod( arg, &errpart ); if ( *errpart == 0 ) { sval = (*pflt) - argval; argvalid = TRUE; } } } if ( argvalid ) { if ( ( FLOAT_TO_FIXED( sval ) >= plist->bmin ) && ( FLOAT_TO_FIXED( sval ) <= plist->bmax ) ) { *pflt = sval; } else { CON_AddLine( range_error ); return FALSE; } } else { CON_AddLine( invalid_arg ); return FALSE; } // transfer intermediate field into actual property SetPropertyValue( objclassid, plist, 0, *pflt, NULL ); // scan other classes of this type and alter also if ( ( objtypeid != TYPE_ID_INVALID ) && ( objclassid != CLASS_ID_INVALID ) ) { for ( int cid = objclassid + 1; cid < NumObjClasses; cid++ ) { if ( ObjClasses[ cid ]->ObjectType == objtypeid ) { SetPropertyValue( cid, plist, 0, *pflt, NULL ); } } } } return TRUE; } // set new float-property value if supplied, otherwise just display current --- // INLINE int SetObjPropertyValueStr( dword objclassid, dword objtypeid, proplist_s *plist, char *pstr ) { ASSERT( plist != NULL ); ASSERT( pstr != NULL ); char *scan = strtok( NULL, "" ); if ( scan != NULL ) { // eat whitespace and leading quotations while ( ( *scan == ' ' ) || ( *scan == '"' ) ) scan++; // argument found? if ( *scan != 0 ) { // cut off trailing whitespace and quotations char *start = scan; while ( *scan != 0 ) scan++; scan--; while ( ( *scan == ' ' ) || ( *scan == '"' ) ) scan--; *( scan + 1 ) = 0; // store string into field SetPropertyValue( objclassid, plist, 0, 0, start ); // scan other classes of this type and alter also if ( ( objtypeid != TYPE_ID_INVALID ) && ( objclassid != CLASS_ID_INVALID ) ) { for ( int cid = objclassid + 1; cid < NumObjClasses; cid++ ) { if ( ObjClasses[ cid ]->ObjectType == objtypeid ) { SetPropertyValue( objclassid, plist, 0, 0, start ); } } } return TRUE; } } // display current value CON_AddLine( pstr ); return TRUE; } // set new property value if supplied, otherwise just display current --------- // PRIVATE void SetObjPropertyValue( dword objclassid, dword objtypeid, proplist_s *plist, const char *query ) { ASSERT( plist != NULL ); ASSERT( query != NULL ); // all properties must be queriable right now! int pint; float pflt; char* pstr; int acct = GetPropertyValue( objclassid, plist, &pint, &pflt, &pstr ); //NOTE: // ( objclassid == CLASS_ID_INVALID ) && ( objtypeid == TYPE_ID_INVALID ) // means an object instance should be altered instead of the class itself. // // ( objtypeid == TYPE_ID_INVALID ) means a class is being altered, resulting // in a change of only a single class's property field. // // ( objtypeid != TYPE_ID_INVALID ) means a type is being altered, resulting // in a change of property fields of all classes belonging to this type. switch ( acct ) { case ACCESSTYPE_INT: SetObjPropertyValueInt( objclassid, objtypeid, plist, &pint, query ); break; case ACCESSTYPE_FLOAT: SetObjPropertyValueFlt( objclassid, objtypeid, plist, &pflt, "%f" ); break; case ACCESSTYPE_STRING: case ACCESSTYPE_CHARPTR: SetObjPropertyValueStr( objclassid, objtypeid, plist, pstr ); break; } } // resolve type name to type id with aliases and custom support --------------- // PRIVATE dword AliasResolveTypeName( const char *name ) { ASSERT( name != NULL ); // check type name aliases unsigned int tid = 0; for ( tid = 0; tid < NUM_DISTINCT_OBJTYPES; tid++ ) if ( strcmp( name, AliasTypeNames[ tid ].objtypename ) == 0 ) break; if ( tid != NUM_DISTINCT_OBJTYPES ) { ASSERT( ( AliasTypeNames[ tid ].objtypeid & TYPENUMBERMASK ) == tid ); return AliasTypeNames[ tid ].objtypeid; } // check custom type names for ( tid = 0; tid < (dword)num_custom_types; tid++ ) if ( stricmp( name, custom_type_info[ tid ].type_name ) == 0 ) break; if ( tid != (dword)num_custom_types ) { return custom_type_info[ tid ].type_id; } return TYPE_ID_INVALID; } // check argument that alters an object type property ------------------------- // int CheckSetObjTypeProperty( const char *query, const char *scan ) { ASSERT( query != NULL ); // all properties must be queriable right now! ASSERT( scan != NULL ); // check if prop command if ( strcmp( scan, CMSTR( CM_PROP ) ) != 0 ) return FALSE; // isolate type name field char *objtypename = strtok( NULL, "." ); if ( objtypename == NULL ) { CON_AddLine( prop_syntax ); return TRUE; } // resolve name to id dword objtypeid = AliasResolveTypeName( objtypename ); if ( objtypeid == TYPE_ID_INVALID ) { CON_AddLine( prop_wrong_type ); return TRUE; } // isolate property name field char *fieldname = strtok( NULL, " " ); if ( fieldname == NULL ) { CON_AddLine( prop_syntax ); return TRUE; } // check if property name exists for specified type int propfound = FALSE; proplist_s *plist = FetchTypePropertyList( objtypeid ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } for ( ; plist->propname; plist++ ) { if ( stricmp( plist->propname, fieldname ) == 0 ) { propfound = TRUE; break; } } if ( !propfound ) { CON_AddLine( prop_wrong_field ); return TRUE; } // default: use instance/template dword objclassid = CLASS_ID_INVALID; ASSERT( alter_object_instance == NULL ); // try to find type template (for custom types only) if ( TYPEID_TYPE_CUSTOM( objtypeid ) ) { // (ab)use instance pointer for template alter_object_instance = OBJ_FetchCustomTypeTemplate( objtypeid ); } // find class if no template available if ( alter_object_instance == NULL ) { //NOTE: // the first class of this type encountered is taken // at this time. still, the selected property of all // classes of this type will be altered, since // SetObjPropertyValue() continues the search in the // class list. // scan object class list int cid = 0; for ( cid = 0; cid < NumObjClasses; cid++ ) if ( ObjClasses[ cid ]->ObjectType == objtypeid ) break; if ( cid == NumObjClasses ) { CON_AddLine( no_objs_of_type ); return TRUE; } objclassid = cid; } // set new value if supplied, otherwise just display current value SetObjPropertyValue( objclassid, objtypeid, plist, query ); // reset instance pointer alter_object_instance = NULL; return TRUE; } // resolve class name to class id with aliases -------------------------------- // PRIVATE dword AliasResolveClassName( const char *name ) { ASSERT( name != NULL ); // check class name aliases int propindx = -1; int cid = 0; for ( cid = 0; cid < NUM_ALTERABLE_CLASSES; cid++ ) { if ( strcmp( name, AliasClassNames[ cid ].objclassname ) == 0 ) { propindx = cid; break; } } if ( propindx != -1 ) { return AliasClassNames[ propindx ].objclassid; } // check original class names ASSERT( NumObjClasses >= NUM_ALTERABLE_CLASSES ); for ( cid = 0; cid < NumObjClasses; cid++ ) { if ( stricmp( name, ObjectInfo[ cid ].name ) == 0 ) { propindx = cid; break; } } if ( propindx != -1 ) { return propindx; } return CLASS_ID_INVALID; } // check argument that alters an object class property ------------------------ // int CheckSetObjClassProperty( const char *query, const char *scan ) { ASSERT( query != NULL ); // all properties must be queriable right now! ASSERT( scan != NULL ); // check if propc command if ( strcmp( scan, CMSTR( CM_PROPC ) ) != 0 ) return FALSE; // isolate class name field char *objclassname = strtok( NULL, "." ); if ( objclassname == NULL ) { CON_AddLine( propc_syntax ); return TRUE; } // allow class name to be parenthesized to include whitespace objclassname = GetParenthesizedName( objclassname ); if ( objclassname == NULL ) { CON_AddLine( propc_syntax ); return TRUE; } // resolve name to id dword objclassid = AliasResolveClassName( objclassname ); if ( objclassid == CLASS_ID_INVALID ) { CON_AddLine( prop_wrong_class ); return TRUE; } // isolate property name field char *fieldname = strtok( NULL, " " ); if ( fieldname == NULL ) { CON_AddLine( propc_syntax ); return TRUE; } ASSERT( objclassid < (dword)NumObjClasses ); dword objtypeid = ObjectInfo[ objclassid ].type; // check if property name exists for specified class int propfound = FALSE; proplist_s *plist = FetchTypePropertyList( objtypeid ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } for ( ; plist->propname; plist++ ) { if ( stricmp( plist->propname, fieldname ) == 0 ) { propfound = TRUE; break; } } if ( !propfound ) { CON_AddLine( prop_wrong_field ); return TRUE; } // check if class is valid (i.e., actually memory resident) if ( objclassid >= (dword)NumObjClasses ) { CON_AddLine( class_not_loaded ); return TRUE; } // set new value if supplied, otherwise just display current value SetObjPropertyValue( objclassid, TYPE_ID_INVALID, plist, query ); return TRUE; } // check argument that alters an object instance property --------------------- // int CheckSetObjInstanceProperty( const char *query, const char *scan ) { ASSERT( query != NULL ); // all properties must be queriable right now! ASSERT( scan != NULL ); // check if propo command if ( strcmp( scan, CMSTR( CM_PROPO ) ) != 0 ) return FALSE; // isolate object id field char *objidstr = strtok( NULL, "." ); if ( objidstr == NULL ) { CON_AddLine( propo_syntax ); return TRUE; } // convert object id string to int char *errpart; dword objid = strtol( objidstr, &errpart, 10/*int_calc_base*/ ); if ( *errpart != 0 ) { CON_AddLine( prop_objid_syntax ); return TRUE; } //NOTE: // id 0 means use id of most recently // summoned object. if ( objid == 0 ) { objid = last_summoned_objectid; if ( !AUX_DISABLE_LEVEL_CONSOLE_MESSAGES ) { sprintf( paste_str, "using object id %u.", (unsigned int)objid ); CON_AddLine( paste_str ); } } // isolate property name field char *fieldname = strtok( NULL, " " ); if ( fieldname == NULL ) { CON_AddLine( propo_syntax ); return TRUE; } // find object GenObject *obj = FetchObject( objid ); if ( obj == NULL ) { CON_AddLine( prop_no_object ); return TRUE; } // check if property name exists int propfound = FALSE; proplist_s *plist = FetchTypePropertyList( obj->ObjectType ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } for ( ; plist->propname; plist++ ) { if ( stricmp( plist->propname, fieldname ) == 0 ) { propfound = TRUE; break; } } if ( !propfound ) { CON_AddLine( prop_wrong_field ); return TRUE; } // set new value if supplied, otherwise just display current value alter_object_instance = obj; SetObjPropertyValue( CLASS_ID_INVALID, TYPE_ID_INVALID, plist, query ); alter_object_instance = NULL; return TRUE; } // build description for type property of numeric type ------------------------ // PRIVATE void DescTypeNum( const char *name, proplist_s *plist, int acct ) { static char format[] = "%s.%s %s (min=%d max=%d)"; char typespec = ( acct == ACCESSTYPE_INT ) ? int_print_base[ 1 ] : 'f'; format[ 15 ] = typespec; format[ 22 ] = typespec; if ( acct == ACCESSTYPE_INT ) { sprintf( paste_str, format, name, plist->propname, "int", plist->bmin, plist->bmax ); } else { sprintf( paste_str, format, name, plist->propname, "float", FIXED_TO_FLOAT( plist->bmin ), FIXED_TO_FLOAT( plist->bmax ) ); } } // build description for type property of string type ------------------------- // PRIVATE void DescTypeStr( const char *name, proplist_s *plist ) { sprintf( paste_str, "%s.%s string (min=%d max=%d)", name, plist->propname, plist->bmin, plist->bmax ); } // build description for class property of numeric type ----------------------- // PRIVATE void DescClassNum( const char *name, proplist_s *plist, int acct, int pint, float pflt ) { static char format[] = "%s.%s %d (%s min=%d max=%d)"; char typespec = ( acct == ACCESSTYPE_INT ) ? int_print_base[ 1 ] : 'f'; format[ 7 ] = typespec; format[ 18 ] = typespec; format[ 25 ] = typespec; if ( acct == ACCESSTYPE_INT ) { sprintf( paste_str, format, name, plist->propname, pint, "int", plist->bmin, plist->bmax ); } else { sprintf( paste_str, format, name, plist->propname, pflt, "float", FIXED_TO_FLOAT( plist->bmin ), FIXED_TO_FLOAT( plist->bmax ) ); } } // build description for class property of string type ------------------------ // PRIVATE void DescClassStr( const char *name, proplist_s *plist, const char *pstr ) { sprintf( paste_str, "%s.%s \"%s\" (min=%d max=%d)", name, plist->propname, pstr, plist->bmin, plist->bmax ); } // print various info about specific object type ------------------------------ // int CheckTypeInfo( const char *scan ) { ASSERT( scan != NULL ); // check if typeinfo command if ( strcmp( scan, CMSTR( CM_TYPEINFO ) ) != 0 ) return FALSE; // isolate type name field char *objtypename = strtok( NULL, " " ); if ( objtypename == NULL ) { CON_AddLine( typeinfo_syntax ); return TRUE; } //NOTE: // parenthesized type names are not // allowed. // check if too many fields supplied if ( strtok( NULL, " " ) != NULL ) { CON_AddLine( typeinfo_syntax ); return TRUE; } // resolve name to id dword objtypeid = AliasResolveTypeName( objtypename ); if ( objtypeid == TYPE_ID_INVALID ) { CON_AddLine( prop_wrong_type ); return TRUE; } // print info header sprintf( paste_str, "--properties of type %s (%08x_h):", objtypename, (unsigned int)objtypeid ); CON_AddLine( paste_str ); // default: use instance/template dword objclassid = CLASS_ID_INVALID; ASSERT( alter_object_instance == NULL ); // try to find type template (for custom types only) if ( TYPEID_TYPE_CUSTOM( objtypeid ) ) { // (ab)use instance pointer for template alter_object_instance = OBJ_FetchCustomTypeTemplate( objtypeid ); } // find class if no template available if ( alter_object_instance == NULL ) { // determine whether there are classes of this type // (scan object class list for class of this type) for ( int cid = 0; cid < NumObjClasses; cid++ ) { if ( ObjClasses[ cid ]->ObjectType == objtypeid ) { objclassid = cid; break; } } //NOTE: // to display info about a type any class of this type // may be used! (that is, the first class of this type // contained in the class-list is used.) this is the // behavior that should be expected, but it is only // guaranteed to actually obtain homogeneous type-info // if no class of this type has been altered separately! if ( objclassid == CLASS_ID_INVALID ) { CON_AddLine( "(there are no objects of this type)" ); } } // fetch property descriptions proplist_s *plist = FetchTypePropertyList( objtypeid ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } // print list of properties (and their current values // if the type has been instanced/templatized) for ( ; plist->propname; plist++ ) { if ( ( objclassid != CLASS_ID_INVALID ) || ( alter_object_instance != NULL ) ) { int pint = 0; float pflt = 0.0f; char* pstr = NULL; int acct = GetPropertyValue( objclassid, plist, &pint, &pflt, &pstr ); switch ( acct ) { case ACCESSTYPE_INT: case ACCESSTYPE_FLOAT: DescClassNum( objtypename, plist, acct, pint, pflt ); break; case ACCESSTYPE_STRING: case ACCESSTYPE_CHARPTR: DescClassStr( objtypename, plist, pstr ); break; } } else { switch ( plist->fieldtype ) { case PROPTYPE_INT: DescTypeNum( objtypename, plist, ACCESSTYPE_INT ); break; case PROPTYPE_FLOAT: case PROPTYPE_GEOMV: case PROPTYPE_FIXED: DescTypeNum( objtypename, plist, ACCESSTYPE_FLOAT ); break; case PROPTYPE_STRING: case PROPTYPE_CHARPTR: DescTypeStr( objtypename, plist ); break; } } CON_AddLine( paste_str ); } // reset instance pointer alter_object_instance = NULL; return TRUE; } // print various info about specific object class ----------------------------- // int CheckClassInfo( const char *scan ) { ASSERT( scan != NULL ); // check if classinfo command if ( strcmp( scan, CMSTR( CM_CLASSINFO ) ) != 0 ) return FALSE; // isolate class name field char *objclassname = strtok( NULL, " " ); if ( objclassname == NULL ) { CON_AddLine( classinfo_syntax ); return TRUE; } // allow class name to be parenthesized to include whitespace objclassname = GetParenthesizedName( objclassname ); if ( objclassname == NULL ) { CON_AddLine( classinfo_syntax ); return TRUE; } // check if too many fields supplied if ( strtok( NULL, " " ) != NULL ) { CON_AddLine( classinfo_syntax ); return TRUE; } // resolve name to id dword objclassid = AliasResolveClassName( objclassname ); if ( objclassid == CLASS_ID_INVALID ) { CON_AddLine( prop_wrong_class ); return TRUE; } // check if class is valid (i.e., actually memory resident) if ( objclassid >= (dword)NumObjClasses ) { CON_AddLine( class_not_loaded ); return TRUE; } ASSERT( objclassid < (dword)NumObjClasses ); dword objtypeid = ObjectInfo[ objclassid ].type; // print info header sprintf( paste_str, "--properties of class %s (%02u_d) (type is %s):", objclassname, (unsigned int)objclassid, FetchTypeName( objtypeid ) ); CON_AddLine( paste_str ); // fetch property descriptions proplist_s *plist = FetchTypePropertyList( objtypeid ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } // print list of properties with current values for ( ; plist->propname; plist++ ) { int pint = 0; float pflt = 0.0f; char* pstr = NULL; int acct = GetPropertyValue( objclassid, plist, &pint, &pflt, &pstr ); switch ( acct ) { case ACCESSTYPE_INT: case ACCESSTYPE_FLOAT: DescClassNum( objclassname, plist, acct, pint, pflt ); break; case ACCESSTYPE_STRING: case ACCESSTYPE_CHARPTR: DescClassStr( objclassname, plist, pstr ); break; } CON_AddLine( paste_str ); } return TRUE; } // print various info about specific object (class instance) ------------------ // int CheckInstanceInfo( const char *scan ) { ASSERT( scan != NULL ); // check if objectinfo command if ( strcmp( scan, CMSTR( CM_OBJECTINFO ) ) != 0 ) return FALSE; // isolate object id field char *objidstr = strtok( NULL, " " ); if ( objidstr == NULL ) { CON_AddLine( objectinfo_syntax ); return TRUE; } // convert object id string to int char *errpart; dword objid = strtol( objidstr, &errpart, 10/*int_calc_base*/ ); if ( *errpart != 0 ) { CON_AddLine( objectinfo_syntax ); return TRUE; } // check if too many fields supplied if ( strtok( NULL, " " ) != NULL ) { CON_AddLine( objectinfo_syntax ); return TRUE; } //NOTE: // id 0 means use id of most recently // summoned object. if ( objid == 0 ) { objid = last_summoned_objectid; if ( !AUX_DISABLE_LEVEL_CONSOLE_MESSAGES ) { sprintf( paste_str, "using object id %u.", (unsigned int)objid ); CON_AddLine( paste_str ); } } // find object GenObject *obj = FetchObject( objid ); if ( obj == NULL ) { CON_AddLine( prop_no_object ); return TRUE; } dword objclassid = obj->ObjectClass; dword objtypeid = obj->ObjectType; ASSERT( objclassid < (dword)NumObjClasses ); char *objclassname = ObjectInfo[ objclassid ].name; // print info header sprintf( paste_str, "--properties of object %u (class %s id %u, type %s):", (unsigned int)objid, objclassname, (unsigned int)objclassid, FetchTypeName( objtypeid ) ); CON_AddLine( paste_str ); // fetch property descriptions proplist_s *plist = FetchTypePropertyList( objtypeid ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } // set instance pointer alter_object_instance = obj; // print list of properties with current values for ( ; plist->propname; plist++ ) { int pint = 0; float pflt = 0.0f; char* pstr = NULL; int acct = GetPropertyValue( CLASS_ID_INVALID, plist, &pint, &pflt, &pstr ); switch ( acct ) { case ACCESSTYPE_INT: case ACCESSTYPE_FLOAT: DescClassNum( objclassname, plist, acct, pint, pflt ); break; case ACCESSTYPE_STRING: case ACCESSTYPE_CHARPTR: DescClassStr( objclassname, plist, pstr ); break; } CON_AddLine( paste_str ); } // reset instance pointer alter_object_instance = NULL; return TRUE; } // write the properties of a instance to a console script ( propo 0.????? ) --- // int WritePropList( FILE* fp, dword objid ) { ASSERT( fp != NULL ); // find object GenObject *obj = FetchObject( objid ); if ( obj == NULL ) { CON_AddLine( prop_no_object ); return TRUE; } dword objclassid = obj->ObjectClass; dword objtypeid = obj->ObjectType; ASSERT( objclassid < (dword)NumObjClasses ); char *objclassname = ObjectInfo[ objclassid ].name; // print info header fprintf( fp, "; properties of object %d (class %s id %d, type %s)\n", objid, objclassname, objclassid, FetchTypeName( objtypeid ) ); // fetch property descriptions proplist_s *plist = FetchTypePropertyList( objtypeid ); if ( plist == NULL ) { CON_AddLine( not_accessible ); return TRUE; } // set instance pointer alter_object_instance = obj; // print list of properties with current values for ( ; plist->propname; plist++ ) { int pint; float pflt; char* pstr; int acct = GetPropertyValue( CLASS_ID_INVALID, plist, &pint, &pflt, &pstr ); switch ( acct ) { case ACCESSTYPE_INT: fprintf( fp, "propo 0.%s %d\n", plist->propname, pint ); break; case ACCESSTYPE_FLOAT: fprintf( fp, "propo 0.%s %f\n", plist->propname, pflt ); break; case ACCESSTYPE_STRING: case ACCESSTYPE_CHARPTR: fprintf( fp, "propo 0.%s \"%s\"\n", plist->propname, pstr ); break; } } // reset instance pointer alter_object_instance = NULL; return TRUE; } // key table for faceinfo command --------------------------------------------- // key_value_s faceinfo_key_value[] = { { "class", NULL, KEYVALFLAG_PARENTHESIZE }, { "classid", NULL, KEYVALFLAG_NONE }, { "faceid", NULL, KEYVALFLAG_PARENTHESIZE }, { "shader", NULL, KEYVALFLAG_PARENTHESIZE }, { "texture", NULL, KEYVALFLAG_PARENTHESIZE }, { NULL, NULL, KEYVALFLAG_NONE }, }; enum { KEY_FACEINFO_CLASS, KEY_FACEINFO_CLASSID, KEY_FACEINFO_FACEID, KEY_FACEINFO_SHADER, KEY_FACEINFO_TEXTURE }; // face search callback vars -------------------------------------------------- // static int (*face_cmp_function)( GenObject*, int ); static TextureMap *facesearch_texture; // return whether a face has the criterion texture ---------------------------- // PRIVATE int FaceHasTexture( GenObject *gobj, int faceid ) { ASSERT( gobj != NULL ); ASSERT( ( faceid >= 0 ) && ( (dword)faceid < gobj->NumFaces ) ); return ( gobj->FaceList[ faceid ].TexMap == facesearch_texture ); } // display list of face ids satisfying a specific criterion ------------------- // PRIVATE void DisplayFaceList( GenObject *gobj ) { ASSERT( gobj != NULL ); ASSERT( face_cmp_function != NULL ); int outpos = 0; for ( unsigned int fid = 0; fid < gobj->NumFaces; fid++ ) { if ( (*face_cmp_function)( gobj, fid ) ) { sprintf( paste_str + outpos, "%3d, ", fid ); outpos += strlen( paste_str + outpos ); if ( outpos > 60 ) { // strip ", " and display accumulated line paste_str[ outpos - 2 ] = 0; CON_AddLine( paste_str ); outpos = 0; } } } if ( outpos > 0 ) { // strip ", " and display last line paste_str[ outpos - 2 ] = 0; CON_AddLine( paste_str ); } } // command "faceinfo" to display various object face information -------------- // int Cmd_FaceInfo( char *command ) { //NOTE: //CONCOM: // faceinfo_command ::= 'faceinfo' // class_spec ::= | // class_name ::= 'class' // class_id ::= 'classid' // face_spec ::= | // face_id_spec ::= 'faceid' // attrib_spec ::= | // shader_spec ::= 'shader' | // shader_iter ::= '(' 'iter_xx'* 'flag_xx'* ')' // shader_name ::= "valid name of shader" // tex_spec ::= 'texture' ASSERT( command != NULL ); HANDLE_COMMAND_DOMAIN_SEP( command ); // scan out all values to keys if ( !ScanKeyValuePairs( faceinfo_key_value, command ) ) return TRUE; // get object class (either name or id) dword objclass = ScanKeyValueObjClass( faceinfo_key_value, KEY_FACEINFO_CLASS, KEY_FACEINFO_CLASSID ); if ( objclass == CLASS_ID_INVALID ) { return TRUE; } GenObject *gobj = ObjClasses[ objclass ]; // guard against empty base objects if ( gobj->NumFaces == 0 ) { CON_AddLine( base_object_empty ); return TRUE; } // display info about specified face char *faceid = faceinfo_key_value[ KEY_FACEINFO_FACEID ].value; if ( faceid != NULL ) { dword maxfaceid = gobj->NumFaces - 1; // read face id int faceid; if ( ScanKeyValueInt( &faceinfo_key_value[ KEY_FACEINFO_FACEID ], &faceid ) < 0 ) { CON_AddLine( face_id_invalid ); return TRUE; } if ( ( faceid < 0 ) || ( (dword)faceid > maxfaceid ) ) { CON_AddLine( face_id_invalid ); return TRUE; } //TODO: ASSERT( 0 ); return TRUE; } // list all faces with specified texture char *texname = faceinfo_key_value[ KEY_FACEINFO_TEXTURE ].value; if ( texname != NULL ) { TextureMap *texmap = FetchTextureMap( texname ); if ( texmap == NULL ) { CON_AddLine( no_texture_found ); return TRUE; } face_cmp_function = FaceHasTexture; facesearch_texture = texmap; DisplayFaceList( gobj ); return TRUE; } // list all faces with specified shader char *shaderspec = faceinfo_key_value[ KEY_FACEINFO_SHADER ].value; if ( shaderspec != NULL ) { //TODO: ASSERT( 0 ); // face_cmp_function = FaceHasShader; // facesearch_texture = shader; // DisplayFaceList( gobj ); return TRUE; } CON_AddLine( no_face_selected ); return TRUE; }