759 lines
33 KiB
C
Raw Normal View History

/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ThingTemplate.h //////////////////////////////////////////////////////////////////////////
// Author: Colin Day, April 2001
// Desc: Thing templates are a 'roadmap' to creating things
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __THINGTEMPLATE_H_
#define __THINGTEMPLATE_H_
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "Lib/BaseType.h"
#include "Common/AudioEventRTS.h"
#include "Common/FileSystem.h"
#include "Common/GameCommon.h"
#include "Common/Geometry.h"
#include "Common/KindOf.h"
#include "Common/ModuleFactory.h"
#include "Common/Overridable.h"
#include "Common/ProductionPrerequisite.h"
#include "Common/Science.h"
#include "Common/UnicodeString.h"
#include "GameLogic/ArmorSet.h"
#include "GameLogic/WeaponSet.h"
#include "Common/STLTypedefs.h"
#include "GameClient/Color.h"
// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
class AIUpdateModuleData;
class Image;
class Object;
class Drawable;
class ProductionPrerequisite;
struct FieldParse;
class Player;
class INI;
enum RadarPriorityType;
enum ScienceType;
enum EditorSortingType;
enum ShadowType;
class WeaponTemplateSet;
class ArmorTemplateSet;
class FXList;
// TYPEDEFS FOR FILE //////////////////////////////////////////////////////////////////////////////
typedef std::map<AsciiString, AudioEventRTS> PerUnitSoundMap;
typedef std::map<AsciiString, const FXList*> PerUnitFXMap;
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//Code renderer handles these states now.
//enum InventoryImageType
//{
// INV_IMAGE_ENABLED = 0,
// INV_IMAGE_DISABLED,
// INV_IMAGE_HILITE,
// INV_IMAGE_PUSHED,
//
// INV_IMAGE_NUM_IMAGES // keep this last
//
//};
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
enum
{
MAX_UPGRADE_CAMEO_UPGRADES = 5
};
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
enum ThingTemplateAudioType
{
TTAUDIO_voiceSelect, ///< Response when unit is selected
TTAUDIO_voiceGroupSelect, ///< Response when a group of this unit is selected
TTAUDIO_voiceSelectElite, ///< Response when unit is selected and elite
TTAUDIO_voiceMove, ///< Response when unit moves
TTAUDIO_voiceAttack, ///< Response when unit is told to attack
TTAUDIO_voiceEnter, ///< Response when unit is told to enter a building
TTAUDIO_voiceFear, ///< Response when unit is under attack
TTAUDIO_voiceCreated, ///< Response when unit is created
TTAUDIO_voiceNearEnemy, ///< Unit is near an enemy
TTAUDIO_voiceTaskUnable, ///< Unit is told to do something impossible
TTAUDIO_voiceTaskComplete, ///< Unit completes a move, or other task indicated
TTAUDIO_voiceMeetEnemy, ///< Unit meets an enemy unit
TTAUDIO_soundMoveStart, ///< Sound when unit starts moving
TTAUDIO_soundMoveStartDamaged, ///< Sound when unit starts moving and is damaged
TTAUDIO_soundMoveLoop, ///< Sound when unit is moving
TTAUDIO_soundMoveLoopDamaged, ///< Sound when unit is moving and is damaged
TTAUDIO_soundDie, ///< Sound when unit is dieing
TTAUDIO_soundCrush, ///< Sound when unit is crushed
TTAUDIO_soundAmbient, ///< Ambient sound for unit during normal status. Also the default sound
TTAUDIO_soundAmbientDamaged, ///< Ambient sound for unit if damaged. Corresponds to body info damage
TTAUDIO_soundAmbientReallyDamaged,///< Ambient sound for unit if badly damaged.
TTAUDIO_soundAmbientRubble, ///< Ambient sound for unit if it is currently rubble. (Dam, for instance)
TTAUDIO_soundStealthOn, ///< Sound when unit stealths
TTAUDIO_soundStealthOff, ///< Sound when unit destealths
TTAUDIO_soundCreated, ///< Sound when unit is created
TTAUDIO_soundOnDamaged, ///< Sound when unit enters damaged state
TTAUDIO_soundOnReallyDamaged, ///< Sound when unit enters reallyd damaged state
TTAUDIO_soundDieFire, ///< Sound when unit dies by fire. NOTE: Replaces soundDie if present and unit dies by fire.
TTAUDIO_soundDieToxin, ///< Sound when unit dies by Toxin. NOTE: Replaces soundDie if present and unit dies by fire.
TTAUDIO_soundEnter, ///< Sound when another unit enters me.
TTAUDIO_soundExit, ///< Sound when another unit exits me.
TTAUDIO_soundPromotedVeteran, ///< Sound when unit gets promoted to Veteran level
TTAUDIO_soundPromotedElite, ///< Sound when unit gets promoted to Elite level
TTAUDIO_soundPromotedHero, ///< Sound when unit gets promoted to Hero level
TTAUDIO_voiceGarrison, ///< Unit is ordered to enter a garrisonable building
TTAUDIO_soundFalling, ///< This sound is actually called on a unit when it is exiting another.
///< However, there is a soundExit which refers to the container, and this is only used for bombs falling from planes.
#ifdef ALLOW_SURRENDER
TTAUDIO_voiceSurrender, ///< Unit surrenders
#endif
TTAUDIO_voiceDefect, ///< Unit is forced to defect
TTAUDIO_voiceAttackSpecial, ///< Unit is ordered to use a special attack
TTAUDIO_voiceAttackAir, ///< Unit is ordered to attack an airborne unit
TTAUDIO_voiceGuard, ///< Unit is ordered to guard an area
TTAUDIO_COUNT // keep last!
};
class AudioArray
{
public:
DynamicAudioEventRTS* m_audio[TTAUDIO_COUNT];
AudioArray()
{
for (Int i = 0; i < TTAUDIO_COUNT; ++i)
m_audio[i] = NULL;
}
~AudioArray()
{
for (Int i = 0; i < TTAUDIO_COUNT; ++i)
if (m_audio[i])
m_audio[i]->deleteInstance();
}
AudioArray(const AudioArray& that)
{
for (Int i = 0; i < TTAUDIO_COUNT; ++i)
{
if (that.m_audio[i])
m_audio[i] = newInstance(DynamicAudioEventRTS)(*that.m_audio[i]);
else
m_audio[i] = NULL;
}
}
AudioArray& operator=(const AudioArray& that)
{
if (this != &that)
{
for (Int i = 0; i < TTAUDIO_COUNT; ++i)
{
if (that.m_audio[i])
{
if (m_audio[i])
*m_audio[i] = *that.m_audio[i];
else
m_audio[i] = newInstance(DynamicAudioEventRTS)(*that.m_audio[i]);
}
else
{
m_audio[i] = NULL;
}
}
}
return *this;
}
};
//-------------------------------------------------------------------------------------------------
/** Object class type enumeration */
//-------------------------------------------------------------------------------------------------
enum BuildCompletionType
{
BC_INVALID = 0,
BC_APPEARS_AT_RALLY_POINT, ///< unit appears at rally point of its #1 prereq
BC_PLACED_BY_PLAYER, ///< unit must be manually placed by player
BC_NUM_TYPES // leave this last
};
#ifdef DEFINE_BUILD_COMPLETION_NAMES
static const char *BuildCompletionNames[] =
{
"INVALID",
"APPEARS_AT_RALLY_POINT",
"PLACED_BY_PLAYER",
NULL
};
#endif // end DEFINE_BUILD_COMPLETION_NAMES
enum BuildableStatus
{
// saved into savegames... do not change or remove values!
BSTATUS_YES = 0,
BSTATUS_IGNORE_PREREQUISITES,
BSTATUS_NO,
BSTATUS_ONLY_BY_AI,
BSTATUS_NUM_TYPES // leave this last
};
#ifdef DEFINE_BUILDABLE_STATUS_NAMES
static const char *BuildableStatusNames[] =
{
"Yes",
"Ignore_Prerequisites",
"No",
"Only_By_AI",
NULL
};
#endif // end DEFINE_BUILDABLE_STATUS_NAMES
//-------------------------------------------------------------------------------------------------
enum ModuleParseMode
{
MODULEPARSE_NORMAL,
MODULEPARSE_ADD_REMOVE_REPLACE,
MODULEPARSE_INHERITABLE
};
//-------------------------------------------------------------------------------------------------
class ModuleInfo
{
private:
struct Nugget
{
AsciiString first;
AsciiString m_moduleTag;
const ModuleData* second;
Int interfaceMask;
Bool copiedFromDefault;
Bool inheritable;
Nugget(const AsciiString& n, const AsciiString& moduleTag, const ModuleData* d, Int i, Bool inh)
: first(n),
m_moduleTag(moduleTag),
second(d),
interfaceMask(i),
copiedFromDefault(false),
inheritable(inh)
{
}
};
std::vector<Nugget> m_info;
public:
ModuleInfo() { }
void addModuleInfo(ThingTemplate *thingTemplate, const AsciiString& name, const AsciiString& moduleTag, const ModuleData* data, Int interfaceMask, Bool inheritable);
const ModuleInfo::Nugget *ModuleInfo::getNuggetWithTag( const AsciiString& tag ) const;
Int getCount() const
{
return m_info.size();
}
#if defined(_DEBUG) || defined(_INTERNAL)
Bool containsPartialName(const char* n) const
{
for (int i = 0; i < m_info.size(); i++)
if (strstr(m_info[i].first.str(), n) != NULL)
return true;
return false;
}
#endif
AsciiString getNthName(Int i) const
{
if (i >= 0 && i < m_info.size())
{
return m_info[i].first;
}
return AsciiString::TheEmptyString;
}
AsciiString getNthTag(Int i) const
{
if (i >= 0 && i < m_info.size())
{
return m_info[i].m_moduleTag;
}
return AsciiString::TheEmptyString;
}
const ModuleData* getNthData(Int i) const
{
if (i >= 0 && i < m_info.size())
{
return m_info[i].second;
}
return NULL;
}
// for use only by ThingTemplate::friend_getAIModuleInfo
ModuleData* friend_getNthData(Int i);
void clear()
{
m_info.clear();
}
void setCopiedFromDefault(Bool v)
{
for (int i = 0; i < m_info.size(); i++)
m_info[i].copiedFromDefault = v;
}
Bool clearModuleDataWithTag(const AsciiString& tagToClear, AsciiString& clearedModuleNameOut);
Bool clearCopiedFromDefaultEntries(Int interfaceMask);
Bool clearAiModuleInfo();
};
//-------------------------------------------------------------------------------------------------
/** Definition of a thing template to read from our game data framework */
//-------------------------------------------------------------------------------------------------
class ThingTemplate : public Overridable
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(ThingTemplate, "ThingTemplatePool" )
private:
ThingTemplate(const ThingTemplate& that) : m_geometryInfo(that.m_geometryInfo)
{
DEBUG_CRASH(("This should never be called\n"));
}
public:
ThingTemplate();
// copy the guts of that into this, but preserve this' name, id, and list-links.
void copyFrom(const ThingTemplate* that);
/// called by ThingFactory after all templates have been loaded.
void resolveNames();
#ifdef LOAD_TEST_ASSETS
void initForLTA(const AsciiString& name);
inline AsciiString getLTAName() const { return m_LTAName; }
#endif
/**
return a unique identifier suitable for identifying this ThingTemplate on machines playing
across the net. this should be considered a Magic Cookie and used only for net traffic or
similar sorts of things. To convert an id back to a ThingTemplate, use ThingFactory::findByID().
Note that 0 is always an invalid id. NOTE that we are not referencing m_override here
because even though we actually have multiple templates here representing overrides,
we still only conceptually have one template and want to always use one single
pointer for comparisons of templates. However, even if we did reference m_override
the IDs would be the same for each one since every override first *COPIES* data
from the current/parent template data.
*/
UnsignedShort getTemplateID() const { return m_templateID; }
// note that m_override is not used here, see getTemplateID(), for it is the same reasons
const AsciiString& getName() const { return m_nameString; } ///< return the name of this template
/// get the display color (used for the editor)
Color getDisplayColor() const { return m_displayColor; }
/// get the editor sorting
EditorSortingType getEditorSorting() const { return (EditorSortingType)m_editorSorting; }
/// return true iff the template has the specified kindOf flag set.
inline Bool isKindOf(KindOfType t) const
{
return TEST_KINDOFMASK(m_kindof, t);
}
/// convenience for doing multiple kindof testing at once.
inline Bool isKindOfMulti(const KindOfMaskType& mustBeSet, const KindOfMaskType& mustBeClear) const
{
return TEST_KINDOFMASK_MULTI(m_kindof, mustBeSet, mustBeClear);
}
inline Bool isAnyKindOf( const KindOfMaskType& anyKindOf ) const
{
return TEST_KINDOFMASK_ANY(m_kindof, anyKindOf);
}
/// set the display name
const UnicodeString& getDisplayName() const { return m_displayName; } ///< return display name
RadarPriorityType getDefaultRadarPriority() const { return (RadarPriorityType)m_radarPriority; } ///< return radar priority from INI
// note, you should not call this directly; rather, call Object::getTransportSlotCount().
Int getRawTransportSlotCount() const { return m_transportSlotCount; }
Real getFenceWidth() const { return m_fenceWidth; } // return fence width
Real getFenceXOffset() const { return m_fenceXOffset; } // return fence offset
Bool isBridge() const { return m_isBridge; } // return fence offset
// Only Object can ask this. Everyone else should ask the Object. In fact, you really should ask the Object everything.
Real friend_getVisionRange() const { return m_visionRange; } ///< get vision range
Real friend_getShroudClearingRange() const { return m_shroudClearingRange; } ///< get vision range for Shroud ONLY (Design requested split)
// This function is only for use by the AIUpdateModuleData::parseLocomotorSet function.
AIUpdateModuleData *friend_getAIModuleInfo(void);
ShadowType getShadowType() const { return (ShadowType)m_shadowType; }
Real getShadowSizeX() const { return m_shadowSizeX; }
Real getShadowSizeY() const { return m_shadowSizeY; }
Real getShadowOffsetX() const { return m_shadowOffsetX; }
Real getShadowOffsetY() const { return m_shadowOffsetY; }
const AsciiString& getShadowTextureName( void ) const { return m_shadowTextureName; }
UnsignedInt getOcclusionDelay(void) const { return m_occlusionDelay;}
const ModuleInfo& getBehaviorModuleInfo() const { return m_behaviorModuleInfo; }
const ModuleInfo& getDrawModuleInfo() const { return m_drawModuleInfo; }
const ModuleInfo& getClientUpdateModuleInfo() const { return m_clientUpdateModuleInfo; }
const Image *getSelectedPortraitImage( void ) const { return m_selectedPortraitImage; }
const Image *getButtonImage( void ) const { return m_buttonImage; }
//Code renderer handles these states now.
//const AsciiString& getInventoryImageName( InventoryImageType type ) const { return m_inventoryImage[ type ]; }
Int getSkillPointValue(Int level) const;
Int getExperienceValue(Int level) const { return m_experienceValues[level]; }
Int getExperienceRequired(Int level) const {return m_experienceRequired[level]; }
Bool isTrainable() const{return m_isTrainable; }
const AudioEventRTS *getVoiceSelect() const { return getAudio(TTAUDIO_voiceSelect); }
const AudioEventRTS *getVoiceGroupSelect() const { return getAudio(TTAUDIO_voiceGroupSelect); }
const AudioEventRTS *getVoiceMove() const { return getAudio(TTAUDIO_voiceMove); }
const AudioEventRTS *getVoiceAttack() const { return getAudio(TTAUDIO_voiceAttack); }
const AudioEventRTS *getVoiceEnter() const { return getAudio(TTAUDIO_voiceEnter); }
const AudioEventRTS *getVoiceFear() const { return getAudio(TTAUDIO_voiceFear); }
const AudioEventRTS *getVoiceSelectElite() const { return getAudio(TTAUDIO_voiceSelectElite); }
const AudioEventRTS *getVoiceCreated() const { return getAudio(TTAUDIO_voiceCreated); }
const AudioEventRTS *getVoiceNearEnemy() const { return getAudio(TTAUDIO_voiceNearEnemy); }
const AudioEventRTS *getVoiceTaskUnable() const { return getAudio(TTAUDIO_voiceTaskUnable); }
const AudioEventRTS *getVoiceTaskComplete() const { return getAudio(TTAUDIO_voiceTaskComplete); }
const AudioEventRTS *getVoiceMeetEnemy() const { return getAudio(TTAUDIO_voiceMeetEnemy); }
const AudioEventRTS *getVoiceGarrison() const { return getAudio(TTAUDIO_voiceGarrison); }
#ifdef ALLOW_SURRENDER
const AudioEventRTS *getVoiceSurrender() const { return getAudio(TTAUDIO_voiceSurrender); }
#endif
const AudioEventRTS *getVoiceDefect() const { return getAudio(TTAUDIO_voiceDefect); }
const AudioEventRTS *getVoiceAttackSpecial() const { return getAudio(TTAUDIO_voiceAttackSpecial); }
const AudioEventRTS *getVoiceAttackAir() const { return getAudio(TTAUDIO_voiceAttackAir); }
const AudioEventRTS *getVoiceGuard() const { return getAudio(TTAUDIO_voiceGuard); }
const AudioEventRTS *getSoundMoveStart() const { return getAudio(TTAUDIO_soundMoveStart); }
const AudioEventRTS *getSoundMoveStartDamaged() const { return getAudio(TTAUDIO_soundMoveStartDamaged); }
const AudioEventRTS *getSoundMoveLoop() const { return getAudio(TTAUDIO_soundMoveLoop); }
const AudioEventRTS *getSoundMoveLoopDamaged() const { return getAudio(TTAUDIO_soundMoveLoopDamaged); }
const AudioEventRTS *getSoundDie() const { return getAudio(TTAUDIO_soundDie); }
const AudioEventRTS *getSoundCrush() const { return getAudio(TTAUDIO_soundCrush); }
const AudioEventRTS *getSoundAmbient() const { return getAudio(TTAUDIO_soundAmbient); }
const AudioEventRTS *getSoundAmbientDamaged() const { return getAudio(TTAUDIO_soundAmbientDamaged); }
const AudioEventRTS *getSoundAmbientReallyDamaged() const { return getAudio(TTAUDIO_soundAmbientReallyDamaged); }
const AudioEventRTS *getSoundAmbientRubble() const { return getAudio(TTAUDIO_soundAmbientRubble); }
const AudioEventRTS *getSoundStealthOn() const { return getAudio(TTAUDIO_soundStealthOn); }
const AudioEventRTS *getSoundStealthOff() const { return getAudio(TTAUDIO_soundStealthOff); }
const AudioEventRTS *getSoundCreated() const { return getAudio(TTAUDIO_soundCreated); }
const AudioEventRTS *getSoundOnDamaged() const { return getAudio(TTAUDIO_soundOnDamaged); }
const AudioEventRTS *getSoundOnReallyDamaged() const { return getAudio(TTAUDIO_soundOnReallyDamaged); }
const AudioEventRTS *getSoundDieFire() const { return getAudio(TTAUDIO_soundDieFire); }
const AudioEventRTS *getSoundDieToxin() const { return getAudio(TTAUDIO_soundDieToxin); }
const AudioEventRTS *getSoundEnter() const { return getAudio(TTAUDIO_soundEnter); }
const AudioEventRTS *getSoundExit() const { return getAudio(TTAUDIO_soundExit); }
const AudioEventRTS *getSoundPromotedVeteran() const { return getAudio(TTAUDIO_soundPromotedVeteran); }
const AudioEventRTS *getSoundPromotedElite() const { return getAudio(TTAUDIO_soundPromotedElite); }
const AudioEventRTS *getSoundPromotedHero() const { return getAudio(TTAUDIO_soundPromotedHero); }
const AudioEventRTS *getSoundFalling() const { return getAudio(TTAUDIO_soundFalling); }
const AudioEventRTS *getPerUnitSound(const AsciiString& soundName) const;
const FXList* getPerUnitFX(const AsciiString& fxName) const;
UnsignedInt getThreatValue() const { return m_threatValue; }
UnsignedInt getMaxSimultaneousOfType() const { return m_maxSimultaneousOfType; }
void validate();
// The version that does not take an Object argument is labeled friend for use by WorldBuilder. All game requests
// for CommandSet must use Object::getCommandSetString, as we have two different sources for dynamic answers.
const AsciiString& friend_getCommandSetString() const { return m_commandSetString; }
const std::vector<AsciiString>& getBuildVariations() const { return m_buildVariations; }
Real getAssetScale() const { return m_assetScale; } ///< return uniform scaling
Real getInstanceScaleFuzziness() const { return m_instanceScaleFuzziness; } ///< return uniform scaling
Real getStructureRubbleHeight() const { return (Real)m_structureRubbleHeight; } ///< return uniform scaling
/*
NOTE: if you have a Thing, don't call this function; call Thing::getGeometryInfo instead, since
geometry can now vary on a per-object basis. Only call this when you have no Thing around,
and want to get info for the "prototype" (eg, for building new Things)...
*/
const GeometryInfo& getTemplateGeometryInfo() const { return m_geometryInfo; }
//
// these are intended ONLY for the private use of ThingFactory and do not use
// the m_override pointer, it deals only with templates at the "top" level
//
inline void friend_setTemplateName( const AsciiString& name ) { m_nameString = name; }
inline ThingTemplate *friend_getNextTemplate() const { return m_nextThingTemplate; }
inline void friend_setNextTemplate(ThingTemplate *tmplate) { m_nextThingTemplate = tmplate; }
inline void friend_setTemplateID(UnsignedShort id) { m_templateID = id; }
Int getEnergyProduction() const { return m_energyProduction; }
Int getEnergyBonus() const { return m_energyBonus; }
// these are NOT publicly available; you should call calcCostToBuild() or calcTimeToBuild()
// instead, because they will take player handicaps into account.
// Int getBuildCost() const { return m_buildCost; }
Int getRefundValue() const { return m_refundValue; }
BuildCompletionType getBuildCompletion() const { return (BuildCompletionType)m_buildCompletion; }
BuildableStatus getBuildable() const;
Int getPrereqCount() const { return m_prereqInfo.size(); }
const ProductionPrerequisite *getNthPrereq(Int i) const { return &m_prereqInfo[i]; }
/**
return the BuildFacilityTemplate, if any.
if this template needs no build facility, null is returned.
if the template needs a build facility but the given player doesn't have any in existence,
null will be returned.
if you pass null for player, we'll return the 'natural' build facility.
*/
const ThingTemplate *getBuildFacilityTemplate( const Player *player ) const;
Bool isBuildableItem(void) const;
/// calculate how long (in logic frames) it will take the given player to build this unit
Int calcTimeToBuild( const Player* player) const;
/// calculate how much money it will take the given player to build this unit
Int calcCostToBuild( const Player* player) const;
/// Used only by Skirmish AI. Everyone else should call calcCostToBuild.
Int friend_getBuildCost() const { return m_buildCost; }
const AsciiString& getDefaultOwningSide() const { return m_defaultOwningSide; }
/// get us the table to parse the fields for thing templates
const FieldParse* getFieldParse() const { return s_objectFieldParseTable; }
const FieldParse* getReskinFieldParse() const { return s_objectReskinFieldParseTable; }
Bool isBuildFacility() const { return m_isBuildFacility; }
Real getPlacementViewAngle( void ) const { return m_placementViewAngle; }
Real getFactoryExitWidth() const { return m_factoryExitWidth; }
Real getFactoryExtraBibWidth() const { return m_factoryExtraBibWidth; }
void setCopiedFromDefault();
void setReskinnedFrom(const ThingTemplate* tt) { DEBUG_ASSERTCRASH(m_reskinnedFrom == NULL, ("should be null")); m_reskinnedFrom = tt; }
Bool isPrerequisite() const { return m_isPrerequisite; }
const WeaponTemplateSet* findWeaponTemplateSet(const WeaponSetFlags& t) const;
const ArmorTemplateSet* findArmorTemplateSet(const ArmorSetFlags& t) const;
// returns true iff we have at least one weaponset that contains a weapon.
// returns false if we have no weaponsets, or they are all empty.
Bool canPossiblyHaveAnyWeapon() const;
Bool isEquivalentTo(const ThingTemplate* tt) const;
UnsignedByte getCrushableLevel() const { return m_crushableLevel; }
UnsignedByte getCrusherLevel() const { return m_crusherLevel; }
AsciiString getUpgradeCameoName( Int n)const{ return m_upgradeCameoUpgradeNames[n]; }
protected:
//
// these are NOT publicly available; you should call calcCostToBuild() or calcTimeToBuild()
// instead, because they will take player handicaps into account.
//
Int getBuildCost() const { return m_buildCost; }
Real getBuildTime() const { return m_buildTime; }
const PerUnitSoundMap* getAllPerUnitSounds( void ) const { return &m_perUnitSounds; }
void validateAudio();
const AudioEventRTS* getAudio(ThingTemplateAudioType t) const { return m_audioarray.m_audio[t] ? &m_audioarray.m_audio[t]->m_event : &s_audioEventNoSound; }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** Table for parsing the object fields */
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void parseArmorTemplateSet( INI* ini, void *instance, void *store, const void* /*userData*/ );
static void parseWeaponTemplateSet( INI* ini, void *instance, void *store, const void* /*userData*/ );
static void parsePrerequisites( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
static void parseModuleName(INI* ini, void *instance, void* /*store*/, const void* userData);
static void parseIntList(INI* ini, void *instance, void* store, const void* userData);
static void parsePerUnitSounds(INI* ini, void *instance, void* store, const void* userData);
static void parsePerUnitFX(INI* ini, void *instance, void* store, const void* userData);
static void parseAddModule(INI *ini, void *instance, void *store, const void *userData);
static void parseRemoveModule(INI *ini, void *instance, void *store, const void *userData);
static void parseReplaceModule(INI *ini, void *instance, void *store, const void *userData);
static void parseInheritableModule(INI *ini, void *instance, void *store, const void *userData);
Bool removeModuleInfo(const AsciiString& moduleToRemove, AsciiString& clearedModuleNameOut);
private:
static const FieldParse s_objectFieldParseTable[]; ///< the parse table
static const FieldParse s_objectReskinFieldParseTable[]; ///< the parse table
static AudioEventRTS s_audioEventNoSound;
private:
// ---- Strings
UnicodeString m_displayName; ///< UI display for onscreen display
AsciiString m_nameString; ///< name of this thing template
AsciiString m_defaultOwningSide; ///< default owning side (owning player is inferred)
AsciiString m_commandSetString;
AsciiString m_selectedPortraitImageName;
AsciiString m_buttonImageName;
AsciiString m_upgradeCameoUpgradeNames[MAX_UPGRADE_CAMEO_UPGRADES]; ///< Use these to find the upgrade images to display on the control bar
AsciiString m_shadowTextureName; ///< name of texture to use for shadow decal
AsciiString m_moduleBeingReplacedName; ///< used only during map.ini loading... name (not tag) of Module being replaced, or empty if not inside ReplaceModule block
AsciiString m_moduleBeingReplacedTag; ///< used only during map.ini loading... tag (not name) of Module being replaced, or empty if not inside ReplaceModule block
#ifdef LOAD_TEST_ASSETS
AsciiString m_LTAName;
#endif
// ---- Misc Larger-than-int things
GeometryInfo m_geometryInfo; ///< geometry information
KindOfMaskType m_kindof; ///< kindof bits
AudioArray m_audioarray;
ModuleInfo m_behaviorModuleInfo;
ModuleInfo m_drawModuleInfo;
ModuleInfo m_clientUpdateModuleInfo;
// ---- Misc Arrays-of-things
Int m_skillPointValues[LEVEL_COUNT];
Int m_experienceValues[LEVEL_COUNT]; ///< How much I am worth at each experience level
Int m_experienceRequired[LEVEL_COUNT]; ///< How many experience points I need for each level
//Code renderer handles these states now.
//AsciiString m_inventoryImage[ INV_IMAGE_NUM_IMAGES ]; ///< portrait inventory pictures
// ---- STL-sized things
std::vector<ProductionPrerequisite> m_prereqInfo; ///< the unit Prereqs for this tech
std::vector<AsciiString> m_buildVariations; /**< if we build a unit of this type via script or ui, randomly choose one
of these templates instead. (doesn't apply to MapObject-created items) */
WeaponTemplateSetVector m_weaponTemplateSets; ///< our weaponsets
WeaponTemplateSetFinder m_weaponTemplateSetFinder; ///< helper to allow us to find the best sets, quickly
ArmorTemplateSetVector m_armorTemplateSets; ///< our armorsets
ArmorTemplateSetFinder m_armorTemplateSetFinder; ///< helper to allow us to find the best sets, quickly
PerUnitSoundMap m_perUnitSounds; ///< An additional set of sounds that only apply for this template.
PerUnitFXMap m_perUnitFX; ///< An additional set of fx that only apply for this template.
// ---- Pointer-sized things
ThingTemplate* m_nextThingTemplate;
const ThingTemplate* m_reskinnedFrom; ///< non NULL if we were generated via a reskin
const Image * m_selectedPortraitImage; /// portrait image when selected (to display in GUI)
const Image * m_buttonImage;
// ---- Real-sized things
Real m_fenceWidth; ///< Fence width for fence type objects.
Real m_fenceXOffset; ///< Fence X offset for fence type objects.
Real m_visionRange; ///< object "sees" this far around itself
Real m_shroudClearingRange; ///< Since So many things got added to "Seeing" functionality, we need to split this part out.
Real m_placementViewAngle; ///< when placing buildings this will be the angle of the building when "floating" at the mouse
Real m_factoryExitWidth; ///< when placing buildings this will be the width of the reserved exit area on the right side.
Real m_factoryExtraBibWidth; ///< when placing buildings this will be the width of the reserved exit area on the right side.
Real m_buildTime; ///< Seconds to build
Real m_assetScale;
Real m_instanceScaleFuzziness; ///< scale randomization tolerance to init for each Drawable instance,
Real m_shadowSizeX; ///< world-space extent of decal shadow texture
Real m_shadowSizeY; ///< world-space extent of decal shadow texture
Real m_shadowOffsetX; ///< world-space offset of decal shadow texture
Real m_shadowOffsetY; ///< world-space offset of decal shadow texture
// ---- Int-sized things
Int m_energyProduction; ///< how much Energy this takes (negative values produce Energy, rather than consuming it)
Int m_energyBonus; ///< how much extra Energy this produces due to the upgrade
Color m_displayColor; ///< for the editor display color
UnsignedInt m_occlusionDelay; ///< delay after object creation before building occlusion is allowed.
// ---- Short-sized things
UnsignedShort m_templateID; ///< id for net (etc.) transmission purposes
UnsignedShort m_buildCost; ///< money to build (0 == not buildable)
UnsignedShort m_refundValue; ///< custom resale value, if sold. (0 == use default)
UnsignedShort m_threatValue; ///< Threat map info
UnsignedShort m_maxSimultaneousOfType; ///< max simultaneous of this unit we can have (per player) at one time. (0 == unlimited)
// ---- Bool-sized things
Bool m_isPrerequisite; ///< Is this thing considered in a prerequisite for any other thing?
Bool m_isBridge; ///< True if this model is a bridge.
Bool m_isBuildFacility; ///< is this the build facility for something? (calculated based on other template's prereqs)
Bool m_isTrainable; ///< Whether or not I can even gain experience
Bool m_isForbidden; ///< useful when overriding in <mapfile>.ini
Bool m_armorCopiedFromDefault;
Bool m_weaponsCopiedFromDefault;
// ---- Byte-sized things
Byte m_radarPriority; ///< does object appear on radar, and if so at what priority
Byte m_transportSlotCount; ///< how many "slots" we take in a transport (0 == not transportable)
Byte m_buildable; ///< is this thing buildable at all?
Byte m_buildCompletion; ///< how the units come into the world when build is complete
Byte m_editorSorting; ///< editor sorting type, see EditorSortingType enum
Byte m_structureRubbleHeight;
Byte m_shadowType; ///< settings which determine the type of shadow rendered
Byte m_moduleParsingMode;
UnsignedByte m_crusherLevel; ///< crusher > crushable level to actually crush
UnsignedByte m_crushableLevel; ///< Specifies the level of crushability (must be hit by a crusher greater than this to crush me).
};
//-----------------------------------------------------------------------------
// Inlining
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Externals
//-----------------------------------------------------------------------------
#endif // __THINGTEMPLATE_H_