759 lines
33 KiB
C
759 lines
33 KiB
C
![]() |
/*
|
||
|
** 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_
|
||
|
|