/* MEDIA.C Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc. and the "Aleph One" developers. 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. This license is contained in the file "COPYING", which is included with this source code; it is available online at http://www.gnu.org/licenses/gpl.html Sunday, March 26, 1995 1:13:11 AM (Jason') May 17, 2000 (Loren Petrich): Added XML support, including a damage parser May 26, 2000 (Loren Petrich): Added XML shapes support June 3, 2000 (Loren Petrich): Added some idiot-proofing: if a liquid type is not found, then it is assumed to be nonexistent. This is implemented by returning the null pointer. July 1, 2000 (Loren Petrich): Inlined the media accessors Aug 29, 2000 (Loren Petrich): Added packing and unpacking routines Feb 8, 2001 (Loren Petrich): Fixed liquid-count bug in parallel with similar bug in map.cpp */ #include "cseries.h" #include "map.h" #include "media.h" #include "effects.h" #include "fades.h" #include "lightsource.h" #include "SoundManager.h" #include "Packing.h" // LP addition: XML parser for damage #include "DamageParser.h" #include #ifdef env68k #pragma segment marathon #endif /* ---------- macros */ #define CALCULATE_MEDIA_HEIGHT(m) ((m)->low + FIXED_INTEGERAL_PART(((m)->high-(m)->low)*get_light_intensity((m)->light_index))) /* ---------- globals */ // Turned the list of liquids into a variable array; // took over their maximum number as how many of them vector MediaList; // struct media_data *medias; /* ---------- private prototypes */ static void update_one_media(size_t media_index, bool force_update); /* ---------- globals */ #include "media_definitions.h" static media_definition *get_media_definition( const short type); /* ---------- code */ media_data *get_media_data( const size_t media_index) { struct media_data *media = GetMemberWithBounds(medias,media_index,MAXIMUM_MEDIAS_PER_MAP); if (!media) return NULL; if (!(SLOT_IS_USED(media))) return NULL; return media; } // LP change: moved down here because it uses liquid definitions media_definition *get_media_definition( const short type) { return GetMemberWithBounds(media_definitions,type,NUMBER_OF_MEDIA_TYPES); } // light_index must be loaded size_t new_media( struct media_data *initializer) { struct media_data *media; size_t media_index; for (media_index= 0, media= medias; media_indexorigin.x= media->origin.y= 0; update_one_media(media_index, true); break; } } if (media_index==MAXIMUM_MEDIAS_PER_MAP) media_index= UNONE; return media_index; } bool media_in_environment( short media_type, short environment_code) { // LP change: idiot-proofing struct media_definition *definition= get_media_definition(media_type); if (!definition) return false; return collection_in_environment(definition->collection, environment_code); } void update_medias( void) { size_t media_index; struct media_data *media; for (media_index= 0, media= medias; media_indexorigin.x= WORLD_FRACTIONAL_PART(media->origin.x + ((cosine_table[media->current_direction]*media->current_magnitude)>>TRIG_SHIFT)); media->origin.y= WORLD_FRACTIONAL_PART(media->origin.y + ((sine_table[media->current_direction]*media->current_magnitude)>>TRIG_SHIFT)); } } } void get_media_detonation_effect( short media_index, short type, short *detonation_effect) { struct media_data *media= get_media_data(media_index); // LP change: idiot-proofing if (!media) return; struct media_definition *definition= get_media_definition(media->type); if (!definition) return; if (type!=NONE) { if (!(type>=0 && typedetonation_effects[type]!=NONE) *detonation_effect= definition->detonation_effects[type]; } } short get_media_sound( short media_index, short type) { struct media_data *media= get_media_data(media_index); // LP change: idiot-proofing if (!media) return NONE; struct media_definition *definition= get_media_definition(media->type); if (!definition) return NONE; if (!(type>=0 && typesounds[type]; } struct damage_definition *get_media_damage( short media_index, _fixed scale) { struct media_data *media= get_media_data(media_index); // LP change: idiot-proofing if (!media) return NULL; struct media_definition *definition= get_media_definition(media->type); if (!definition) return NULL; struct damage_definition *damage= &definition->damage; damage->scale= scale; return (damage->type==NONE || (dynamic_world->tick_count&definition->damage_frequency)) ? (struct damage_definition *) NULL : damage; } short get_media_submerged_fade_effect( short media_index) { struct media_data *media= get_media_data(media_index); // LP change: idiot-proofing if (!media) return NONE; struct media_definition *definition= get_media_definition(media->type); if (!definition) return NONE; return definition->submerged_fade_effect; } bool get_media_collection(short media_index, short& collection) { media_data *media = get_media_data(media_index); if (!media) return false; media_definition *definition = get_media_definition(media->type); if (!definition) return false; collection = definition->collection; return true; } // LP addition: bool IsMediaDangerous(short media_index) { media_definition *definition = get_media_definition(media_index); if (!definition) return false; struct damage_definition *damage= &definition->damage; if (damage->type == NONE) return false; else return (damage->base > 0); } /* ---------- private code */ static void update_one_media( size_t media_index, bool force_update) { struct media_data *media= get_media_data(media_index); // LP change: idiot-proofing if (!media) return; struct media_definition *definition= get_media_definition(media->type); if (!definition) return; /* update height */ media->height= (media->low + FIXED_INTEGERAL_PART((media->high-media->low)*get_light_intensity(media->light_index))); /* update texture */ media->texture= BUILD_DESCRIPTOR(definition->collection, definition->shape); media->transfer_mode= definition->transfer_mode; #if 0 if (force_update || !(dynamic_world->tick_count&definition->shape_frequency)) { shape_descriptor texture; do { texture= BUILD_DESCRIPTOR(definition->collection, definition->shape + global_random()%definition->shape_count); } while (definition->shape_count>1 && texture==media->texture); media->texture= BUILD_DESCRIPTOR(definition->collection, definition->shape); media->transfer_mode= definition->transfer_mode; } #else (void)force_update; #endif } // LP addition: count number of media types used, // for better Infinity compatibility when saving games. // Fixed countdown bug in parallel with similar bug in map.cpp size_t count_number_of_medias_used() { size_t number_used = 0; // Take care of the case of no slots being used for (int media_index=((int)MAXIMUM_MEDIAS_PER_MAP)-1; media_index>=0; media_index--) { // Look for the last used one rather than the last unused one! if (SLOT_IS_USED(medias + media_index)) { number_used = (size_t)(media_index + 1); break; } } return number_used; } uint8 *unpack_media_data(uint8 *Stream, media_data* Objects, size_t Count) { uint8* S = Stream; media_data* ObjPtr = Objects; for (size_t k = 0; k < Count; k++, ObjPtr++) { StreamToValue(S,ObjPtr->type); StreamToValue(S,ObjPtr->flags); StreamToValue(S,ObjPtr->light_index); StreamToValue(S,ObjPtr->current_direction); StreamToValue(S,ObjPtr->current_magnitude); StreamToValue(S,ObjPtr->low); StreamToValue(S,ObjPtr->high); StreamToValue(S,ObjPtr->origin.x); StreamToValue(S,ObjPtr->origin.y); StreamToValue(S,ObjPtr->height); StreamToValue(S,ObjPtr->minimum_light_intensity); StreamToValue(S,ObjPtr->texture); StreamToValue(S,ObjPtr->transfer_mode); S += 2*2; } assert((S - Stream) == static_cast(Count*SIZEOF_media_data)); return S; } uint8 *pack_media_data(uint8 *Stream, media_data* Objects, size_t Count) { uint8* S = Stream; media_data* ObjPtr = Objects; for (size_t k = 0; k < Count; k++, ObjPtr++) { ValueToStream(S,ObjPtr->type); ValueToStream(S,ObjPtr->flags); ValueToStream(S,ObjPtr->light_index); ValueToStream(S,ObjPtr->current_direction); ValueToStream(S,ObjPtr->current_magnitude); ValueToStream(S,ObjPtr->low); ValueToStream(S,ObjPtr->high); ValueToStream(S,ObjPtr->origin.x); ValueToStream(S,ObjPtr->origin.y); ValueToStream(S,ObjPtr->height); ValueToStream(S,ObjPtr->minimum_light_intensity); ValueToStream(S,ObjPtr->texture); ValueToStream(S,ObjPtr->transfer_mode); S += 2*2; } assert((S - Stream) == static_cast(Count*SIZEOF_media_data)); return S; } // Parses effect indices // NOTE: this does not need a ResetValues() method because XML_LiquidParser (parent) does it already. class XML_LqEffectParser: public XML_ElementParser { short Type; short Which; enum {NumberOfValues = 2}; bool IsPresent[NumberOfValues]; public: bool Start(); bool HandleAttribute(const char *Tag, const char *Value); bool AttributesDone(); short *EffectList; XML_LqEffectParser(): XML_ElementParser("effect") {} }; bool XML_LqEffectParser::Start() { for (int k=0; k