Initial Prey Game integration support.

This commit is contained in:
Justin Marshall
2026-05-05 15:01:01 -07:00
parent a6c6f1ed26
commit 8d5f678b25
552 changed files with 265551 additions and 209 deletions
+24 -37
View File
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.4.11626.88 stable
VisualStudioVersion = 18.4.11626.88
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{347D107C-D787-4408-A60D-86FA45997F9B}"
EndProject
@@ -20,95 +20,81 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MayaImport", "MayaImport.vc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl", "opengl\opengl.vcxproj", "{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "preydlls", "preydlls", "{F65E2305-0208-4A25-BEB0-038C92484211}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PreyGame", "prey\PreyGame.vcxproj", "{6CD8E46D-E28E-493F-BB06-537A637A68C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug with inlines and memory log|x64 = Debug with inlines and memory log|x64
Debug with inlines|x64 = Debug with inlines|x64
Debug|x64 = Debug|x64
Dedicated Debug with inlines|x64 = Dedicated Debug with inlines|x64
Dedicated Debug|x64 = Dedicated Debug|x64
Dedicated Release|x64 = Dedicated Release|x64
Prey Debug|x64 = Prey Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{49BEC5C6-B964-417A-851E-808886B57430}.Debug with inlines and memory log|x64.ActiveCfg = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Debug with inlines and memory log|x64.Build.0 = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Debug with inlines|x64.ActiveCfg = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Debug with inlines|x64.Build.0 = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Debug|x64.ActiveCfg = Debug|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Debug|x64.Build.0 = Debug|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Dedicated Debug with inlines|x64.ActiveCfg = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Dedicated Debug with inlines|x64.Build.0 = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Dedicated Debug|x64.ActiveCfg = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Dedicated Debug|x64.Build.0 = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Dedicated Release|x64.ActiveCfg = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Dedicated Release|x64.Build.0 = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Release|x64.ActiveCfg = Release|x64
{49BEC5C6-B964-417A-851E-808886B57430}.Release|x64.Build.0 = Release|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Debug with inlines and memory log|x64.ActiveCfg = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Debug with inlines and memory log|x64.Build.0 = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Debug with inlines|x64.ActiveCfg = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Debug with inlines|x64.Build.0 = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Debug|x64.ActiveCfg = Debug|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Debug|x64.Build.0 = Debug|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Dedicated Debug with inlines|x64.ActiveCfg = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Dedicated Debug with inlines|x64.Build.0 = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Dedicated Debug|x64.ActiveCfg = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Dedicated Debug|x64.Build.0 = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Dedicated Release|x64.ActiveCfg = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Dedicated Release|x64.Build.0 = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Prey Debug|x64.Build.0 = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Release|x64.ActiveCfg = Release|x64
{49BEC5C6-B964-417A-851E-808886B57400}.Release|x64.Build.0 = Release|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Debug with inlines and memory log|x64.ActiveCfg = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Debug with inlines and memory log|x64.Build.0 = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Debug with inlines|x64.ActiveCfg = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Debug with inlines|x64.Build.0 = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Debug|x64.ActiveCfg = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Debug|x64.Build.0 = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Dedicated Debug with inlines|x64.ActiveCfg = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Dedicated Debug with inlines|x64.Build.0 = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Dedicated Debug|x64.ActiveCfg = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Dedicated Debug|x64.Build.0 = Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Dedicated Release|x64.ActiveCfg = Release|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Dedicated Release|x64.Build.0 = Release|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Prey Debug|x64.Build.0 = Prey Debug|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Release|x64.ActiveCfg = Release|x64
{F46F5D4E-C1D4-4ADE-9FAA-5F0CE3AA07F1}.Release|x64.Build.0 = Release|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Debug with inlines and memory log|x64.ActiveCfg = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Debug with inlines and memory log|x64.Build.0 = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Debug with inlines|x64.ActiveCfg = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Debug with inlines|x64.Build.0 = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Debug|x64.ActiveCfg = Debug|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Debug|x64.Build.0 = Debug|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Dedicated Debug with inlines|x64.ActiveCfg = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Dedicated Debug with inlines|x64.Build.0 = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Dedicated Debug|x64.ActiveCfg = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Dedicated Debug|x64.Build.0 = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Dedicated Release|x64.ActiveCfg = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Dedicated Release|x64.Build.0 = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Prey Debug|x64.Build.0 = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Release|x64.ActiveCfg = Release|x64
{49BEC5C6-B964-417A-851E-808886B57420}.Release|x64.Build.0 = Release|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Debug with inlines and memory log|x64.ActiveCfg = Debug with inlines and memory log|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Debug with inlines|x64.ActiveCfg = Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Debug|x64.ActiveCfg = Debug|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Debug|x64.Build.0 = Debug|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Dedicated Debug with inlines|x64.ActiveCfg = Dedicated Debug with inlines|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Dedicated Debug|x64.ActiveCfg = Dedicated Debug|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Dedicated Release|x64.ActiveCfg = Dedicated Release|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Prey Debug|x64.Build.0 = Prey Debug|x64
{49BEC5C6-B964-417A-851E-808886B574F1}.Release|x64.ActiveCfg = Release|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Debug with inlines and memory log|x64.ActiveCfg = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Debug with inlines and memory log|x64.Build.0 = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Debug with inlines|x64.ActiveCfg = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Debug with inlines|x64.Build.0 = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Debug|x64.ActiveCfg = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Debug|x64.Build.0 = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Dedicated Debug with inlines|x64.ActiveCfg = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Dedicated Debug with inlines|x64.Build.0 = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Dedicated Debug|x64.ActiveCfg = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Dedicated Debug|x64.Build.0 = Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Dedicated Release|x64.ActiveCfg = Release|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Dedicated Release|x64.Build.0 = Release|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Prey Debug|x64.Build.0 = Prey Debug|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Release|x64.ActiveCfg = Release|x64
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D}.Release|x64.Build.0 = Release|x64
{6CD8E46D-E28E-493F-BB06-537A637A68C2}.Debug|x64.ActiveCfg = Debug|x64
{6CD8E46D-E28E-493F-BB06-537A637A68C2}.Dedicated Debug|x64.ActiveCfg = Dedicated Debug with Inlines|x64
{6CD8E46D-E28E-493F-BB06-537A637A68C2}.Dedicated Release|x64.ActiveCfg = Dedicated Release|x64
{6CD8E46D-E28E-493F-BB06-537A637A68C2}.Prey Debug|x64.ActiveCfg = Prey Debug|x64
{6CD8E46D-E28E-493F-BB06-537A637A68C2}.Prey Debug|x64.Build.0 = Prey Debug|x64
{6CD8E46D-E28E-493F-BB06-537A637A68C2}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -120,6 +106,7 @@ Global
{49BEC5C6-B964-417A-851E-808886B57420} = {003B01AB-152D-45C8-BF45-E5A035042D7F}
{49BEC5C6-B964-417A-851E-808886B574F1} = {1E2B3940-65F8-4D8F-9EEE-85E94EBBC6DF}
{58320C19-5139-47C5-AAFE-4CAD2C8ED14D} = {003B01AB-152D-45C8-BF45-E5A035042D7F}
{6CD8E46D-E28E-493F-BB06-537A637A68C2} = {F65E2305-0208-4A25-BEB0-038C92484211}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {822AE68E-37FD-4947-AC78-29CFA29E613F}
+28
View File
@@ -25,6 +25,10 @@
<Configuration>Dedicated Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|x64">
<Configuration>Prey Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
@@ -86,6 +90,12 @@
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@@ -138,6 +148,12 @@
<Import Project="_MayaImport.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="_Common.props" />
<Import Project="_MayaImport.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
@@ -148,8 +164,11 @@
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
@@ -171,6 +190,14 @@
<OutputFile>../$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>MayaImport/fbxsdk/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>../$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">
<ClCompile>
<AdditionalIncludeDirectories>MayaImport/fbxsdk/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -229,6 +256,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">Create</PrecompiledHeader>
+146
View File
@@ -0,0 +1,146 @@
// Copyright (C) 2004 Id Software, Inc.
//
#ifndef __COLLISIONMODELMANAGER_H__
#define __COLLISIONMODELMANAGER_H__
/*
===============================================================================
Trace model vs. polygonal model collision detection.
Short translations are the least expensive. Retrieving contact points is
about as cheap as a short translation. Position tests are more expensive
and rotations are most expensive.
There is no position test at the start of a translation or rotation. In other
words if a translation with start != end or a rotation with angle != 0 starts
in solid, this goes unnoticed and the collision result is undefined.
A translation with start == end or a rotation with angle == 0 performs
a position test and fills in the trace_t structure accordingly.
===============================================================================
*/
// contact type
typedef enum {
CONTACT_NONE, // no contact
CONTACT_EDGE, // trace model edge hits model edge
CONTACT_MODELVERTEX, // model vertex hits trace model polygon
CONTACT_TRMVERTEX // trace model vertex hits model polygon
} contactType_t;
// contact info
typedef struct {
contactType_t type; // contact type
idVec3 point; // point of contact
idVec3 normal; // contact plane normal
float dist; // contact plane distance
int contents; // contents at other side of surface
const idMaterial * material; // surface material
int modelFeature; // contact feature on model
int trmFeature; // contact feature on trace model
int entityNum; // entity the contact surface is a part of
int id; // id of clip model the contact surface is part of
} contactInfo_t;
// trace result
typedef struct trace_s {
float fraction; // fraction of movement completed, 1.0 = didn't hit anything
idVec3 endpos; // final position of trace model
idMat3 endAxis; // final axis of trace model
contactInfo_t c; // contact information, only valid if fraction < 1.0
} trace_t;
typedef int cmHandle_t;
#define CM_CLIP_EPSILON 0.25f // always stay this distance away from any model
#define CM_BOX_EPSILON 1.0f // should always be larger than clip epsilon
#define CM_MAX_TRACE_DIST 4096.0f // maximum distance a trace model may be traced, point traces are unlimited
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
#define PROC_CLIPMODEL_INDEX_START 1
#define PROC_CLIPMODEL_STRING_PRFX "inlined_proc_clip_"
#endif
//HUMANHEAD END
class idCollisionModelManager {
public:
virtual ~idCollisionModelManager( void ) {}
// Loads collision models from a map file.
virtual void LoadMap( const idMapFile *mapFile ) = 0;
// HUMANHEAD pdm: Support for level appending
virtual const char * ContentsName(const int contents) const = 0;
const char * StringFromContents( const int contents ) const;
#if DEATHWALK_AUTOLOAD
virtual void AppendMap( const idMapFile *mapFile ) = 0;
virtual bool WillUseAlreadyLoadedCollisionMap( const idMapFile *mapFile) = 0;
#endif
// HUMANHEAD END
// Frees all the collision models.
virtual void FreeMap( void ) = 0;
// Gets the clip handle for a model.
virtual cmHandle_t LoadModel( const char *modelName, const bool precache ) = 0;
// Sets up a trace model for collision with other trace models.
virtual cmHandle_t SetupTrmModel( const idTraceModel &trm, const idMaterial *material ) = 0;
// Creates a trace model from a collision model, returns true if succesfull.
virtual bool TrmFromModel( const char *modelName, idTraceModel &trm ) = 0;
// Gets the name of a model.
virtual const char * GetModelName( cmHandle_t model ) const = 0;
// Gets the bounds of a model.
virtual bool GetModelBounds( cmHandle_t model, idBounds &bounds ) const = 0;
// Gets all contents flags of brushes and polygons of a model ored together.
virtual bool GetModelContents( cmHandle_t model, int &contents ) const = 0;
// Gets a vertex of a model.
virtual bool GetModelVertex( cmHandle_t model, int vertexNum, idVec3 &vertex ) const = 0;
// Gets an edge of a model.
virtual bool GetModelEdge( cmHandle_t model, int edgeNum, idVec3 &start, idVec3 &end ) const = 0;
// Gets a polygon of a model.
virtual bool GetModelPolygon( cmHandle_t model, int polygonNum, idFixedWinding &winding ) const = 0;
// Translates a trace model and reports the first collision if any.
virtual void Translation( trace_t *results, const idVec3 &start, const idVec3 &end,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) = 0;
// Rotates a trace model and reports the first collision if any.
virtual void Rotation( trace_t *results, const idVec3 &start, const idRotation &rotation,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) = 0;
// Returns the contents touched by the trace model or 0 if the trace model is in free space.
virtual int Contents( const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) = 0;
// Stores all contact points of the trace model with the model, returns the number of contacts.
virtual int Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) = 0;
// Tests collision detection.
virtual void DebugOutput( const idVec3 &origin ) = 0;
// Draws a model.
virtual void DrawModel( cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis,
const idVec3 &viewOrigin, const float radius ) = 0;
// Prints model information, use -1 handle for accumulated model info.
virtual void ModelInfo( cmHandle_t model ) = 0;
// Lists all loaded models.
virtual void ListModels( void ) = 0;
// Writes a collision model file for the given map entity.
virtual bool WriteCollisionModelForMapEntity( const idMapEntity *mapEnt, const char *filename, const bool testTraceModel = true ) = 0;
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
virtual int GetNumInlinedProcClipModels(void) = 0;
#endif
//HUMANHEAD END
};
extern idCollisionModelManager * collisionModelManager;
#endif /* !__COLLISIONMODELMANAGER_H__ */
+48
View File
@@ -0,0 +1,48 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Retrieving contacts
===============================================================================
*/
/*
==================
idCollisionModelManagerLocal::Contacts
==================
*/
int idCollisionModelManagerLocal::Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis ) {
trace_t results;
idVec3 end;
// same as Translation but instead of storing the first collision we store all collisions as contacts
idCollisionModelManagerLocal::getContacts = true;
idCollisionModelManagerLocal::contacts = contacts;
idCollisionModelManagerLocal::maxContacts = maxContacts;
idCollisionModelManagerLocal::numContacts = 0;
end = start + dir.SubVec3(0) * depth;
idCollisionModelManagerLocal::Translation( &results, start, end, trm, trmAxis, contentMask, model, origin, modelAxis );
if ( dir.SubVec3(1).LengthSqr() != 0.0f ) {
// FIXME: rotational contacts
}
idCollisionModelManagerLocal::getContacts = false;
idCollisionModelManagerLocal::maxContacts = 0;
return idCollisionModelManagerLocal::numContacts;
}
+614
View File
@@ -0,0 +1,614 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Contents test
===============================================================================
*/
/*
================
idCollisionModelManagerLocal::TestTrmVertsInBrush
returns true if any of the trm vertices is inside the brush
================
*/
bool idCollisionModelManagerLocal::TestTrmVertsInBrush( cm_traceWork_t *tw, cm_brush_t *b ) {
int i, j, numVerts, bestPlane;
float d, bestd;
idVec3 *p;
if ( b->checkcount == idCollisionModelManagerLocal::checkCount ) {
return false;
}
b->checkcount = idCollisionModelManagerLocal::checkCount;
if ( !(b->contents & tw->contents) ) {
return false;
}
// if the brush bounds don't intersect the trace bounds
if ( !b->bounds.IntersectsBounds( tw->bounds ) ) {
return false;
}
if ( tw->pointTrace ) {
numVerts = 1;
}
else {
numVerts = tw->numVerts;
}
for ( j = 0; j < numVerts; j++ ) {
p = &tw->vertices[j].p;
// see if the point is inside the brush
bestPlane = 0;
bestd = -idMath::INFINITY;
for ( i = 0; i < b->numPlanes; i++ ) {
d = b->planes[i].Distance( *p );
if ( d >= 0.0f ) {
break;
}
if ( d > bestd ) {
bestd = d;
bestPlane = i;
}
}
if ( i >= b->numPlanes ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_TRMVERTEX;
tw->trace.c.normal = b->planes[bestPlane].Normal();
tw->trace.c.dist = b->planes[bestPlane].Dist();
tw->trace.c.contents = b->contents;
tw->trace.c.material = b->material;
tw->trace.c.point = *p;
tw->trace.c.modelFeature = 0;
tw->trace.c.trmFeature = j;
return true;
}
}
return false;
}
/*
================
CM_SetTrmEdgeSidedness
================
*/
#define CM_SetTrmEdgeSidedness( edge, bpl, epl, bitNum ) { \
if ( !(edge->sideSet & (1<<bitNum)) ) { \
float fl; \
fl = (bpl).PermutedInnerProduct( epl ); \
edge->side = (edge->side & ~(1<<bitNum)) | (FLOATSIGNBITSET(fl) << bitNum); \
edge->sideSet |= (1 << bitNum); \
} \
}
/*
================
CM_SetTrmPolygonSidedness
================
*/
#define CM_SetTrmPolygonSidedness( v, plane, bitNum ) { \
if ( !((v)->sideSet & (1<<bitNum)) ) { \
float fl; \
fl = plane.Distance( (v)->p ); \
/* cannot use float sign bit because it is undetermined when fl == 0.0f */ \
if ( fl < 0.0f ) { \
(v)->side |= (1 << bitNum); \
} \
else { \
(v)->side &= ~(1 << bitNum); \
} \
(v)->sideSet |= (1 << bitNum); \
} \
}
/*
================
idCollisionModelManagerLocal::TestTrmInPolygon
returns true if the trm intersects the polygon
================
*/
bool idCollisionModelManagerLocal::TestTrmInPolygon( cm_traceWork_t *tw, cm_polygon_t *p ) {
int i, j, k, edgeNum, flip, trmEdgeNum, bitNum, bestPlane;
int sides[MAX_TRACEMODEL_VERTS];
float d, bestd;
cm_trmEdge_t *trmEdge;
cm_edge_t *edge;
cm_vertex_t *v, *v1, *v2;
// if already checked this polygon
if ( p->checkcount == idCollisionModelManagerLocal::checkCount ) {
return false;
}
p->checkcount = idCollisionModelManagerLocal::checkCount;
// if this polygon does not have the right contents behind it
if ( !(p->contents & tw->contents) ) {
return false;
}
// if the polygon bounds don't intersect the trace bounds
if ( !p->bounds.IntersectsBounds( tw->bounds ) ) {
return false;
}
// bounds should cross polygon plane
switch( tw->bounds.PlaneSide( p->plane ) ) {
case PLANESIDE_CROSS:
break;
case PLANESIDE_FRONT:
if ( tw->model->isConvex ) {
tw->quickExit = true;
return true;
}
default:
return false;
}
// if the trace model is convex
if ( tw->isConvex ) {
// test if any polygon vertices are inside the trm
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = tw->model->edges + abs(edgeNum);
// if this edge is already tested
if ( edge->checkcount == idCollisionModelManagerLocal::checkCount ) {
continue;
}
for ( j = 0; j < 2; j++ ) {
v = &tw->model->vertices[edge->vertexNum[j]];
// if this vertex is already tested
if ( v->checkcount == idCollisionModelManagerLocal::checkCount ) {
continue;
}
bestPlane = 0;
bestd = -idMath::INFINITY;
for ( k = 0; k < tw->numPolys; k++ ) {
d = tw->polys[k].plane.Distance( v->p );
if ( d >= 0.0f ) {
break;
}
if ( d > bestd ) {
bestd = d;
bestPlane = k;
}
}
if ( k >= tw->numPolys ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_MODELVERTEX;
tw->trace.c.normal = -tw->polys[bestPlane].plane.Normal();
tw->trace.c.dist = -tw->polys[bestPlane].plane.Dist();
tw->trace.c.contents = p->contents;
tw->trace.c.material = p->material;
tw->trace.c.point = v->p;
tw->trace.c.modelFeature = edge->vertexNum[j];
tw->trace.c.trmFeature = 0;
return true;
}
}
}
}
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = tw->model->edges + abs(edgeNum);
// reset sidedness cache if this is the first time we encounter this edge
if ( edge->checkcount != idCollisionModelManagerLocal::checkCount ) {
edge->sideSet = 0;
}
// pluecker coordinate for edge
tw->polygonEdgePlueckerCache[i].FromLine( tw->model->vertices[edge->vertexNum[0]].p,
tw->model->vertices[edge->vertexNum[1]].p );
v = &tw->model->vertices[edge->vertexNum[INTSIGNBITSET(edgeNum)]];
// reset sidedness cache if this is the first time we encounter this vertex
if ( v->checkcount != idCollisionModelManagerLocal::checkCount ) {
v->sideSet = 0;
}
v->checkcount = idCollisionModelManagerLocal::checkCount;
}
// get side of polygon for each trm vertex
for ( i = 0; i < tw->numVerts; i++ ) {
d = p->plane.Distance( tw->vertices[i].p );
sides[i] = d < 0.0f ? -1 : 1;
}
// test if any trm edges go through the polygon
for ( i = 1; i <= tw->numEdges; i++ ) {
// if the trm edge does not cross the polygon plane
if ( sides[tw->edges[i].vertexNum[0]] == sides[tw->edges[i].vertexNum[1]] ) {
continue;
}
// check from which side to which side the trm edge goes
flip = INTSIGNBITSET( sides[tw->edges[i].vertexNum[0]] );
// test if trm edge goes through the polygon between the polygon edges
for ( j = 0; j < p->numEdges; j++ ) {
edgeNum = p->edges[j];
edge = tw->model->edges + abs(edgeNum);
#if 1
CM_SetTrmEdgeSidedness( edge, tw->edges[i].pl, tw->polygonEdgePlueckerCache[j], i );
if ( INTSIGNBITSET(edgeNum) ^ ((edge->side >> i) & 1) ^ flip ) {
break;
}
#else
d = tw->edges[i].pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[j] );
if ( flip ) {
d = -d;
}
if ( edgeNum > 0 ) {
if ( d <= 0.0f ) {
break;
}
}
else {
if ( d >= 0.0f ) {
break;
}
}
#endif
}
if ( j >= p->numEdges ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_EDGE;
tw->trace.c.normal = p->plane.Normal();
tw->trace.c.dist = p->plane.Dist();
tw->trace.c.contents = p->contents;
tw->trace.c.material = p->material;
tw->trace.c.point = tw->vertices[tw->edges[i].vertexNum[ !flip ]].p;
tw->trace.c.modelFeature = *reinterpret_cast<int *>(&p);
tw->trace.c.trmFeature = i;
return true;
}
}
// test if any polygon edges go through the trm polygons
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = tw->model->edges + abs(edgeNum);
if ( edge->checkcount == idCollisionModelManagerLocal::checkCount ) {
continue;
}
edge->checkcount = idCollisionModelManagerLocal::checkCount;
for ( j = 0; j < tw->numPolys; j++ ) {
#if 1
v1 = tw->model->vertices + edge->vertexNum[0];
CM_SetTrmPolygonSidedness( v1, tw->polys[j].plane, j );
v2 = tw->model->vertices + edge->vertexNum[1];
CM_SetTrmPolygonSidedness( v2, tw->polys[j].plane, j );
// if the polygon edge does not cross the trm polygon plane
if ( !(((v1->side ^ v2->side) >> j) & 1) ) {
continue;
}
flip = (v1->side >> j) & 1;
#else
float d1, d2;
v1 = tw->model->vertices + edge->vertexNum[0];
d1 = tw->polys[j].plane.Distance( v1->p );
v2 = tw->model->vertices + edge->vertexNum[1];
d2 = tw->polys[j].plane.Distance( v2->p );
// if the polygon edge does not cross the trm polygon plane
if ( (d1 >= 0.0f && d2 >= 0.0f) || (d1 <= 0.0f && d2 <= 0.0f) ) {
continue;
}
flip = false;
if ( d1 < 0.0f ) {
flip = true;
}
#endif
// test if polygon edge goes through the trm polygon between the trm polygon edges
for ( k = 0; k < tw->polys[j].numEdges; k++ ) {
trmEdgeNum = tw->polys[j].edges[k];
trmEdge = tw->edges + abs(trmEdgeNum);
#if 1
bitNum = abs(trmEdgeNum);
CM_SetTrmEdgeSidedness( edge, trmEdge->pl, tw->polygonEdgePlueckerCache[i], bitNum );
if ( INTSIGNBITSET(trmEdgeNum) ^ ((edge->side >> bitNum) & 1) ^ flip ) {
break;
}
#else
d = trmEdge->pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] );
if ( flip ) {
d = -d;
}
if ( trmEdgeNum > 0 ) {
if ( d <= 0.0f ) {
break;
}
}
else {
if ( d >= 0.0f ) {
break;
}
}
#endif
}
if ( k >= tw->polys[j].numEdges ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_EDGE;
tw->trace.c.normal = -tw->polys[j].plane.Normal();
tw->trace.c.dist = -tw->polys[j].plane.Dist();
tw->trace.c.contents = p->contents;
tw->trace.c.material = p->material;
tw->trace.c.point = tw->model->vertices[edge->vertexNum[ !flip ]].p;
tw->trace.c.modelFeature = edgeNum;
tw->trace.c.trmFeature = j;
return true;
}
}
}
return false;
}
/*
================
idCollisionModelManagerLocal::PointNode
================
*/
cm_node_t *idCollisionModelManagerLocal::PointNode( const idVec3 &p, cm_model_t *model ) {
cm_node_t *node;
node = model->node;
while ( node->planeType != -1 ) {
if (p[node->planeType] > node->planeDist) {
node = node->children[0];
}
else {
node = node->children[1];
}
assert( node != NULL );
}
return node;
}
/*
================
idCollisionModelManagerLocal::PointContents
================
*/
int idCollisionModelManagerLocal::PointContents( const idVec3 p, cmHandle_t model ) {
int i;
float d;
cm_node_t *node;
cm_brushRef_t *bref;
cm_brush_t *b;
idPlane *plane;
node = idCollisionModelManagerLocal::PointNode( p, idCollisionModelManagerLocal::models[model] );
for ( bref = node->brushes; bref; bref = bref->next ) {
b = bref->b;
// test if the point is within the brush bounds
for ( i = 0; i < 3; i++ ) {
if ( p[i] < b->bounds[0][i] ) {
break;
}
if ( p[i] > b->bounds[1][i] ) {
break;
}
}
if ( i < 3 ) {
continue;
}
// test if the point is inside the brush
plane = b->planes;
for ( i = 0; i < b->numPlanes; i++, plane++ ) {
d = plane->Distance( p );
if ( d >= 0 ) {
break;
}
}
if ( i >= b->numPlanes ) {
return b->contents;
}
}
return 0;
}
/*
==================
idCollisionModelManagerLocal::TransformedPointContents
==================
*/
int idCollisionModelManagerLocal::TransformedPointContents( const idVec3 &p, cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis ) {
idVec3 p_l;
// subtract origin offset
p_l = p - origin;
if ( modelAxis.IsRotated() ) {
p_l *= modelAxis;
}
return idCollisionModelManagerLocal::PointContents( p_l, model );
}
/*
==================
idCollisionModelManagerLocal::ContentsTrm
==================
*/
int idCollisionModelManagerLocal::ContentsTrm( trace_t *results, const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
int i;
bool model_rotated, trm_rotated;
idMat3 invModelAxis, tmpAxis;
idVec3 dir;
ALIGN16( cm_traceWork_t tw; )
// fast point case
if ( !trm || ( trm->bounds[1][0] - trm->bounds[0][0] <= 0.0f &&
trm->bounds[1][1] - trm->bounds[0][1] <= 0.0f &&
trm->bounds[1][2] - trm->bounds[0][2] <= 0.0f ) ) {
results->c.contents = idCollisionModelManagerLocal::TransformedPointContents( start, model, modelOrigin, modelAxis );
results->fraction = ( results->c.contents == 0 );
results->endpos = start;
results->endAxis = trmAxis;
return results->c.contents;
}
idCollisionModelManagerLocal::checkCount++;
tw.trace.fraction = 1.0f;
tw.trace.c.contents = 0;
tw.trace.c.type = CONTACT_NONE;
tw.contents = contentMask;
tw.isConvex = true;
tw.rotation = false;
tw.positionTest = true;
tw.pointTrace = false;
tw.quickExit = false;
tw.numContacts = 0;
tw.model = idCollisionModelManagerLocal::models[model];
tw.start = start - modelOrigin;
tw.end = tw.start;
model_rotated = modelAxis.IsRotated();
if ( model_rotated ) {
invModelAxis = modelAxis.Transpose();
}
// setup trm structure
idCollisionModelManagerLocal::SetupTrm( &tw, trm );
trm_rotated = trmAxis.IsRotated();
// calculate vertex positions
if ( trm_rotated ) {
for ( i = 0; i < tw.numVerts; i++ ) {
// rotate trm around the start position
tw.vertices[i].p *= trmAxis;
}
}
for ( i = 0; i < tw.numVerts; i++ ) {
// set trm at start position
tw.vertices[i].p += tw.start;
}
if ( model_rotated ) {
for ( i = 0; i < tw.numVerts; i++ ) {
// rotate trm around model instead of rotating the model
tw.vertices[i].p *= invModelAxis;
}
}
// add offset to start point
if ( trm_rotated ) {
dir = trm->offset * trmAxis;
tw.start += dir;
tw.end += dir;
} else {
tw.start += trm->offset;
tw.end += trm->offset;
}
if ( model_rotated ) {
// rotate trace instead of model
tw.start *= invModelAxis;
tw.end *= invModelAxis;
}
// setup trm vertices
tw.size.Clear();
for ( i = 0; i < tw.numVerts; i++ ) {
// get axial trm size after rotations
tw.size.AddPoint( tw.vertices[i].p - tw.start );
}
// setup trm edges
for ( i = 1; i <= tw.numEdges; i++ ) {
// edge start, end and pluecker coordinate
tw.edges[i].start = tw.vertices[tw.edges[i].vertexNum[0]].p;
tw.edges[i].end = tw.vertices[tw.edges[i].vertexNum[1]].p;
tw.edges[i].pl.FromLine( tw.edges[i].start, tw.edges[i].end );
}
// setup trm polygons
if ( trm_rotated & model_rotated ) {
tmpAxis = trmAxis * invModelAxis;
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane *= tmpAxis;
}
} else if ( trm_rotated ) {
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane *= trmAxis;
}
} else if ( model_rotated ) {
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane *= invModelAxis;
}
}
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane.FitThroughPoint( tw.edges[abs(tw.polys[i].edges[0])].start );
}
// bounds for full trace, a little bit larger for epsilons
for ( i = 0; i < 3; i++ ) {
if ( tw.start[i] < tw.end[i] ) {
tw.bounds[0][i] = tw.start[i] + tw.size[0][i] - CM_BOX_EPSILON;
tw.bounds[1][i] = tw.end[i] + tw.size[1][i] + CM_BOX_EPSILON;
} else {
tw.bounds[0][i] = tw.end[i] + tw.size[0][i] - CM_BOX_EPSILON;
tw.bounds[1][i] = tw.start[i] + tw.size[1][i] + CM_BOX_EPSILON;
}
if ( idMath::Fabs(tw.size[0][i]) > idMath::Fabs(tw.size[1][i]) ) {
tw.extents[i] = idMath::Fabs( tw.size[0][i] ) + CM_BOX_EPSILON;
} else {
tw.extents[i] = idMath::Fabs( tw.size[1][i] ) + CM_BOX_EPSILON;
}
}
// trace through the model
idCollisionModelManagerLocal::TraceThroughModel( &tw );
*results = tw.trace;
results->fraction = ( results->c.contents == 0 );
results->endpos = start;
results->endAxis = trmAxis;
return results->c.contents;
}
/*
==================
idCollisionModelManagerLocal::Contents
==================
*/
int idCollisionModelManagerLocal::Contents( const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
trace_t results;
if ( model < 0 || model > idCollisionModelManagerLocal::maxModels || model > MAX_SUBMODELS ) {
common->Printf("idCollisionModelManagerLocal::Contents: invalid model handle\n");
return 0;
}
if ( !idCollisionModelManagerLocal::models || !idCollisionModelManagerLocal::models[model] ) {
common->Printf("idCollisionModelManagerLocal::Contents: invalid model\n");
return 0;
}
return ContentsTrm( &results, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
}
+498
View File
@@ -0,0 +1,498 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Visualisation code
===============================================================================
*/
const char *cm_contentsNameByIndex[] = {
// HUMANHEAD: Redid these as they were out of sync
"none", //
"solid", // bit 0
"opaque", // 1
"water", // 2
"playerclip", // 3
"monsterclip", // 4
"moveableclip", // 5
"ikclip", // 6
"blood", // 7
"body", // 8
"projectile", // 9
"corpse", // 10
"rendermodel", // 11
"trigger", // 12
"aas_solid", // 13
"aas_obstacle", // 14
"flashlight_trigger", // 15
// HUMANHEAD pdm: added our contents
"forcefield", // 16
"spiritbridge", // 17
"areaportal", // 18
"nocsg", // 19
"block_radiusdamage", // 20
"shootable", // 21
"deathvolume", // 22
"vehicleclip", // 23
"owner_to_owner", // 24
"game_portal", // 25
"shootablebyarrow", // 26
"hunterclip", // 27
// END HUMANHEAD
NULL
};
int cm_contentsFlagByIndex[] = {
// HUMANHEAD: Redid these as they were out of sync
-1, // -1
CONTENTS_SOLID, // bit 0
CONTENTS_OPAQUE, // 1
CONTENTS_WATER, // 2
CONTENTS_PLAYERCLIP, // 3
CONTENTS_MONSTERCLIP, // 4
CONTENTS_MOVEABLECLIP, // 5
CONTENTS_IKCLIP, // 6
CONTENTS_BLOOD, // 7
CONTENTS_BODY, // 8
CONTENTS_PROJECTILE, // 9
CONTENTS_CORPSE, // 10
CONTENTS_RENDERMODEL, // 11
CONTENTS_TRIGGER, // 12
CONTENTS_AAS_SOLID, // 13
CONTENTS_AAS_OBSTACLE, // 14
CONTENTS_FLASHLIGHT_TRIGGER, // 15
// HUMANHEAD pdm: added our contents
CONTENTS_FORCEFIELD, // 16
CONTENTS_SPIRITBRIDGE, // 17
CONTENTS_AREAPORTAL, // 18
CONTENTS_NOCSG, // 19
CONTENTS_BLOCK_RADIUSDAMAGE, // 20
CONTENTS_SHOOTABLE, // 21
CONTENTS_DEATHVOLUME, // 22
CONTENTS_VEHICLECLIP, // 23
CONTENTS_OWNER_TO_OWNER, // 24
CONTENTS_GAME_PORTAL, // 25
CONTENTS_SHOOTABLEBYARROW, // 26
CONTENTS_HUNTERCLIP, // 27
// END HUMANHEAD
0
};
idCVar cm_drawMask( "cm_drawMask", "none", CVAR_GAME, "collision mask", cm_contentsNameByIndex, idCmdSystem::ArgCompletion_String<cm_contentsNameByIndex> );
idCVar cm_drawColor( "cm_drawColor", "1 0 0 .5", CVAR_GAME, "color used to draw the collision models" );
idCVar cm_drawFilled( "cm_drawFilled", "0", CVAR_GAME | CVAR_BOOL, "draw filled polygons" );
idCVar cm_drawInternal( "cm_drawInternal", "1", CVAR_GAME | CVAR_BOOL, "draw internal edges green" );
idCVar cm_drawNormals( "cm_drawNormals", "0", CVAR_GAME | CVAR_BOOL, "draw polygon and edge normals" );
idCVar cm_backFaceCull( "cm_backFaceCull", "0", CVAR_GAME | CVAR_BOOL, "cull back facing polygons" );
idCVar cm_debugCollision( "cm_debugCollision", "0", CVAR_GAME | CVAR_BOOL, "debug the collision detection" );
static idVec4 cm_color;
/*
================
idCollisionModelManagerLocal::ContentsFromString
================
*/
int idCollisionModelManagerLocal::ContentsFromString( const char *string ) const {
int i, contents = 0;
idLexer src( string, idStr::Length( string ), "ContentsFromString" );
idToken token;
while( src.ReadToken( &token ) ) {
if ( token == "," ) {
continue;
}
for ( i = 1; cm_contentsNameByIndex[i] != NULL; i++ ) {
if ( token.Icmp( cm_contentsNameByIndex[i] ) == 0 ) {
contents |= cm_contentsFlagByIndex[i];
break;
}
}
}
return contents;
}
/*
================
idCollisionModelManagerLocal::StringFromContents
================
*/
const char *idCollisionModelManagerLocal::StringFromContents( const int contents ) const {
int i, length = 0;
static char contentsString[MAX_STRING_CHARS];
contentsString[0] = '\0';
for ( i = 1; cm_contentsFlagByIndex[i] != 0; i++ ) {
if ( contents & cm_contentsFlagByIndex[i] ) {
if ( length != 0 ) {
length += idStr::snPrintf( contentsString + length, sizeof( contentsString ) - length, "," );
}
length += idStr::snPrintf( contentsString + length, sizeof( contentsString ) - length, cm_contentsNameByIndex[i] );
}
}
return contentsString;
}
/*
================
idCollisionModelManagerLocal::DrawEdge
================
*/
void idCollisionModelManagerLocal::DrawEdge( cm_model_t *model, int edgeNum, const idVec3 &origin, const idMat3 &axis ) {
int side;
cm_edge_t *edge;
idVec3 start, end, mid;
bool isRotated;
isRotated = axis.IsRotated();
edge = model->edges + abs(edgeNum);
side = edgeNum < 0;
start = model->vertices[edge->vertexNum[side]].p;
end = model->vertices[edge->vertexNum[!side]].p;
if ( isRotated ) {
start *= axis;
end *= axis;
}
start += origin;
end += origin;
if ( edge->internal ) {
if ( cm_drawInternal.GetBool() ) {
session->rw->DebugArrow( colorGreen, start, end, 1 );
}
} else {
if ( edge->numUsers > 2 ) {
session->rw->DebugArrow( colorBlue, start, end, 1 );
} else {
session->rw->DebugArrow( cm_color, start, end, 1 );
}
}
if ( cm_drawNormals.GetBool() ) {
mid = (start + end) * 0.5f;
if ( isRotated ) {
end = mid + 5 * (axis * edge->normal);
} else {
end = mid + 5 * edge->normal;
}
session->rw->DebugArrow( colorCyan, mid, end, 1 );
}
}
/*
================
idCollisionModelManagerLocal::DrawPolygon
================
*/
void idCollisionModelManagerLocal::DrawPolygon( cm_model_t *model, cm_polygon_t *p, const idVec3 &origin, const idMat3 &axis, const idVec3 &viewOrigin ) {
int i, edgeNum;
cm_edge_t *edge;
idVec3 center, end, dir;
if ( cm_backFaceCull.GetBool() ) {
edgeNum = p->edges[0];
edge = model->edges + abs(edgeNum);
dir = model->vertices[edge->vertexNum[0]].p - viewOrigin;
if ( dir * p->plane.Normal() > 0.0f ) {
return;
}
}
if ( cm_drawNormals.GetBool() ) {
center = vec3_origin;
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = model->edges + abs(edgeNum);
center += model->vertices[edge->vertexNum[edgeNum < 0]].p;
}
center *= (1.0f / p->numEdges);
if ( axis.IsRotated() ) {
center = center * axis + origin;
end = center + 5 * (axis * p->plane.Normal());
} else {
center += origin;
end = center + 5 * p->plane.Normal();
}
session->rw->DebugArrow( colorMagenta, center, end, 1 );
}
if ( cm_drawFilled.GetBool() ) {
idFixedWinding winding;
for ( i = p->numEdges - 1; i >= 0; i-- ) {
edgeNum = p->edges[i];
edge = model->edges + abs(edgeNum);
winding += origin + model->vertices[edge->vertexNum[INTSIGNBITSET(edgeNum)]].p * axis;
}
session->rw->DebugPolygon( cm_color, winding );
} else {
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = model->edges + abs(edgeNum);
if ( edge->checkcount == checkCount ) {
continue;
}
edge->checkcount = checkCount;
DrawEdge( model, edgeNum, origin, axis );
}
}
}
/*
================
idCollisionModelManagerLocal::DrawNodePolygons
================
*/
void idCollisionModelManagerLocal::DrawNodePolygons( cm_model_t *model, cm_node_t *node,
const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin, const float radius ) {
int i;
cm_polygon_t *p;
cm_polygonRef_t *pref;
while (1) {
for ( pref = node->polygons; pref; pref = pref->next ) {
p = pref->p;
if ( radius ) {
// polygon bounds should overlap with trace bounds
for ( i = 0; i < 3; i++ ) {
if ( p->bounds[0][i] > viewOrigin[i] + radius ) {
break;
}
if ( p->bounds[1][i] < viewOrigin[i] - radius ) {
break;
}
}
if ( i < 3 ) {
continue;
}
}
if ( p->checkcount == checkCount ) {
continue;
}
if ( !( p->contents & cm_contentsFlagByIndex[cm_drawMask.GetInteger()] ) ) {
continue;
}
DrawPolygon( model, p, origin, axis, viewOrigin );
p->checkcount = checkCount;
}
if ( node->planeType == -1 ) {
break;
}
if ( radius && viewOrigin[node->planeType] > node->planeDist + radius ) {
node = node->children[0];
} else if ( radius && viewOrigin[node->planeType] < node->planeDist - radius ) {
node = node->children[1];
} else {
DrawNodePolygons( model, node->children[1], origin, axis, viewOrigin, radius );
node = node->children[0];
}
}
}
/*
================
idCollisionModelManagerLocal::DrawModel
================
*/
void idCollisionModelManagerLocal::DrawModel( cmHandle_t handle, const idVec3 &modelOrigin, const idMat3 &modelAxis,
const idVec3 &viewOrigin, const float radius ) {
cm_model_t *model;
idVec3 viewPos;
if ( handle < 0 && handle >= numModels ) {
return;
}
if ( cm_drawColor.IsModified() ) {
sscanf( cm_drawColor.GetString(), "%f %f %f %f", &cm_color.x, &cm_color.y, &cm_color.z, &cm_color.w );
cm_drawColor.ClearModified();
}
model = models[ handle ];
viewPos = (viewOrigin - modelOrigin) * modelAxis.Transpose();
checkCount++;
DrawNodePolygons( model, model->node, modelOrigin, modelAxis, viewPos, radius );
}
/*
===============================================================================
Speed test code
===============================================================================
*/
static idCVar cm_testCollision( "cm_testCollision", "0", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testRotation( "cm_testRotation", "1", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testModel( "cm_testModel", "0", CVAR_GAME | CVAR_INTEGER, "" );
static idCVar cm_testTimes( "cm_testTimes", "1000", CVAR_GAME | CVAR_INTEGER, "" );
static idCVar cm_testRandomMany( "cm_testRandomMany", "0", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testOrigin( "cm_testOrigin", "0 0 0", CVAR_GAME, "" );
static idCVar cm_testReset( "cm_testReset", "0", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testBox( "cm_testBox", "-16 -16 0 16 16 64", CVAR_GAME, "" );
static idCVar cm_testBoxRotation( "cm_testBoxRotation", "0 0 0", CVAR_GAME, "" );
static idCVar cm_testWalk( "cm_testWalk", "1", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testLength( "cm_testLength", "1024", CVAR_GAME | CVAR_FLOAT, "" );
static idCVar cm_testRadius( "cm_testRadius", "64", CVAR_GAME | CVAR_FLOAT, "" );
static idCVar cm_testAngle( "cm_testAngle", "60", CVAR_GAME | CVAR_FLOAT, "" );
static int total_translation;
static int min_translation = 999999;
static int max_translation = -999999;
static int num_translation = 0;
static int total_rotation;
static int min_rotation = 999999;
static int max_rotation = -999999;
static int num_rotation = 0;
static idVec3 start;
static idVec3 *testend;
#include "../../sys/sys_public.h"
void idCollisionModelManagerLocal::DebugOutput( const idVec3 &origin ) {
int i, k, t;
char buf[128];
idVec3 end;
idAngles boxAngles;
idMat3 modelAxis, boxAxis;
idBounds bounds;
trace_t trace;
if ( !cm_testCollision.GetBool() ) {
return;
}
testend = (idVec3 *) Mem_Alloc( cm_testTimes.GetInteger() * sizeof(idVec3) );
if ( cm_testReset.GetBool() || ( cm_testWalk.GetBool() && !start.Compare( start ) ) ) {
total_translation = total_rotation = 0;
min_translation = min_rotation = 999999;
max_translation = max_rotation = -999999;
num_translation = num_rotation = 0;
cm_testReset.SetBool( false );
}
if ( cm_testWalk.GetBool() ) {
start = origin;
cm_testOrigin.SetString( va( "%1.2f %1.2f %1.2f", start[0], start[1], start[2] ) );
} else {
sscanf( cm_testOrigin.GetString(), "%f %f %f", &start[0], &start[1], &start[2] );
}
sscanf( cm_testBox.GetString(), "%f %f %f %f %f %f", &bounds[0][0], &bounds[0][1], &bounds[0][2],
&bounds[1][0], &bounds[1][1], &bounds[1][2] );
sscanf( cm_testBoxRotation.GetString(), "%f %f %f", &boxAngles[0], &boxAngles[1], &boxAngles[2] );
boxAxis = boxAngles.ToMat3();
modelAxis.Identity();
idTraceModel itm( bounds );
idRandom random( 0 );
idTimer timer;
if ( cm_testRandomMany.GetBool() ) {
// if many traces in one random direction
for ( i = 0; i < 3; i++ ) {
testend[0][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat();
}
for ( k = 1; k < cm_testTimes.GetInteger(); k++ ) {
testend[k] = testend[0];
}
} else {
// many traces each in a different random direction
for ( k = 0; k < cm_testTimes.GetInteger(); k++ ) {
for ( i = 0; i < 3; i++ ) {
testend[k][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat();
}
}
}
// translational collision detection
timer.Clear();
timer.Start();
for ( i = 0; i < cm_testTimes.GetInteger(); i++ ) {
Translation( &trace, start, testend[i], &itm, boxAxis, CONTENTS_SOLID|CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis );
}
timer.Stop();
t = timer.Milliseconds();
if ( t < min_translation ) min_translation = t;
if ( t > max_translation ) max_translation = t;
num_translation++;
total_translation += t;
if ( cm_testTimes.GetInteger() > 9999 ) {
sprintf( buf, "%3dK", (int ) ( cm_testTimes.GetInteger() / 1000 ) );
} else {
sprintf( buf, "%4d", cm_testTimes.GetInteger() );
}
common->Printf("%s translations: %4d milliseconds, (min = %d, max = %d, av = %1.1f)\n", buf, t, min_translation, max_translation, (float) total_translation / num_translation );
if ( cm_testRandomMany.GetBool() ) {
// if many traces in one random direction
for ( i = 0; i < 3; i++ ) {
testend[0][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat();
}
for ( k = 1; k < cm_testTimes.GetInteger(); k++ ) {
testend[k] = testend[0];
}
} else {
// many traces each in a different random direction
for ( k = 0; k < cm_testTimes.GetInteger(); k++ ) {
for ( i = 0; i < 3; i++ ) {
testend[k][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat();
}
}
}
if ( cm_testRotation.GetBool() ) {
// rotational collision detection
idVec3 vec( random.CRandomFloat(), random.CRandomFloat(), random.RandomFloat() );
vec.Normalize();
idRotation rotation( vec3_origin, vec, cm_testAngle.GetFloat() );
timer.Clear();
timer.Start();
for ( i = 0; i < cm_testTimes.GetInteger(); i++ ) {
rotation.SetOrigin( testend[i] );
Rotation( &trace, start, rotation, &itm, boxAxis, CONTENTS_SOLID|CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis );
}
timer.Stop();
t = timer.Milliseconds();
if ( t < min_rotation ) min_rotation = t;
if ( t > max_rotation ) max_rotation = t;
num_rotation++;
total_rotation += t;
if ( cm_testTimes.GetInteger() > 9999 ) {
sprintf( buf, "%3dK", (int ) ( cm_testTimes.GetInteger() / 1000 ) );
} else {
sprintf( buf, "%4d", cm_testTimes.GetInteger() );
}
common->Printf("%s rotation: %4d milliseconds, (min = %d, max = %d, av = %1.1f)\n", buf, t, min_rotation, max_rotation, (float) total_rotation / num_rotation );
}
Mem_Free( testend );
testend = NULL;
}
+598
View File
@@ -0,0 +1,598 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
#define CM_FILE_EXT "cm"
#define CM_FILEID "CM"
#define CM_FILEVERSION "1.00"
/*
===============================================================================
Writing of collision model file
===============================================================================
*/
void CM_GetNodeBounds( idBounds *bounds, cm_node_t *node );
int CM_GetNodeContents( cm_node_t *node );
/*
================
idCollisionModelManagerLocal::WriteNodes
================
*/
void idCollisionModelManagerLocal::WriteNodes( idFile *fp, cm_node_t *node ) {
fp->WriteFloatString( "\t( %d %f )\n", node->planeType, node->planeDist );
if ( node->planeType != -1 ) {
WriteNodes( fp, node->children[0] );
WriteNodes( fp, node->children[1] );
}
}
/*
================
idCollisionModelManagerLocal::CountPolygonMemory
================
*/
int idCollisionModelManagerLocal::CountPolygonMemory( cm_node_t *node ) const {
cm_polygonRef_t *pref;
cm_polygon_t *p;
int memory;
memory = 0;
for ( pref = node->polygons; pref; pref = pref->next ) {
p = pref->p;
if ( p->checkcount == checkCount ) {
continue;
}
p->checkcount = checkCount;
memory += sizeof( cm_polygon_t ) + ( p->numEdges - 1 ) * sizeof( p->edges[0] );
}
if ( node->planeType != -1 ) {
memory += CountPolygonMemory( node->children[0] );
memory += CountPolygonMemory( node->children[1] );
}
return memory;
}
/*
================
idCollisionModelManagerLocal::WritePolygons
================
*/
void idCollisionModelManagerLocal::WritePolygons( idFile *fp, cm_node_t *node ) {
cm_polygonRef_t *pref;
cm_polygon_t *p;
int i;
for ( pref = node->polygons; pref; pref = pref->next ) {
p = pref->p;
if ( p->checkcount == checkCount ) {
continue;
}
p->checkcount = checkCount;
fp->WriteFloatString( "\t%d (", p->numEdges );
for ( i = 0; i < p->numEdges; i++ ) {
fp->WriteFloatString( " %d", p->edges[i] );
}
fp->WriteFloatString( " ) ( %f %f %f ) %f", p->plane.Normal()[0], p->plane.Normal()[1], p->plane.Normal()[2], p->plane.Dist() );
fp->WriteFloatString( " ( %f %f %f )", p->bounds[0][0], p->bounds[0][1], p->bounds[0][2] );
fp->WriteFloatString( " ( %f %f %f )", p->bounds[1][0], p->bounds[1][1], p->bounds[1][2] );
fp->WriteFloatString( " \"%s\"\n", p->material->GetName() );
}
if ( node->planeType != -1 ) {
WritePolygons( fp, node->children[0] );
WritePolygons( fp, node->children[1] );
}
}
/*
================
idCollisionModelManagerLocal::CountBrushMemory
================
*/
int idCollisionModelManagerLocal::CountBrushMemory( cm_node_t *node ) const {
cm_brushRef_t *bref;
cm_brush_t *b;
int memory;
memory = 0;
for ( bref = node->brushes; bref; bref = bref->next ) {
b = bref->b;
if ( b->checkcount == checkCount ) {
continue;
}
b->checkcount = checkCount;
memory += sizeof( cm_brush_t ) + ( b->numPlanes - 1 ) * sizeof( b->planes[0] );
}
if ( node->planeType != -1 ) {
memory += CountBrushMemory( node->children[0] );
memory += CountBrushMemory( node->children[1] );
}
return memory;
}
/*
================
idCollisionModelManagerLocal::WriteBrushes
================
*/
void idCollisionModelManagerLocal::WriteBrushes( idFile *fp, cm_node_t *node ) {
cm_brushRef_t *bref;
cm_brush_t *b;
int i;
for ( bref = node->brushes; bref; bref = bref->next ) {
b = bref->b;
if ( b->checkcount == checkCount ) {
continue;
}
b->checkcount = checkCount;
fp->WriteFloatString( "\t%d {\n", b->numPlanes );
for ( i = 0; i < b->numPlanes; i++ ) {
fp->WriteFloatString( "\t\t( %f %f %f ) %f\n", b->planes[i].Normal()[0], b->planes[i].Normal()[1], b->planes[i].Normal()[2], b->planes[i].Dist() );
}
fp->WriteFloatString( "\t} ( %f %f %f )", b->bounds[0][0], b->bounds[0][1], b->bounds[0][2] );
fp->WriteFloatString( " ( %f %f %f ) \"%s\"\n", b->bounds[1][0], b->bounds[1][1], b->bounds[1][2], StringFromContents( b->contents ) );
}
if ( node->planeType != -1 ) {
WriteBrushes( fp, node->children[0] );
WriteBrushes( fp, node->children[1] );
}
}
/*
================
idCollisionModelManagerLocal::WriteCollisionModel
================
*/
void idCollisionModelManagerLocal::WriteCollisionModel( idFile *fp, cm_model_t *model ) {
int i, polygonMemory, brushMemory;
fp->WriteFloatString( "collisionModel \"%s\" {\n", model->name.c_str() );
// vertices
fp->WriteFloatString( "\tvertices { /* numVertices = */ %d\n", model->numVertices );
for ( i = 0; i < model->numVertices; i++ ) {
fp->WriteFloatString( "\t/* %d */ ( %f %f %f )\n", i, model->vertices[i].p[0], model->vertices[i].p[1], model->vertices[i].p[2] );
}
fp->WriteFloatString( "\t}\n" );
// edges
fp->WriteFloatString( "\tedges { /* numEdges = */ %d\n", model->numEdges );
for ( i = 0; i < model->numEdges; i++ ) {
fp->WriteFloatString( "\t/* %d */ ( %d %d ) %d %d\n", i, model->edges[i].vertexNum[0], model->edges[i].vertexNum[1], model->edges[i].internal, model->edges[i].numUsers );
}
fp->WriteFloatString( "\t}\n" );
// nodes
fp->WriteFloatString( "\tnodes {\n" );
WriteNodes( fp, model->node );
fp->WriteFloatString( "\t}\n" );
// polygons
checkCount++;
polygonMemory = CountPolygonMemory( model->node );
fp->WriteFloatString( "\tpolygons /* polygonMemory = */ %d {\n", polygonMemory );
checkCount++;
WritePolygons( fp, model->node );
fp->WriteFloatString( "\t}\n" );
// brushes
checkCount++;
brushMemory = CountBrushMemory( model->node );
fp->WriteFloatString( "\tbrushes /* brushMemory = */ %d {\n", brushMemory );
checkCount++;
WriteBrushes( fp, model->node );
fp->WriteFloatString( "\t}\n" );
// closing brace
fp->WriteFloatString( "}\n" );
}
/*
================
idCollisionModelManagerLocal::WriteCollisionModelsToFile
================
*/
void idCollisionModelManagerLocal::WriteCollisionModelsToFile( const char *filename, int firstModel, int lastModel, unsigned int mapFileCRC ) {
int i;
idFile *fp;
idStr name;
name = filename;
name.SetFileExtension( CM_FILE_EXT );
common->Printf( "writing %s\n", name.c_str() );
// _D3XP was saving to fs_cdpath
fp = fileSystem->OpenFileWrite( name, "fs_devpath" );
if ( !fp ) {
common->Warning( "idCollisionModelManagerLocal::WriteCollisionModelsToFile: Error opening file %s\n", name.c_str() );
return;
}
// write file id and version
fp->WriteFloatString( "%s \"%s\"\n\n", CM_FILEID, CM_FILEVERSION );
// write the map file crc
fp->WriteFloatString( "%u\n\n", mapFileCRC );
// write the collision models
for ( i = firstModel; i < lastModel; i++ ) {
WriteCollisionModel( fp, models[ i ] );
}
fileSystem->CloseFile( fp );
}
/*
================
idCollisionModelManagerLocal::WriteCollisionModelForMapEntity
================
*/
bool idCollisionModelManagerLocal::WriteCollisionModelForMapEntity( const idMapEntity *mapEnt, const char *filename, const bool testTraceModel ) {
idFile *fp;
idStr name;
cm_model_t *model;
SetupHash();
model = CollisionModelForMapEntity( mapEnt );
model->name = filename;
name = filename;
name.SetFileExtension( CM_FILE_EXT );
common->Printf( "writing %s\n", name.c_str() );
fp = fileSystem->OpenFileWrite( name, "fs_devpath" );
if ( !fp ) {
common->Printf( "idCollisionModelManagerLocal::WriteCollisionModelForMapEntity: Error opening file %s\n", name.c_str() );
FreeModel( model );
return false;
}
// write file id and version
fp->WriteFloatString( "%s \"%s\"\n\n", CM_FILEID, CM_FILEVERSION );
// write the map file crc
fp->WriteFloatString( "%u\n\n", 0 );
// write the collision model
WriteCollisionModel( fp, model );
fileSystem->CloseFile( fp );
if ( testTraceModel ) {
idTraceModel trm;
TrmFromModel( model, trm );
}
FreeModel( model );
return true;
}
/*
===============================================================================
Loading of collision model file
===============================================================================
*/
/*
================
idCollisionModelManagerLocal::ParseVertices
================
*/
void idCollisionModelManagerLocal::ParseVertices( idLexer *src, cm_model_t *model ) {
int i;
src->ExpectTokenString( "{" );
model->numVertices = src->ParseInt();
model->maxVertices = model->numVertices;
model->vertices = (cm_vertex_t *) Mem_Alloc( model->maxVertices * sizeof( cm_vertex_t ) );
for ( i = 0; i < model->numVertices; i++ ) {
src->Parse1DMatrix( 3, model->vertices[i].p.ToFloatPtr() );
model->vertices[i].side = 0;
model->vertices[i].sideSet = 0;
model->vertices[i].checkcount = 0;
}
src->ExpectTokenString( "}" );
}
/*
================
idCollisionModelManagerLocal::ParseEdges
================
*/
void idCollisionModelManagerLocal::ParseEdges( idLexer *src, cm_model_t *model ) {
int i;
src->ExpectTokenString( "{" );
model->numEdges = src->ParseInt();
model->maxEdges = model->numEdges;
model->edges = (cm_edge_t *) Mem_Alloc( model->maxEdges * sizeof( cm_edge_t ) );
for ( i = 0; i < model->numEdges; i++ ) {
src->ExpectTokenString( "(" );
model->edges[i].vertexNum[0] = src->ParseInt();
model->edges[i].vertexNum[1] = src->ParseInt();
src->ExpectTokenString( ")" );
model->edges[i].side = 0;
model->edges[i].sideSet = 0;
model->edges[i].internal = src->ParseInt();
model->edges[i].numUsers = src->ParseInt();
model->edges[i].normal = vec3_origin;
model->edges[i].checkcount = 0;
model->numInternalEdges += model->edges[i].internal;
}
src->ExpectTokenString( "}" );
}
/*
================
idCollisionModelManagerLocal::ParseNodes
================
*/
cm_node_t *idCollisionModelManagerLocal::ParseNodes( idLexer *src, cm_model_t *model, cm_node_t *parent ) {
cm_node_t *node;
model->numNodes++;
node = AllocNode( model, model->numNodes < NODE_BLOCK_SIZE_SMALL ? NODE_BLOCK_SIZE_SMALL : NODE_BLOCK_SIZE_LARGE );
node->brushes = NULL;
node->polygons = NULL;
node->parent = parent;
src->ExpectTokenString( "(" );
node->planeType = src->ParseInt();
node->planeDist = src->ParseFloat();
src->ExpectTokenString( ")" );
if ( node->planeType != -1 ) {
node->children[0] = ParseNodes( src, model, node );
node->children[1] = ParseNodes( src, model, node );
}
return node;
}
/*
================
idCollisionModelManagerLocal::ParsePolygons
================
*/
void idCollisionModelManagerLocal::ParsePolygons( idLexer *src, cm_model_t *model ) {
cm_polygon_t *p;
int i, numEdges;
idVec3 normal;
idToken token;
if ( src->CheckTokenType( TT_NUMBER, 0, &token ) ) {
model->polygonBlock = (cm_polygonBlock_t *) Mem_Alloc( sizeof( cm_polygonBlock_t ) + token.GetIntValue() );
model->polygonBlock->bytesRemaining = token.GetIntValue();
model->polygonBlock->next = ( (byte *) model->polygonBlock ) + sizeof( cm_polygonBlock_t );
}
src->ExpectTokenString( "{" );
while ( !src->CheckTokenString( "}" ) ) {
// parse polygon
numEdges = src->ParseInt();
p = AllocPolygon( model, numEdges );
p->numEdges = numEdges;
src->ExpectTokenString( "(" );
for ( i = 0; i < p->numEdges; i++ ) {
p->edges[i] = src->ParseInt();
}
src->ExpectTokenString( ")" );
src->Parse1DMatrix( 3, normal.ToFloatPtr() );
p->plane.SetNormal( normal );
p->plane.SetDist( src->ParseFloat() );
src->Parse1DMatrix( 3, p->bounds[0].ToFloatPtr() );
src->Parse1DMatrix( 3, p->bounds[1].ToFloatPtr() );
src->ExpectTokenType( TT_STRING, 0, &token );
// get material
p->material = declManager->FindMaterial( token );
p->contents = p->material->GetContentFlags();
p->checkcount = 0;
// filter polygon into tree
R_FilterPolygonIntoTree( model, model->node, NULL, p );
}
}
/*
================
idCollisionModelManagerLocal::ParseBrushes
================
*/
void idCollisionModelManagerLocal::ParseBrushes( idLexer *src, cm_model_t *model ) {
cm_brush_t *b;
int i, numPlanes;
idVec3 normal;
idToken token;
if ( src->CheckTokenType( TT_NUMBER, 0, &token ) ) {
model->brushBlock = (cm_brushBlock_t *) Mem_Alloc( sizeof( cm_brushBlock_t ) + token.GetIntValue() );
model->brushBlock->bytesRemaining = token.GetIntValue();
model->brushBlock->next = ( (byte *) model->brushBlock ) + sizeof( cm_brushBlock_t );
}
src->ExpectTokenString( "{" );
while ( !src->CheckTokenString( "}" ) ) {
// parse brush
numPlanes = src->ParseInt();
b = AllocBrush( model, numPlanes );
b->numPlanes = numPlanes;
src->ExpectTokenString( "{" );
for ( i = 0; i < b->numPlanes; i++ ) {
src->Parse1DMatrix( 3, normal.ToFloatPtr() );
b->planes[i].SetNormal( normal );
b->planes[i].SetDist( src->ParseFloat() );
}
src->ExpectTokenString( "}" );
src->Parse1DMatrix( 3, b->bounds[0].ToFloatPtr() );
src->Parse1DMatrix( 3, b->bounds[1].ToFloatPtr() );
src->ReadToken( &token );
if ( token.type == TT_NUMBER ) {
b->contents = token.GetIntValue(); // old .cm files use a single integer
} else {
b->contents = ContentsFromString( token );
}
b->checkcount = 0;
b->primitiveNum = 0;
// filter brush into tree
R_FilterBrushIntoTree( model, model->node, NULL, b );
}
}
/*
================
idCollisionModelManagerLocal::ParseCollisionModel
================
*/
bool idCollisionModelManagerLocal::ParseCollisionModel( idLexer *src ) {
cm_model_t *model;
idToken token;
if ( numModels >= MAX_SUBMODELS ) {
common->Error( "LoadModel: no free slots" );
return false;
}
model = AllocModel();
models[numModels ] = model;
numModels++;
// parse the file
src->ExpectTokenType( TT_STRING, 0, &token );
model->name = token;
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
if (anyInlinedProcClipMats) {
if (token.Cmpn(PROC_CLIPMODEL_STRING_PRFX, strlen(PROC_CLIPMODEL_STRING_PRFX)) == 0) {
numInlinedProcClipModels++;
}
}
#endif
//HUMANHEAD END
src->ExpectTokenString( "{" );
while ( !src->CheckTokenString( "}" ) ) {
src->ReadToken( &token );
if ( token == "vertices" ) {
ParseVertices( src, model );
continue;
}
if ( token == "edges" ) {
ParseEdges( src, model );
continue;
}
if ( token == "nodes" ) {
src->ExpectTokenString( "{" );
model->node = ParseNodes( src, model, NULL );
src->ExpectTokenString( "}" );
continue;
}
if ( token == "polygons" ) {
ParsePolygons( src, model );
continue;
}
if ( token == "brushes" ) {
ParseBrushes( src, model );
continue;
}
src->Error( "ParseCollisionModel: bad token \"%s\"", token.c_str() );
}
// calculate edge normals
checkCount++;
CalculateEdgeNormals( model, model->node );
// get model bounds from brush and polygon bounds
CM_GetNodeBounds( &model->bounds, model->node );
// get model contents
model->contents = CM_GetNodeContents( model->node );
// total memory used by this model
model->usedMemory = model->numVertices * sizeof(cm_vertex_t) +
model->numEdges * sizeof(cm_edge_t) +
model->polygonMemory +
model->brushMemory +
model->numNodes * sizeof(cm_node_t) +
model->numPolygonRefs * sizeof(cm_polygonRef_t) +
model->numBrushRefs * sizeof(cm_brushRef_t);
return true;
}
/*
================
idCollisionModelManagerLocal::LoadCollisionModelFile
================
*/
bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char *name, unsigned int mapFileCRC ) {
idStr fileName;
idToken token;
idLexer *src;
unsigned int crc;
// load it
fileName = name;
fileName.SetFileExtension( CM_FILE_EXT );
src = new idLexer( fileName );
src->SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
if ( !src->IsLoaded() ) {
delete src;
return false;
}
if ( !src->ExpectTokenString( CM_FILEID ) ) {
common->Warning( "%s is not an CM file.", fileName.c_str() );
delete src;
return false;
}
if ( !src->ReadToken( &token ) || token != CM_FILEVERSION ) {
common->Warning( "%s has version %s instead of %s", fileName.c_str(), token.c_str(), CM_FILEVERSION );
delete src;
return false;
}
if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
common->Warning( "%s has no map file CRC", fileName.c_str() );
delete src;
return false;
}
crc = token.GetUnsignedLongValue();
if ( mapFileCRC && crc != mapFileCRC ) {
common->Printf( "%s is out of date\n", fileName.c_str() );
delete src;
return false;
}
// parse the file
while ( 1 ) {
if ( !src->ReadToken( &token ) ) {
break;
}
if ( token == "collisionModel" ) {
if ( !ParseCollisionModel( src ) ) {
delete src;
return false;
}
continue;
}
src->Error( "idCollisionModelManagerLocal::LoadCollisionModelFile: bad token \"%s\"", token.c_str() );
}
delete src;
return true;
}
File diff suppressed because it is too large Load Diff
+527
View File
@@ -0,0 +1,527 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "CollisionModel.h"
#define MIN_NODE_SIZE 64.0f
#define MAX_NODE_POLYGONS 128
#define CM_MAX_POLYGON_EDGES 64
#define CIRCLE_APPROXIMATION_LENGTH 64.0f
#define MAX_SUBMODELS 2048
#define TRACE_MODEL_HANDLE MAX_SUBMODELS
#define VERTEX_HASH_BOXSIZE (1<<6) // must be power of 2
#define VERTEX_HASH_SIZE (VERTEX_HASH_BOXSIZE*VERTEX_HASH_BOXSIZE)
#define EDGE_HASH_SIZE (1<<14)
#define NODE_BLOCK_SIZE_SMALL 8
#define NODE_BLOCK_SIZE_LARGE 256
#define REFERENCE_BLOCK_SIZE_SMALL 8
#define REFERENCE_BLOCK_SIZE_LARGE 256
#define MAX_WINDING_LIST 128 // quite a few are generated at times
#define INTEGRAL_EPSILON 0.01f
#define VERTEX_EPSILON 0.1f
#define CHOP_EPSILON 0.1f
typedef struct cm_windingList_s {
int numWindings; // number of windings
idFixedWinding w[MAX_WINDING_LIST]; // windings
idVec3 normal; // normal for all windings
idBounds bounds; // bounds of all windings in list
idVec3 origin; // origin for radius
float radius; // radius relative to origin for all windings
int contents; // winding surface contents
int primitiveNum; // number of primitive the windings came from
} cm_windingList_t;
/*
===============================================================================
Collision model
===============================================================================
*/
typedef struct cm_vertex_s {
idVec3 p; // vertex point
int checkcount; // for multi-check avoidance
unsigned long side; // each bit tells at which side this vertex passes one of the trace model edges
unsigned long sideSet; // each bit tells if sidedness for the trace model edge has been calculated yet
} cm_vertex_t;
typedef struct cm_edge_s {
int checkcount; // for multi-check avoidance
unsigned short internal; // a trace model can never collide with internal edges
unsigned short numUsers; // number of polygons using this edge
unsigned long side; // each bit tells at which side of this edge one of the trace model vertices passes
unsigned long sideSet; // each bit tells if sidedness for the trace model vertex has been calculated yet
int vertexNum[2]; // start and end point of edge
idVec3 normal; // edge normal
} cm_edge_t;
typedef struct cm_polygonBlock_s {
int bytesRemaining;
byte * next;
} cm_polygonBlock_t;
typedef struct cm_polygon_s {
idBounds bounds; // polygon bounds
int checkcount; // for multi-check avoidance
int contents; // contents behind polygon
const idMaterial * material; // material
idPlane plane; // polygon plane
int numEdges; // number of edges
int edges[1]; // variable sized, indexes into cm_edge_t list
} cm_polygon_t;
typedef struct cm_polygonRef_s {
cm_polygon_t * p; // pointer to polygon
struct cm_polygonRef_s *next; // next polygon in chain
} cm_polygonRef_t;
typedef struct cm_polygonRefBlock_s {
cm_polygonRef_t * nextRef; // next polygon reference in block
struct cm_polygonRefBlock_s *next; // next block with polygon references
} cm_polygonRefBlock_t;
typedef struct cm_brushBlock_s {
int bytesRemaining;
byte * next;
} cm_brushBlock_t;
typedef struct cm_brush_s {
int checkcount; // for multi-check avoidance
idBounds bounds; // brush bounds
int contents; // contents of brush
const idMaterial * material; // material
int primitiveNum; // number of brush primitive
int numPlanes; // number of bounding planes
idPlane planes[1]; // variable sized
} cm_brush_t;
typedef struct cm_brushRef_s {
cm_brush_t * b; // pointer to brush
struct cm_brushRef_s * next; // next brush in chain
} cm_brushRef_t;
typedef struct cm_brushRefBlock_s {
cm_brushRef_t * nextRef; // next brush reference in block
struct cm_brushRefBlock_s *next; // next block with brush references
} cm_brushRefBlock_t;
typedef struct cm_node_s {
int planeType; // node axial plane type
float planeDist; // node plane distance
cm_polygonRef_t * polygons; // polygons in node
cm_brushRef_t * brushes; // brushes in node
struct cm_node_s * parent; // parent of this node
struct cm_node_s * children[2]; // node children
} cm_node_t;
typedef struct cm_nodeBlock_s {
cm_node_t * nextNode; // next node in block
struct cm_nodeBlock_s *next; // next block with nodes
} cm_nodeBlock_t;
typedef struct cm_model_s {
idStr name; // model name
idBounds bounds; // model bounds
int contents; // all contents of the model ored together
bool isConvex; // set if model is convex
// model geometry
int maxVertices; // size of vertex array
int numVertices; // number of vertices
cm_vertex_t * vertices; // array with all vertices used by the model
int maxEdges; // size of edge array
int numEdges; // number of edges
cm_edge_t * edges; // array with all edges used by the model
cm_node_t * node; // first node of spatial subdivision
// blocks with allocated memory
cm_nodeBlock_t * nodeBlocks; // list with blocks of nodes
cm_polygonRefBlock_t * polygonRefBlocks; // list with blocks of polygon references
cm_brushRefBlock_t * brushRefBlocks; // list with blocks of brush references
cm_polygonBlock_t * polygonBlock; // memory block with all polygons
cm_brushBlock_t * brushBlock; // memory block with all brushes
// statistics
int numPolygons;
int polygonMemory;
int numBrushes;
int brushMemory;
int numNodes;
int numBrushRefs;
int numPolygonRefs;
int numInternalEdges;
int numSharpEdges;
int numRemovedPolys;
int numMergedPolys;
int usedMemory;
} cm_model_t;
/*
===============================================================================
Data used during collision detection calculations
===============================================================================
*/
typedef struct cm_trmVertex_s {
int used; // true if this vertex is used for collision detection
idVec3 p; // vertex position
idVec3 endp; // end point of vertex after movement
int polygonSide; // side of polygon this vertex is on (rotational collision)
idPluecker pl; // pluecker coordinate for vertex movement
idVec3 rotationOrigin; // rotation origin for this vertex
idBounds rotationBounds; // rotation bounds for this vertex
} cm_trmVertex_t;
typedef struct cm_trmEdge_s {
int used; // true when vertex is used for collision detection
idVec3 start; // start of edge
idVec3 end; // end of edge
int vertexNum[2]; // indexes into cm_traceWork_t->vertices
idPluecker pl; // pluecker coordinate for edge
idVec3 cross; // (z,-y,x) of cross product between edge dir and movement dir
idBounds rotationBounds; // rotation bounds for this edge
idPluecker plzaxis; // pluecker coordinate for rotation about the z-axis
unsigned short bitNum; // vertex bit number
} cm_trmEdge_t;
typedef struct cm_trmPolygon_s {
int used;
idPlane plane; // polygon plane
int numEdges; // number of edges
int edges[MAX_TRACEMODEL_POLYEDGES]; // index into cm_traceWork_t->edges
idBounds rotationBounds; // rotation bounds for this polygon
} cm_trmPolygon_t;
typedef struct cm_traceWork_s {
int numVerts;
cm_trmVertex_t vertices[MAX_TRACEMODEL_VERTS]; // trm vertices
int numEdges;
cm_trmEdge_t edges[MAX_TRACEMODEL_EDGES+1]; // trm edges
int numPolys;
cm_trmPolygon_t polys[MAX_TRACEMODEL_POLYS]; // trm polygons
cm_model_t *model; // model colliding with
idVec3 start; // start of trace
idVec3 end; // end of trace
idVec3 dir; // trace direction
idBounds bounds; // bounds of full trace
idBounds size; // bounds of transformed trm relative to start
idVec3 extents; // largest of abs(size[0]) and abs(size[1]) for BSP trace
int contents; // ignore polygons that do not have any of these contents flags
trace_t trace; // collision detection result
bool rotation; // true if calculating rotational collision
bool pointTrace; // true if only tracing a point
bool positionTest; // true if not tracing but doing a position test
bool isConvex; // true if the trace model is convex
bool axisIntersectsTrm; // true if the rotation axis intersects the trace model
bool getContacts; // true if retrieving contacts
bool quickExit; // set to quickly stop the collision detection calculations
idVec3 origin; // origin of rotation in model space
idVec3 axis; // rotation axis in model space
idMat3 matrix; // rotates axis of rotation to the z-axis
float angle; // angle for rotational collision
float maxTan; // max tangent of half the positive angle used instead of fraction
float radius; // rotation radius of trm start
idRotation modelVertexRotation; // inverse rotation for model vertices
contactInfo_t *contacts; // array with contacts
int maxContacts; // max size of contact array
int numContacts; // number of contacts found
idPlane heartPlane1; // polygons should be near anough the trace heart planes
float maxDistFromHeartPlane1;
idPlane heartPlane2;
float maxDistFromHeartPlane2;
idPluecker polygonEdgePlueckerCache[CM_MAX_POLYGON_EDGES];
idPluecker polygonVertexPlueckerCache[CM_MAX_POLYGON_EDGES];
idVec3 polygonRotationOriginCache[CM_MAX_POLYGON_EDGES];
} cm_traceWork_t;
/*
===============================================================================
Collision Map
===============================================================================
*/
typedef struct cm_procNode_s {
idPlane plane;
int children[2]; // negative numbers are (-1 - areaNumber), 0 = solid
} cm_procNode_t;
class idCollisionModelManagerLocal : public idCollisionModelManager {
public:
// load collision models from a map file
void LoadMap( const idMapFile *mapFile );
// HUMANHEAD pdm: Support for level appending
virtual const char * ContentsName(const int contents) const { return StringFromContents(contents); }
#if DEATHWALK_AUTOLOAD
virtual void AppendMap( const idMapFile *mapFile );
virtual bool WillUseAlreadyLoadedCollisionMap(const idMapFile *mapFile);
#endif
// HUMANHEAD END
// frees all the collision models
void FreeMap( void );
// get clip handle for model
cmHandle_t LoadModel( const char *modelName, const bool precache );
// sets up a trace model for collision with other trace models
cmHandle_t SetupTrmModel( const idTraceModel &trm, const idMaterial *material );
// create trace model from a collision model, returns true if succesfull
bool TrmFromModel( const char *modelName, idTraceModel &trm );
// name of the model
const char * GetModelName( cmHandle_t model ) const;
// bounds of the model
bool GetModelBounds( cmHandle_t model, idBounds &bounds ) const;
// all contents flags of brushes and polygons ored together
bool GetModelContents( cmHandle_t model, int &contents ) const;
// get the vertex of a model
bool GetModelVertex( cmHandle_t model, int vertexNum, idVec3 &vertex ) const;
// get the edge of a model
bool GetModelEdge( cmHandle_t model, int edgeNum, idVec3 &start, idVec3 &end ) const;
// get the polygon of a model
bool GetModelPolygon( cmHandle_t model, int polygonNum, idFixedWinding &winding ) const;
// translates a trm and reports the first collision if any
void Translation( trace_t *results, const idVec3 &start, const idVec3 &end,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// rotates a trm and reports the first collision if any
void Rotation( trace_t *results, const idVec3 &start, const idRotation &rotation,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// returns the contents the trm is stuck in or 0 if the trm is in free space
int Contents( const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// stores all contact points of the trm with the model, returns the number of contacts
int Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// test collision detection
void DebugOutput( const idVec3 &origin );
// draw a model
void DrawModel( cmHandle_t model, const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin, const float radius );
// print model information, use -1 handle for accumulated model info
void ModelInfo( cmHandle_t model );
// list all loaded models
void ListModels( void );
// write a collision model file for the map entity
bool WriteCollisionModelForMapEntity( const idMapEntity *mapEnt, const char *filename, const bool testTraceModel = true );
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
int GetNumInlinedProcClipModels(void);
#endif
//HUMANHEAD END
private: // CollisionMap_translate.cpp
int TranslateEdgeThroughEdge( idVec3 &cross, idPluecker &l1, idPluecker &l2, float *fraction );
void TranslateTrmEdgeThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge );
void TranslateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int bitNum );
void TranslatePointThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v );
void TranslateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly, cm_vertex_t *v, idVec3 &endp, idPluecker &pl );
bool TranslateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p );
void SetupTranslationHeartPlanes( cm_traceWork_t *tw );
void SetupTrm( cm_traceWork_t *tw, const idTraceModel *trm );
private: // CollisionMap_rotate.cpp
int CollisionBetweenEdgeBounds( cm_traceWork_t *tw, const idVec3 &va, const idVec3 &vb,
const idVec3 &vc, const idVec3 &vd, float tanHalfAngle,
idVec3 &collisionPoint, idVec3 &collisionNormal );
int RotateEdgeThroughEdge( cm_traceWork_t *tw, const idPluecker &pl1,
const idVec3 &vc, const idVec3 &vd,
const float minTan, float &tanHalfAngle );
int EdgeFurthestFromEdge( cm_traceWork_t *tw, const idPluecker &pl1,
const idVec3 &vc, const idVec3 &vd,
float &tanHalfAngle, float &dir );
void RotateTrmEdgeThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge );
int RotatePointThroughPlane( const cm_traceWork_t *tw, const idVec3 &point, const idPlane &plane,
const float angle, const float minTan, float &tanHalfAngle );
int PointFurthestFromPlane( const cm_traceWork_t *tw, const idVec3 &point, const idPlane &plane,
const float angle, float &tanHalfAngle, float &dir );
int RotatePointThroughEpsilonPlane( const cm_traceWork_t *tw, const idVec3 &point, const idVec3 &endPoint,
const idPlane &plane, const float angle, const idVec3 &origin,
float &tanHalfAngle, idVec3 &collisionPoint, idVec3 &endDir );
void RotateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int vertexNum);
void RotateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly,
cm_vertex_t *v, idVec3 &rotationOrigin );
bool RotateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p );
void BoundsForRotation( const idVec3 &origin, const idVec3 &axis, const idVec3 &start, const idVec3 &end, idBounds &bounds );
void Rotation180( trace_t *results, const idVec3 &rorg, const idVec3 &axis,
const float startAngle, const float endAngle, const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis );
private: // CollisionMap_contents.cpp
bool TestTrmVertsInBrush( cm_traceWork_t *tw, cm_brush_t *b );
bool TestTrmInPolygon( cm_traceWork_t *tw, cm_polygon_t *p );
cm_node_t * PointNode( const idVec3 &p, cm_model_t *model );
int PointContents( const idVec3 p, cmHandle_t model );
int TransformedPointContents( const idVec3 &p, cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis );
int ContentsTrm( trace_t *results, const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
private: // CollisionMap_trace.cpp
void TraceTrmThroughNode( cm_traceWork_t *tw, cm_node_t *node );
void TraceThroughAxialBSPTree_r( cm_traceWork_t *tw, cm_node_t *node, float p1f, float p2f, idVec3 &p1, idVec3 &p2);
void TraceThroughModel( cm_traceWork_t *tw );
void RecurseProcBSP_r( trace_t *results, int parentNodeNum, int nodeNum, float p1f, float p2f, const idVec3 &p1, const idVec3 &p2 );
private: // CollisionMap_load.cpp
void Clear( void );
void FreeTrmModelStructure( void );
// model deallocation
void RemovePolygonReferences_r( cm_node_t *node, cm_polygon_t *p );
void RemoveBrushReferences_r( cm_node_t *node, cm_brush_t *b );
void FreeNode( cm_node_t *node );
void FreePolygonReference( cm_polygonRef_t *pref );
void FreeBrushReference( cm_brushRef_t *bref );
void FreePolygon( cm_model_t *model, cm_polygon_t *poly );
void FreeBrush( cm_model_t *model, cm_brush_t *brush );
void FreeTree_r( cm_model_t *model, cm_node_t *headNode, cm_node_t *node );
void FreeModel( cm_model_t *model );
// merging polygons
void ReplacePolygons( cm_model_t *model, cm_node_t *node, cm_polygon_t *p1, cm_polygon_t *p2, cm_polygon_t *newp );
cm_polygon_t * TryMergePolygons( cm_model_t *model, cm_polygon_t *p1, cm_polygon_t *p2 );
bool MergePolygonWithTreePolygons( cm_model_t *model, cm_node_t *node, cm_polygon_t *polygon );
void MergeTreePolygons( cm_model_t *model, cm_node_t *node );
// finding internal edges
bool PointInsidePolygon( cm_model_t *model, cm_polygon_t *p, idVec3 &v );
void FindInternalEdgesOnPolygon( cm_model_t *model, cm_polygon_t *p1, cm_polygon_t *p2 );
void FindInternalPolygonEdges( cm_model_t *model, cm_node_t *node, cm_polygon_t *polygon );
void FindInternalEdges( cm_model_t *model, cm_node_t *node );
void FindContainedEdges( cm_model_t *model, cm_polygon_t *p );
// loading of proc BSP tree
void ParseProcNodes( idLexer *src );
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
void CheckProcModelSurfClip(idLexer *src);
#endif
//HUMANHEAD END
void LoadProcBSP( const char *name );
// removal of contained polygons
int R_ChoppedAwayByProcBSP( int nodeNum, idFixedWinding *w, const idVec3 &normal, const idVec3 &origin, const float radius );
int ChoppedAwayByProcBSP( const idFixedWinding &w, const idPlane &plane, int contents );
void ChopWindingListWithBrush( cm_windingList_t *list, cm_brush_t *b );
void R_ChopWindingListWithTreeBrushes( cm_windingList_t *list, cm_node_t *node );
idFixedWinding *WindingOutsideBrushes( idFixedWinding *w, const idPlane &plane, int contents, int patch, cm_node_t *headNode );
// creation of axial BSP tree
cm_model_t * AllocModel( void );
cm_node_t * AllocNode( cm_model_t *model, int blockSize );
cm_polygonRef_t*AllocPolygonReference( cm_model_t *model, int blockSize );
cm_brushRef_t * AllocBrushReference( cm_model_t *model, int blockSize );
cm_polygon_t * AllocPolygon( cm_model_t *model, int numEdges );
cm_brush_t * AllocBrush( cm_model_t *model, int numPlanes );
void AddPolygonToNode( cm_model_t *model, cm_node_t *node, cm_polygon_t *p );
void AddBrushToNode( cm_model_t *model, cm_node_t *node, cm_brush_t *b );
void SetupTrmModelStructure( void );
void R_FilterPolygonIntoTree( cm_model_t *model, cm_node_t *node, cm_polygonRef_t *pref, cm_polygon_t *p );
void R_FilterBrushIntoTree( cm_model_t *model, cm_node_t *node, cm_brushRef_t *pref, cm_brush_t *b );
cm_node_t * R_CreateAxialBSPTree( cm_model_t *model, cm_node_t *node, const idBounds &bounds );
cm_node_t * CreateAxialBSPTree( cm_model_t *model, cm_node_t *node );
// creation of raw polygons
void SetupHash(void);
void ShutdownHash(void);
void ClearHash( idBounds &bounds );
int HashVec(const idVec3 &vec);
int GetVertex( cm_model_t *model, const idVec3 &v, int *vertexNum );
int GetEdge( cm_model_t *model, const idVec3 &v1, const idVec3 &v2, int *edgeNum, int v1num );
void CreatePolygon( cm_model_t *model, idFixedWinding *w, const idPlane &plane, const idMaterial *material, int primitiveNum );
void PolygonFromWinding( cm_model_t *model, idFixedWinding *w, const idPlane &plane, const idMaterial *material, int primitiveNum );
void CalculateEdgeNormals( cm_model_t *model, cm_node_t *node );
void CreatePatchPolygons( cm_model_t *model, idSurface_Patch &mesh, const idMaterial *material, int primitiveNum );
void ConvertPatch( cm_model_t *model, const idMapPatch *patch, int primitiveNum );
void ConvertBrushSides( cm_model_t *model, const idMapBrush *mapBrush, int primitiveNum );
void ConvertBrush( cm_model_t *model, const idMapBrush *mapBrush, int primitiveNum );
void PrintModelInfo( const cm_model_t *model );
void AccumulateModelInfo( cm_model_t *model );
void RemapEdges( cm_node_t *node, int *edgeRemap );
void OptimizeArrays( cm_model_t *model );
void FinishModel( cm_model_t *model );
void BuildModels( const idMapFile *mapFile );
cmHandle_t FindModel( const char *name );
cm_model_t * CollisionModelForMapEntity( const idMapEntity *mapEnt ); // brush/patch model from .map
cm_model_t * LoadRenderModel( const char *fileName ); // ASE/LWO models
bool TrmFromModel_r( idTraceModel &trm, cm_node_t *node );
bool TrmFromModel( const cm_model_t *model, idTraceModel &trm );
private: // CollisionMap_files.cpp
// writing
void WriteNodes( idFile *fp, cm_node_t *node );
int CountPolygonMemory( cm_node_t *node ) const;
void WritePolygons( idFile *fp, cm_node_t *node );
int CountBrushMemory( cm_node_t *node ) const;
void WriteBrushes( idFile *fp, cm_node_t *node );
void WriteCollisionModel( idFile *fp, cm_model_t *model );
void WriteCollisionModelsToFile( const char *filename, int firstModel, int lastModel, unsigned int mapFileCRC );
// loading
cm_node_t * ParseNodes( idLexer *src, cm_model_t *model, cm_node_t *parent );
void ParseVertices( idLexer *src, cm_model_t *model );
void ParseEdges( idLexer *src, cm_model_t *model );
void ParsePolygons( idLexer *src, cm_model_t *model );
void ParseBrushes( idLexer *src, cm_model_t *model );
bool ParseCollisionModel( idLexer *src );
bool LoadCollisionModelFile( const char *name, unsigned int mapFileCRC );
private: // CollisionMap_debug
int ContentsFromString( const char *string ) const;
const char * StringFromContents( const int contents ) const;
void DrawEdge( cm_model_t *model, int edgeNum, const idVec3 &origin, const idMat3 &axis );
void DrawPolygon( cm_model_t *model, cm_polygon_t *p, const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin );
void DrawNodePolygons( cm_model_t *model, cm_node_t *node, const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin, const float radius );
private: // collision map data
idStr mapName;
unsigned int mapFileTime;
int loaded;
// for multi-check avoidance
int checkCount;
// models
int maxModels;
int numModels;
cm_model_t ** models;
// polygons and brush for trm model
cm_polygonRef_t*trmPolygons[MAX_TRACEMODEL_POLYS];
cm_brushRef_t * trmBrushes[1];
const idMaterial *trmMaterial;
// for data pruning
int numProcNodes;
cm_procNode_t * procNodes;
// for retrieving contact points
bool getContacts;
contactInfo_t * contacts;
int maxContacts;
int numContacts;
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
idList<const char *> inlinedProcClipModelMats;
int numInlinedProcClipModels;
bool anyInlinedProcClipMats;
#endif
//HUMANHEAD END
};
// for debugging
extern idCVar cm_debugCollision;
File diff suppressed because it is too large Load Diff
+229
View File
@@ -0,0 +1,229 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Trace through the spatial subdivision
===============================================================================
*/
/*
================
idCollisionModelManagerLocal::TraceTrmThroughNode
================
*/
void idCollisionModelManagerLocal::TraceTrmThroughNode( cm_traceWork_t *tw, cm_node_t *node ) {
cm_polygonRef_t *pref;
cm_brushRef_t *bref;
// position test
if ( tw->positionTest ) {
// if already stuck in solid
if ( tw->trace.fraction == 0.0f ) {
return;
}
// test if any of the trm vertices is inside a brush
for ( bref = node->brushes; bref; bref = bref->next ) {
if ( idCollisionModelManagerLocal::TestTrmVertsInBrush( tw, bref->b ) ) {
return;
}
}
// if just testing a point we're done
if ( tw->pointTrace ) {
return;
}
// test if the trm is stuck in any polygons
for ( pref = node->polygons; pref; pref = pref->next ) {
if ( idCollisionModelManagerLocal::TestTrmInPolygon( tw, pref->p ) ) {
return;
}
}
}
else if ( tw->rotation ) {
// rotate through all polygons in this leaf
for ( pref = node->polygons; pref; pref = pref->next ) {
if ( idCollisionModelManagerLocal::RotateTrmThroughPolygon( tw, pref->p ) ) {
return;
}
}
}
else {
// trace through all polygons in this leaf
for ( pref = node->polygons; pref; pref = pref->next ) {
if ( idCollisionModelManagerLocal::TranslateTrmThroughPolygon( tw, pref->p ) ) {
return;
}
}
}
}
/*
================
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r
================
*/
//#define NO_SPATIAL_SUBDIVISION
void idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( cm_traceWork_t *tw, cm_node_t *node, float p1f, float p2f, idVec3 &p1, idVec3 &p2) {
float t1, t2, offset;
float frac, frac2;
float idist;
idVec3 mid;
int side;
float midf;
if ( !node ) {
return;
}
if ( tw->quickExit ) {
return; // stop immediately
}
if ( tw->trace.fraction <= p1f ) {
return; // already hit something nearer
}
// if we need to test this node for collisions
if ( node->polygons || (tw->positionTest && node->brushes) ) {
// trace through node with collision data
idCollisionModelManagerLocal::TraceTrmThroughNode( tw, node );
}
// if already stuck in solid
if ( tw->positionTest && tw->trace.fraction == 0.0f ) {
return;
}
// if this is a leaf node
if ( node->planeType == -1 ) {
return;
}
#ifdef NO_SPATIAL_SUBDIVISION
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 );
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 );
return;
#endif
// distance from plane for trace start and end
t1 = p1[node->planeType] - node->planeDist;
t2 = p2[node->planeType] - node->planeDist;
// adjust the plane distance appropriately for mins/maxs
offset = tw->extents[node->planeType];
// see which sides we need to consider
if ( t1 >= offset && t2 >= offset ) {
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 );
return;
}
if ( t1 < -offset && t2 < -offset ) {
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 );
return;
}
if ( t1 < t2 ) {
idist = 1.0f / (t1-t2);
side = 1;
frac2 = (t1 + offset) * idist;
frac = (t1 - offset) * idist;
} else if (t1 > t2) {
idist = 1.0f / (t1-t2);
side = 0;
frac2 = (t1 - offset) * idist;
frac = (t1 + offset) * idist;
} else {
side = 0;
frac = 1.0f;
frac2 = 0.0f;
}
// move up to the node
if ( frac < 0.0f ) {
frac = 0.0f;
}
else if ( frac > 1.0f ) {
frac = 1.0f;
}
midf = p1f + (p2f - p1f)*frac;
mid[0] = p1[0] + frac*(p2[0] - p1[0]);
mid[1] = p1[1] + frac*(p2[1] - p1[1]);
mid[2] = p1[2] + frac*(p2[2] - p1[2]);
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side], p1f, midf, p1, mid );
// go past the node
if ( frac2 < 0.0f ) {
frac2 = 0.0f;
}
else if ( frac2 > 1.0f ) {
frac2 = 1.0f;
}
midf = p1f + (p2f - p1f)*frac2;
mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side^1], midf, p2f, mid, p2 );
}
/*
================
idCollisionModelManagerLocal::TraceThroughModel
================
*/
void idCollisionModelManagerLocal::TraceThroughModel( cm_traceWork_t *tw ) {
float d;
int i, numSteps;
idVec3 start, end;
idRotation rot;
if ( !tw->rotation ) {
// trace through spatial subdivision and then through leafs
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, tw->start, tw->end );
}
else {
// approximate the rotation with a series of straight line movements
// total length covered along circle
d = tw->radius * DEG2RAD( tw->angle );
// if more than one step
if ( d > CIRCLE_APPROXIMATION_LENGTH ) {
// number of steps for the approximation
numSteps = (int) (CIRCLE_APPROXIMATION_LENGTH / d);
// start of approximation
start = tw->start;
// trace circle approximation steps through the BSP tree
for ( i = 0; i < numSteps; i++ ) {
// calculate next point on approximated circle
rot.Set( tw->origin, tw->axis, tw->angle * ((float) (i+1) / numSteps) );
end = start * rot;
// trace through spatial subdivision and then through leafs
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, end );
// no need to continue if something was hit already
if ( tw->trace.fraction < 1.0f ) {
return;
}
start = end;
}
}
else {
start = tw->start;
}
// last step of the approximation
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, tw->end );
}
}
File diff suppressed because it is too large Load Diff
+24
View File
@@ -5,6 +5,10 @@
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|x64">
<Configuration>Prey Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
@@ -33,6 +37,11 @@
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@@ -48,12 +57,21 @@
<Import Project="_Curl.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="_Common.props" />
<Import Project="_Curl.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
@@ -64,6 +82,12 @@
<PreprocessorDefinitions>_USRDLL;CURLLIB_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>.\curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_USRDLL;CURLLIB_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>.\curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+230 -8
View File
@@ -25,6 +25,10 @@
<Configuration>Dedicated Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|x64">
<Configuration>Prey Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
@@ -88,6 +92,12 @@
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@@ -140,6 +150,12 @@
<Import Project="_DoomDLL.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="_Common.props" />
<Import Project="_DoomDLL.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
@@ -150,8 +166,11 @@
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
@@ -204,6 +223,20 @@
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<Link>
<AdditionalLibraryDirectories>openal\lib;sys\win32\dongle;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>../Prey.exe</OutputFile>
<AdditionalDependencies>d3d12.lib;nafxcwd.lib;libcmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<ClCompile>
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>PREY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">
<Link>
<AdditionalLibraryDirectories>openal\lib;sys\win32\dongle;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -260,6 +293,8 @@
<ItemGroup>
<ClInclude Include="cm\CollisionModel.h" />
<ClInclude Include="cm\CollisionModel_local.h" />
<ClInclude Include="cm\PreyCM\CollisionModel.h" />
<ClInclude Include="cm\PreyCM\CollisionModel_local.h" />
<ClInclude Include="framework\BuildDefines.h" />
<ClInclude Include="framework\BuildVersion.h" />
<ClInclude Include="framework\CmdSystem.h" />
@@ -637,6 +672,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -646,6 +682,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -655,6 +692,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -664,6 +702,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -673,6 +712,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -682,6 +722,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -691,6 +732,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -700,6 +742,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -709,6 +752,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -1261,14 +1305,94 @@
</CustomBuildStep>
</ItemGroup>
<ItemGroup>
<ClCompile Include="cm\CollisionModel_contacts.cpp" />
<ClCompile Include="cm\CollisionModel_contents.cpp" />
<ClCompile Include="cm\CollisionModel_debug.cpp" />
<ClCompile Include="cm\CollisionModel_files.cpp" />
<ClCompile Include="cm\CollisionModel_load.cpp" />
<ClCompile Include="cm\CollisionModel_rotate.cpp" />
<ClCompile Include="cm\CollisionModel_trace.cpp" />
<ClCompile Include="cm\CollisionModel_translate.cpp" />
<ClCompile Include="cm\CollisionModel_contacts.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_contents.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_debug.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_files.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_load.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_rotate.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_trace.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\CollisionModel_translate.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_contacts.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_contents.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_debug.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_files.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_load.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_rotate.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_trace.cpp" />
<ClCompile Include="cm\PreyCM\CollisionModel_translate.cpp" />
<ClCompile Include="framework\CmdSystem.cpp" />
<ClCompile Include="framework\Common.cpp" />
<ClCompile Include="framework\Compressor.cpp" />
@@ -1300,6 +1424,7 @@
<ClCompile Include="framework\async\ServerScan.cpp" />
<ClCompile Include="idlib\precompiled.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">Create</PrecompiledHeader>
@@ -1355,6 +1480,7 @@
<ClCompile Include="renderer\VertexCache.cpp" />
<ClCompile Include="renderer\jpeg-6\jcapimin.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1364,6 +1490,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jccoefct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1373,6 +1500,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jccolor.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1382,6 +1510,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcdctmgr.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1391,6 +1520,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jchuff.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1400,6 +1530,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcinit.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1409,6 +1540,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcmainct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1418,6 +1550,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcmarker.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1427,6 +1560,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcmaster.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1436,6 +1570,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcomapi.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1445,6 +1580,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcparam.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1454,6 +1590,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcphuff.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1463,6 +1600,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcprepct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1472,6 +1610,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jcsample.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1481,6 +1620,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdapimin.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1490,6 +1630,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdapistd.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1499,6 +1640,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdatadst.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1508,6 +1650,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdatasrc.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1517,6 +1660,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdcoefct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1526,6 +1670,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdcolor.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1535,6 +1680,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jddctmgr.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1544,6 +1690,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdhuff.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1553,6 +1700,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdinput.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1562,6 +1710,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdmainct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1571,6 +1720,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdmarker.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1580,6 +1730,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdmaster.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1589,6 +1740,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdmerge.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1598,6 +1750,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdphuff.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1607,6 +1760,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdpostct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1616,6 +1770,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdsample.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1625,6 +1780,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jdtrans.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1634,6 +1790,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jerror.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1643,6 +1800,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jfdctflt.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1652,6 +1810,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jfdctfst.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1661,6 +1820,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jfdctint.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1670,6 +1830,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jidctflt.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1679,6 +1840,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jidctfst.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1688,6 +1850,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jidctint.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1697,6 +1860,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jidctred.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1706,6 +1870,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jmemmgr.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1715,6 +1880,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jmemnobs.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1724,6 +1890,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jquant1.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1733,6 +1900,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jquant2.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1742,6 +1910,7 @@
</ClCompile>
<ClCompile Include="renderer\jpeg-6\jutils.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1759,6 +1928,7 @@
<ClCompile Include="sound\snd_world.cpp" />
<ClCompile Include="sound\OggVorbis\vorbissrc\analysis.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1768,6 +1938,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\barkmel.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1777,6 +1948,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\bitrate.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1786,6 +1958,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\block.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1795,6 +1968,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\codebook.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1804,6 +1978,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\envelope.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1813,6 +1988,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\floor0.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1822,6 +1998,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\floor1.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1831,6 +2008,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\info.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1840,6 +2018,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\lookup.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1849,6 +2028,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\lpc.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1858,6 +2038,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\lsp.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1867,6 +2048,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\mapping0.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1876,6 +2058,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\mdct.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1885,6 +2068,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\psy.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1894,6 +2078,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\registry.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1903,6 +2088,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\res0.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1912,6 +2098,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\sharedbook.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1921,6 +2108,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\smallft.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1930,6 +2118,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\synthesis.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1939,6 +2128,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\vorbisenc.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1948,6 +2138,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\vorbisfile.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1957,6 +2148,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\vorbissrc\windowvb.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1966,6 +2158,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\oggsrc\bitwise.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1975,6 +2168,7 @@
</ClCompile>
<ClCompile Include="sound\OggVorbis\oggsrc\framing.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">NotUsing</PrecompiledHeader>
@@ -1991,6 +2185,7 @@
<ClCompile Include="sys\win32\win_shared.cpp" />
<ClCompile Include="sys\win32\win_snd.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -2247,6 +2442,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2256,6 +2452,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2265,6 +2462,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2274,6 +2472,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2283,6 +2482,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2292,6 +2492,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2301,6 +2502,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2310,6 +2512,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2319,6 +2522,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -2998,6 +3202,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3007,6 +3212,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3016,6 +3222,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3025,6 +3232,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3035,6 +3243,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3044,6 +3253,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3053,6 +3263,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3062,6 +3273,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3071,6 +3283,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3080,6 +3293,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3089,6 +3303,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3098,6 +3313,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
@@ -3119,6 +3335,12 @@
<ProjectReference Include="opengl\opengl.vcxproj">
<Project>{58320c19-5139-47c5-aafe-4cad2c8ed14d}</Project>
</ProjectReference>
<ProjectReference Include="prey\PreyGame.vcxproj">
<Project>{6cd8e46d-e28e-493f-bb06-537a637a68c2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Image Include="sys\win32\rc\res\prey.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
+38
View File
@@ -106,6 +106,9 @@
<Filter Include="Ui">
<UniqueIdentifier>{b3166d25-0562-49da-bc8d-961006fe1785}</UniqueIdentifier>
</Filter>
<Filter Include="CM\PreyCM">
<UniqueIdentifier>{f7ebd0db-2189-45da-a492-76ab782e337a}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="cm\CollisionModel.h">
@@ -603,6 +606,12 @@
<ClInclude Include="renderer\DeviceContext.h">
<Filter>Renderer</Filter>
</ClInclude>
<ClInclude Include="cm\PreyCM\CollisionModel.h">
<Filter>CM\PreyCM</Filter>
</ClInclude>
<ClInclude Include="cm\PreyCM\CollisionModel_local.h">
<Filter>CM\PreyCM</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="cm\CollisionModel_contacts.cpp">
@@ -1766,6 +1775,30 @@
<ClCompile Include="renderer\draw_dx.cpp">
<Filter>Renderer</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_contacts.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_contents.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_debug.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_files.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_load.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_rotate.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_trace.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
<ClCompile Include="cm\PreyCM\CollisionModel_translate.cpp">
<Filter>CM\PreyCM</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="openal\idal.py">
@@ -2484,4 +2517,9 @@
<Filter>Tools\Script</Filter>
</CustomBuildStep>
</ItemGroup>
<ItemGroup>
<Image Include="sys\win32\rc\res\prey.ico">
<Filter>Sys\RC\res</Filter>
</Image>
</ItemGroup>
</Project>
+8
View File
@@ -19,6 +19,13 @@
<LocalDebuggerWorkingDirectory>D:\projects\Doom3</LocalDebuggerWorkingDirectory>
<LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 6|+set r_fullscreen 1 +set r_mode 6|+set r_fullscreen 1 +set r_mode 1|+set r_fullscreen 0 +set r_mode 1|</LocalDebuggerCommandArgumentsHistory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<LocalDebuggerCommand>D:\projects\Doom3\Prey.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>+set r_fullscreen 0 +set r_mode 1</LocalDebuggerCommandArguments>
<LocalDebuggerWorkingDirectory>D:\projects\Doom3</LocalDebuggerWorkingDirectory>
<LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 6|+set r_fullscreen 1 +set r_mode 6|+set r_fullscreen 1 +set r_mode 1|+set r_fullscreen 0 +set r_mode 1|</LocalDebuggerCommandArgumentsHistory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">
<LocalDebuggerCommand>D:\projects\Doom3\Doom3.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
@@ -36,6 +43,7 @@
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>+set r_fullscreen 0 +set r_mode 6</LocalDebuggerCommandArguments>
<LocalDebuggerWorkingDirectory>D:\projects\Doom3</LocalDebuggerWorkingDirectory>
<LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 6|</LocalDebuggerCommandArgumentsHistory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommand>D:\projects\Doom3\Doom3.exe</LocalDebuggerCommand>
+5
View File
@@ -133,3 +133,8 @@ If you have questions concerning this license or the applicable additional terms
# endif
#endif
// jmarshall - have to make this public outside of preygame for the collision model code.
#ifdef PREY
#define DEATHWALK_AUTOLOAD 1 // Append deathwalk map to all maps loaded
#endif
// jmarshall end
+149 -3
View File
@@ -146,7 +146,9 @@ public:
virtual void Error( const char *fmt, ... ) id_attribute((format(printf,2,3)));
virtual void FatalError( const char *fmt, ... ) id_attribute((format(printf,2,3)));
virtual const idLangDict * GetLanguageDict( void );
#ifdef PREY
virtual void MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey);
#endif
virtual const char * KeysFromBinding( const char *bind );
virtual const char * BindingFromKey( const char *key );
@@ -2645,8 +2647,11 @@ void idCommonLocal::LoadGameDLL( void ) {
gameImport_t gameImport;
gameExport_t gameExport;
GetGameAPI_t GetGameAPI;
#ifdef PREY
fileSystem->FindDLL( "preygame", dllPath, true);
#else
fileSystem->FindDLL( "game", dllPath, true );
#endif
if ( !dllPath[ 0 ] ) {
common->FatalError( "couldn't find game dynamic library" );
@@ -3122,4 +3127,145 @@ int64_t idCommonLocal::Get_com_engineHz_numerator(void) {
int64_t idCommonLocal::Get_com_engineHz_denominator(void) {
return com_engineHz_denominator;
}
}
#ifdef PREY
void idCommonLocal::MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey) {
bool unused1 = false;
bool unused2 = false;
idStr keyName;
idStr displayName;
const char* rawKey = idKeyInput::SingleKeyFromBinding(binding, unused1);
if (rawKey != NULL) {
keyName = rawKey;
}
const char* localizedKey = idKeyInput::SingleKeyFromBinding(binding, unused2);
if (localizedKey != NULL) {
displayName = localizedKey;
}
keyText[0] = '\0';
*wideKey = false;
if (keyName.Length() <= 0) {
strcpy(materialName, "textures/interface/tips/keywide");
const idLangDict* lang = GetLanguageDict();
strcpy(keyText, lang->GetString("#str_07133"));
*wideKey = true;
return;
}
if (!keyName.Icmp("mouse1")) {
strcpy(materialName, "textures/interface/tips/mouse1");
return;
}
if (!keyName.Icmp("mouse2")) {
strcpy(materialName, "textures/interface/tips/mouse2");
return;
}
if (!keyName.Icmp("mouse3")) {
strcpy(materialName, "textures/interface/tips/mouse3");
return;
}
if (!keyName.Icmp("mwheelup")) {
strcpy(materialName, "textures/interface/tips/mouseup");
return;
}
if (!keyName.Icmp("mwheeldown")) {
strcpy(materialName, "textures/interface/tips/mousedn");
return;
}
if (!keyName.Icmp("uparrow")) {
strcpy(materialName, "textures/interface/tips/uparrow");
return;
}
if (!keyName.Icmp("downarrow")) {
strcpy(materialName, "textures/interface/tips/downarrow");
return;
}
if (!keyName.Icmp("leftarrow")) {
strcpy(materialName, "textures/interface/tips/leftarrow");
return;
}
if (!keyName.Icmp("rightarrow")) {
strcpy(materialName, "textures/interface/tips/rightarrow");
return;
}
if (!keyName.Icmp("enter")) {
strcpy(materialName, "textures/interface/tips/enter");
*wideKey = true;
return;
}
if (!keyName.Icmp("backspace")) {
strcpy(materialName, "textures/interface/tips/backspace");
*wideKey = true;
return;
}
if (!keyName.Icmp("tab")) {
strcpy(materialName, "textures/interface/tips/tab");
*wideKey = true;
return;
}
if (!keyName.Icmp("menu")) {
strcpy(materialName, "textures/interface/tips/menu");
return;
}
if (!keyName.Icmp("shift")) {
strcpy(materialName, "textures/interface/tips/shift");
*wideKey = true;
return;
}
/*
Generic short printable keys use the normal key material and put the
localized/display key text on top of it.
The original excludes large/special keys from this path:
printscreen, keypad keys, pause, capslock, windows keys,
modifiers, and space.
*/
if (keyName.Icmp("printscreen") &&
keyName.Icmpn("kp_", 3) &&
keyName.Icmp("pause") &&
keyName.Icmp("capslock") &&
keyName.Icmp("lwin") &&
keyName.Icmp("rwin") &&
keyName.Icmp("shift") &&
keyName.Icmp("ctrl") &&
keyName.Icmp("alt") &&
keyName.Icmp("space") &&
displayName.Length() <= 3) {
strcpy(materialName, "textures/interface/tips/key");
strcpy(keyText, displayName.c_str());
return;
}
/*
Everything else falls back to the wide key material with text.
This handles longer key names or special keys that do not have
dedicated art.
*/
strcpy(materialName, "textures/interface/tips/keywide");
strcpy(keyText, displayName.c_str());
*wideKey = true;
}
#endif
+8
View File
@@ -37,6 +37,10 @@ If you have questions concerning this license or the applicable additional terms
==============================================================
*/
#ifdef PREY
class idKeyInput;
#endif
typedef enum {
EDITOR_NONE = 0,
EDITOR_RADIANT = BIT(1),
@@ -205,6 +209,10 @@ public:
// Directly sample a keystate.
virtual int KeyState( int key ) = 0;
#ifdef PREY
virtual void MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey) = 0;
#endif
virtual float Get_com_engineHz_latched(void) = 0;
virtual int64_t Get_com_engineHz_numerator(void) = 0;
virtual int64_t Get_com_engineHz_denominator(void) = 0;
+30
View File
@@ -189,6 +189,16 @@ void idDeclFX::ParseSingleFXAction( idLexer &src, idFXSingleAction& FXAction ) {
continue;
}
#ifdef PREY
if (!token.Icmp("useAxis")) {
if (!src.ReadToken(&token)) {
break;
}
ParseUseAxis(token, FXAction);
continue;
}
#endif
if ( !token.Icmp( "rotate" ) ) {
FXAction.rotate = src.ParseFloat();
continue;
@@ -471,3 +481,23 @@ idDeclFX::FreeData
void idDeclFX::FreeData( void ) {
events.Clear();
}
#ifdef PREY
void idDeclFX::ParseUseAxis(idStr& text, idFXSingleAction& action) const {
if (!idStr::Icmp(text, "normal")) {
action.useAxis = AXIS_NORMAL;
}
else if (!idStr::Icmp(text, "bounce")) {
action.useAxis = AXIS_BOUNCE;
}
else if (!idStr::Icmp(text, "incoming")) {
action.useAxis = AXIS_INCOMING;
}
else if (!idStr::Icmp(text, "customlocal")) {
action.useAxis = AXIS_CUSTOMLOCAL;
}
else {
action.useAxis = AXIS_CURRENT;
}
}
#endif
+17 -1
View File
@@ -60,7 +60,12 @@ typedef struct {
idStr data;
idStr name;
idStr fire;
#ifdef PREY
// HUMANHEAD nla
int useAxis;
idVec3 dir;
// HUMANHEAD END
#endif
float delay;
float duration;
float restart;
@@ -91,6 +96,11 @@ typedef struct {
bool trackOrigin;
} idFXSingleAction;
#ifdef PREY
enum fxAxis { AXIS_CURRENT, AXIS_NORMAL, AXIS_BOUNCE, AXIS_INCOMING, AXIS_CUSTOMLOCAL };
#endif
//
// grouped fx structures
//
@@ -108,6 +118,12 @@ public:
private:
void ParseSingleFXAction( idLexer &src, idFXSingleAction& FXAction );
#ifdef PREY
// HUMANHEAD nla
void ParseUseAxis(idStr& text, idFXSingleAction& action) const;
// HUMANHEAD END
#endif
};
#endif /* !__DECLFX_H__ */
+3
View File
@@ -78,6 +78,9 @@ typedef enum {
DECL_EMAIL,
DECL_MODELEXPORT,
DECL_MAPDEF,
#ifdef PREY
DECL_BEAM,
#endif
// new decl types can be added here
+1 -1
View File
@@ -50,7 +50,7 @@ public:
virtual bool Parse( const char *text, const int textLength );
virtual void FreeData( void );
const idMaterial * RemapShaderBySkin( const idMaterial *shader ) const;
virtual const idMaterial * RemapShaderBySkin( const idMaterial *shader ) const;
// model associations are just for the preview dialog in the editor
const int GetNumModelAssociations() const;
+1 -1
View File
@@ -45,7 +45,7 @@ public:
virtual bool Parse( const char *text, const int textLength );
virtual void FreeData( void );
float TableLookup( float index ) const;
virtual float TableLookup( float index ) const;
private:
bool clamp;
+33
View File
@@ -454,6 +454,39 @@ int idKeyInput::GetUsercmdAction( int keynum ) {
return keys[ keynum ].usercmdAction;
}
#ifdef PREY
/*
===================
idKeyInput::SingleKeyFromBinding
===================
*/
const char* idKeyInput::SingleKeyFromBinding(const char* binding, bool localized) {
static idStr keyName;
keyName.Clear();
if (binding == NULL || binding[0] == '\0') {
return keyName.c_str();
}
int keyNum;
for (keyNum = 0; keyNum < 256; keyNum++) {
if (!idStr::Icmp(keys[keyNum].binding, binding)) {
break;
}
}
if (keyNum == 256) {
return keyName.c_str();
}
keyName.Append(KeyNumToString(keyNum, localized));
return keyName.c_str();
}
#endif
/*
===================
Key_Unbind_f
+4
View File
@@ -207,6 +207,10 @@ public:
static int StringToKeyNum( const char *str );
static const char * KeyNumToString( int keyNum, bool localized );
#ifdef PREY
static const char* SingleKeyFromBinding(const char* binding, bool localized);
#endif
static void SetBinding( int keyNum, const char *binding );
static const char * GetBinding( int keyNum );
static bool UnbindBinding( const char *bind );
+16 -3
View File
@@ -34,21 +34,34 @@ If you have questions concerning this license or the applicable additional terms
===============================================================================
*/
#define GAME_NAME "DOOM 3" // appears on window titles and errors
#ifdef PREY
#define GAME_NAME "PREY" // appears on window titles and errors
#else
#define GAME_NAME "DOOM 3" // appears on window titles and errors
#endif
#define ENGINE_VERSION "DOOM 1.3.1" // printed in console
#define ENGINE_VERSION GAME_NAME " " __DATE__ " " __TIME__ // printed in console
// paths
#define CD_BASEDIR "Doom"
#ifdef ID_DEMO_BUILD
#define BASE_GAMEDIR "demo"
#else
#ifdef PREY
#define BASE_GAMEDIR "preybase"
#else
#define BASE_GAMEDIR "base"
#endif
#endif
// filenames
#define CD_EXE "doom.exe"
#ifdef PREY
#define CONFIG_FILE "PreyConfig.cfg"
#else
#define CONFIG_FILE "DoomConfig.cfg"
#endif
// base folder where the source code lives
#define SOURCE_CODE_BASE_FOLDER "neo"
@@ -90,7 +103,7 @@ If you have questions concerning this license or the applicable additional terms
// editor info
#define EDITOR_DEFAULT_PROJECT "doom.qe4"
#define EDITOR_REGISTRY_KEY "DOOMRadiant"
#define EDITOR_WINDOWTEXT "IceEdit2"
#define EDITOR_WINDOWTEXT "IceEdit2(for " GAME_NAME " )"
// win32 info
#define WIN32_CONSOLE_CLASS "DOOM 3 WinConsole"
+2
View File
@@ -1444,7 +1444,9 @@ void idSessionLocal::LoadLoadingGui( const char *mapName ) {
char guiMap[ MAX_STRING_CHARS ];
strncpy( guiMap, va( "guis/map/%s.gui", stripped.c_str() ), MAX_STRING_CHARS );
// give the gamecode a chance to override
#ifndef PREY
game->GetMapLoadingGUI( guiMap );
#endif
if ( uiManager->CheckGui( guiMap ) ) {
guiLoading = uiManager->FindGui( guiMap, true, false, true );
+2
View File
@@ -576,9 +576,11 @@ void idSessionLocal::HandleMainMenuCommands( const char *menuCommand ) {
}
// always let the game know the command is being run
#ifndef PREY
if ( game ) {
game->HandleMainMenuCommands( cmd, guiActive );
}
#endif
if ( !idStr::Icmp( cmd, "startGame" ) ) {
cvarSystem->SetCVarInteger( "g_skill", guiMainMenu->State().GetInt( "skill" ) );
+6
View File
@@ -44,9 +44,15 @@ const int USERCMD_MSEC = 1000 / USERCMD_HZ;
const int BUTTON_ATTACK = BIT(0);
const int BUTTON_RUN = BIT(1);
const int BUTTON_ZOOM = BIT(2);
#ifdef PREY
const int BUTTON_ATTACK_ALT = BIT(3);
const int BUTTON_SCORES = BIT(4);
const int BUTTON_MLOOK = BIT(5);
#else
const int BUTTON_SCORES = BIT(3);
const int BUTTON_MLOOK = BIT(4);
const int BUTTON_5 = BIT(5);
#endif
const int BUTTON_6 = BIT(6);
const int BUTTON_7 = BIT(7);
+4
View File
@@ -1880,7 +1880,11 @@ void idAsyncClient::RunFrame( void ) {
bool lastPredictFrame = ( snapshotGameFrame + 1 >= gameFrame && gameTimeResidual + clientPredictTime < USERCMD_MSEC );
// run client prediction
#ifdef PREY
gameReturn_t ret = game->ClientPrediction(clientNum, userCmds[snapshotGameFrame & (MAX_USERCMD_BACKUP - 1)]);
#else
gameReturn_t ret = game->ClientPrediction( clientNum, userCmds[ snapshotGameFrame & ( MAX_USERCMD_BACKUP - 1 ) ], lastPredictFrame );
#endif
idAsyncNetwork::ExecuteSessionCommand( ret.sessionCommand );
+8
View File
@@ -255,7 +255,11 @@ void idAsyncServer::ExecuteMapChange( void ) {
fileSystem->ClearPureChecksums();
// make sure the map/gametype combo is good
#ifdef PREY
strcpy(bestGameType, game->GetBestGameType(cvarSystem->GetCVarString("si_map"), cvarSystem->GetCVarString("si_gametype")));
#else
game->GetBestGameType( cvarSystem->GetCVarString("si_map"), cvarSystem->GetCVarString("si_gametype"), bestGameType );
#endif
cvarSystem->SetCVarString("si_gametype", bestGameType );
// initialize map settings
@@ -695,7 +699,11 @@ void idAsyncServer::InitClient( int clientNum, int clientId, int clientRate ) {
}
// let the game know a player connected
#ifdef PREY
game->ServerClientConnect(clientNum);
#else
game->ServerClientConnect( clientNum, client.guid );
#endif
}
/*
+34
View File
@@ -25,6 +25,10 @@
<Configuration>Dedicated Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|x64">
<Configuration>Prey Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
@@ -79,6 +83,11 @@
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@@ -131,6 +140,12 @@
<Import Project="_Game.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="_Common.props" />
<Import Project="_Game.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
@@ -141,8 +156,11 @@
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
@@ -171,6 +189,21 @@
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<PreBuildEvent>
<Command>
</Command>
</PreBuildEvent>
<Link>
<OutputFile>../gamex64.dll</OutputFile>
</Link>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<ClCompile>
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">
<PreBuildEvent>
<Command>
@@ -333,6 +366,7 @@
<ClCompile Include="game\WorldSpawn.cpp" />
<ClCompile Include="idlib\precompiled.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">Create</PrecompiledHeader>
+25 -1
View File
@@ -25,6 +25,10 @@
<Configuration>Dedicated Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|x64">
<Configuration>Prey Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
@@ -79,6 +83,11 @@
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v145</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@@ -131,6 +140,12 @@
<Import Project="_idlib.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="_Common.props" />
<Import Project="_idlib.props" />
<Import Project="_Debug.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
@@ -141,8 +156,11 @@
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'" />
@@ -156,7 +174,10 @@
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>PREY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="idlib\bv\Bounds.cpp" />
@@ -206,8 +227,11 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines and memory log|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with inlines|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">Create</PrecompiledHeader>
+44
View File
@@ -119,6 +119,14 @@ public:
int ReadData( void *data, int length ) const;
void ReadNetadr( netadr_t *adr ) const;
void WriteVec3(const idVec3& vector);
void WriteMat3(const idMat3& axis);
void WriteBool(bool boolean);
idVec3 ReadVec3() const;
idMat3 ReadMat3() const;
bool ReadBool() const;
int ReadDeltaChar( int oldValue ) const;
int ReadDeltaByte( int oldValue ) const;
int ReadDeltaShort( int oldValue ) const;
@@ -427,6 +435,42 @@ ID_INLINE float idBitMsg::ReadDeltaFloat( float oldValue, int exponentBits, int
return idMath::BitsToFloat( newBits, exponentBits, mantissaBits );
}
ID_INLINE void idBitMsg::WriteVec3(const idVec3& vector) {
WriteFloat(vector[0]);
WriteFloat(vector[1]);
WriteFloat(vector[2]);
}
ID_INLINE void idBitMsg::WriteMat3(const idMat3& axis) {
WriteVec3(axis[0]);
WriteVec3(axis[1]);
WriteVec3(axis[2]);
}
ID_INLINE void idBitMsg::WriteBool(bool boolean) {
WriteBits(boolean, 1);
}
ID_INLINE idVec3 idBitMsg::ReadVec3() const {
idVec3 vector;
vector[0] = ReadFloat();
vector[1] = ReadFloat();
vector[2] = ReadFloat();
return vector;
}
ID_INLINE idMat3 idBitMsg::ReadMat3() const {
idMat3 axis;
axis[0] = ReadVec3();
axis[1] = ReadVec3();
axis[2] = ReadVec3();
return axis;
}
ID_INLINE bool idBitMsg::ReadBool() const {
int boolean = ReadBits(1);
return *(bool*)&boolean;//We seem to get a performance warning unless I do this. Ick!
}
/*
===============================================================================
+1 -1
View File
@@ -131,7 +131,7 @@ public:
void Swap( idList<type> &other ); // swap the contents of the lists
void DeleteContents( bool clear ); // delete the contents of the list
private:
protected:
int num;
int size;
int granularity;
+36
View File
@@ -213,6 +213,42 @@ idMat3 idVec3::ToMat3( void ) const {
return mat;
}
#ifdef PREY
// HUMANHEAD nla
/*
=============
idVec3::hhToMat3
=============
*/
idMat3 idVec3::hhToMat3(void) const {
idVec3 left;
idVec3 down;
// NormalVectors actually returns left and down
NormalVectors(left, down);
return idMat3(*this, left, -down);
}
// HUMANHEAD PDM: Vector conversion to/from axis aligned direction masks (6-bit vector compression)
int idVec3::DirectionMask() const {
int mask = 0;
for (int term = 0; term < 3; term++) {
mask += (*this)[term] < 0 ? 1 << (term << 1) : (*this)[term]>0 ? 1 << ((term << 1) + 1) : 0;
}
return mask;
}
idVec3::idVec3(int directionMask) {
int negativeMask, positiveMask;
for (int term = 0; term < 3; term++) {
negativeMask = 1 << (term << 1);
positiveMask = 1 << ((term << 1) + 1);
(*this)[term] = (directionMask & negativeMask) ? -1 : (directionMask & positiveMask) ? 1 : 0;
}
}
// HUMANHEAD END
#endif
/*
=============
idVec3::ToString
+30
View File
@@ -313,6 +313,18 @@ ID_INLINE float *idVec2::ToFloatPtr( void ) {
//
//===============================================================
#ifdef PREY
// HUMANHEAD pdm: support for 6 bit vector compression, direction masks
#define INDEX_IN_MASK(mask, index) ( ((mask) & (1<<(index)) ) != 0 )
#define MASK_NEGX 0x0001
#define MASK_POSX 0x0002
#define MASK_NEGY 0x0004
#define MASK_POSY 0x0008
#define MASK_NEGZ 0x0010
#define MASK_POSZ 0x0020
// HUMANHEAD END
#endif
class idVec3 {
public:
float x;
@@ -384,11 +396,29 @@ public:
void Lerp( const idVec3 &v1, const idVec3 &v2, const float l );
void SLerp( const idVec3 &v1, const idVec3 &v2, const float l );
idVec3 ToNormal() const;
#ifdef PREY
// HUMANHEAD nla - Returns a Mat3 with Z up instead of down
idMat3 hhToMat3(void) const; // vector should be normalized
int DirectionMask() const; // calculate direction bitmask
idVec3(int directionMask); // construct from direction bitmask
// HUMANHEAD END
#endif
};
extern idVec3 vec3_origin;
#define vec3_zero vec3_origin
ID_INLINE idVec3 idVec3::ToNormal() const {
float sqrLength, invLength;
sqrLength = x * x + y * y + z * z;
invLength = idMath::InvSqrt(sqrLength);
return *this * invLength;
}
ID_INLINE idVec3::idVec3( void ) {
}
+12 -1
View File
@@ -163,30 +163,41 @@ const int MAX_EXPRESSION_REGISTERS = 4096;
#include "../ui/UserInterface.h"
// collision detection system
#if defined(PREY)
#include "../prey/cm/CollisionModel.h"
#else
#include "../cm/CollisionModel.h"
#endif
// AAS files and manager
#include "../tools/compilers/aas/AASFile.h"
#include "../tools/compilers/aas/AASFileManager.h"
// game
#if defined(PREY)
#include "../prey/game/Game.h"
#else
#if defined(_D3XP)
#include "../d3xp/Game.h"
#else
#include "../game/Game.h"
#endif
#endif
//-----------------------------------------------------
#ifndef _D3SDK
#ifdef GAME_DLL
#if defined(PREY)
#include "../prey/game/Game_local.h"
#else
#if defined(_D3XP)
#include "../d3xp/Game_local.h"
#else
#include "../game/Game_local.h"
#endif
#endif
#else
+98
View File
@@ -5,6 +5,14 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|Win32">
<Configuration>Prey Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Prey Debug|x64">
<Configuration>Prey Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
@@ -22,69 +30,106 @@
<ClCompile Include="gl_d3d12arb.cpp" />
<ClCompile Include="gl_d3d12raylight.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Disabled</Optimization>
</ClCompile>
<ClCompile Include="gl_d3d12shim.cpp" />
<ClCompile Include="gl_d3d12tess.cpp" />
<ClCompile Include="gl_d3d12wgl.cpp" />
<ClCompile Include="tess\dict.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\geom.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\memalloc.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\mesh.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\normal.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\priorityq-heap.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\priorityq.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\render.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\sweep.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\tess.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\tessellate.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="tess\tessmono.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Speed</FavorSizeOrSpeed>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
</ItemGroup>
<ItemGroup>
@@ -127,6 +172,12 @@
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@@ -140,6 +191,12 @@
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@@ -155,12 +212,18 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
@@ -181,6 +244,22 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@@ -218,6 +297,25 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>streamline/include</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
+47
View File
@@ -0,0 +1,47 @@
#ifdef _WIN32
#define _BOOL
#include <maya/MStatus.h>
#include <maya/MString.h>
#include <maya/MFileIO.h>
#include <maya/MLibrary.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MEulerRotation.h>
#include <maya/MObject.h>
#include <maya/MArgList.h>
#include <maya/MGlobal.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MItDag.h>
#include <maya/MTime.h>
#include <maya/MAnimControl.h>
#include <maya/MFnGeometryFilter.h>
#include <maya/MFnSet.h>
#include <maya/MSelectionList.h>
#include <maya/MFloatArray.h>
#include <maya/MFnWeightGeometryFilter.h>
#include <maya/MFnSkinCluster.h>
#include <maya/MItDependencyNodes.h>
#include <maya/MFnMesh.h>
#include <maya/MDagPathArray.h>
#include <maya/MItGeometry.h>
#include <maya/MPlugArray.h>
#include <maya/MPlug.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnMatrixData.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MFnTransform.h>
#include <maya/MQuaternion.h>
#include <maya/MFnCamera.h>
#include <maya/MFloatMatrix.h>
#include <maya/MFnEnumAttribute.h>
#undef _BOOL
#endif // _WIN32
+47
View File
@@ -0,0 +1,47 @@
#ifdef _WIN32
#define _BOOL
#include <maya/MStatus.h>
#include <maya/MString.h>
#include <maya/MFileIO.h>
#include <maya/MLibrary.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MEulerRotation.h>
#include <maya/MObject.h>
#include <maya/MArgList.h>
#include <maya/MGlobal.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MItDag.h>
#include <maya/MTime.h>
#include <maya/MAnimControl.h>
#include <maya/MFnGeometryFilter.h>
#include <maya/MFnSet.h>
#include <maya/MSelectionList.h>
#include <maya/MFloatArray.h>
#include <maya/MFnWeightGeometryFilter.h>
#include <maya/MFnSkinCluster.h>
#include <maya/MItDependencyNodes.h>
#include <maya/MFnMesh.h>
#include <maya/MDagPathArray.h>
#include <maya/MItGeometry.h>
#include <maya/MPlugArray.h>
#include <maya/MPlug.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnMatrixData.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MFnTransform.h>
#include <maya/MQuaternion.h>
#include <maya/MFnCamera.h>
#include <maya/MFloatMatrix.h>
#include <maya/MFnEnumAttribute.h>
#undef _BOOL
#endif // _WIN32
+434
View File
@@ -0,0 +1,434 @@
#define MAYA_DEFAULT_CAMERA "camera1"
#define ANIM_TX BIT( 0 )
#define ANIM_TY BIT( 1 )
#define ANIM_TZ BIT( 2 )
#define ANIM_QX BIT( 3 )
#define ANIM_QY BIT( 4 )
#define ANIM_QZ BIT( 5 )
typedef enum {
WRITE_MESH,
WRITE_ANIM,
WRITE_CAMERA
} exportType_t;
typedef struct {
idCQuat q;
idVec3 t;
} jointFrame_t;
typedef struct {
idCQuat q;
idVec3 t;
float fov;
} cameraFrame_t;
/*
==============================================================================================
idTokenizer
==============================================================================================
*/
class idTokenizer {
private:
int currentToken;
idStrList tokens;
public:
idTokenizer() { Clear(); };
void Clear( void ) { currentToken = 0; tokens.Clear(); };
int SetTokens( const char *buffer );
const char *NextToken( const char *errorstring = NULL );
bool TokenAvailable( void ) { return currentToken < tokens.Num(); };
int Num( void ) { return tokens.Num(); };
void UnGetToken( void ) { if ( currentToken > 0 ) { currentToken--; } };
const char *GetToken( int index ) { if ( ( index >= 0 ) && ( index < tokens.Num() ) ) { return tokens[ index ]; } else { return NULL; } };
const char *CurrentToken( void ) { return GetToken( currentToken ); };
};
/*
==============================================================================================
idExportOptions
==============================================================================================
*/
class idNamePair {
public:
idStr from;
idStr to;
};
class idAnimGroup {
public:
idStr name;
idStrList joints;
};
class idExportOptions {
private:
idTokenizer tokens;
void Reset( const char *commandline );
public:
idStr commandLine;
idStr src;
idStr dest;
idStr game;
idStr prefix;
float scale;
exportType_t type;
bool ignoreMeshes;
bool clearOrigin;
bool clearOriginAxis;
bool ignoreScale;
int startframe;
int endframe;
int framerate;
float xyzPrecision;
float quatPrecision;
idStr align;
idList<idNamePair> renamejoints;
idList<idNamePair> remapjoints;
idStrList keepjoints;
idStrList skipmeshes;
idStrList keepmeshes;
idList<idAnimGroup *> exportgroups;
idList<idAnimGroup> groups;
float rotate;
float jointThreshold;
int cycleStart;
// HUMANHEAD pdm: Allow bounds expansion (shared animations calculate bounds based on a different mesh, so give some slop)
float boundsExpansion;
// HUMANHEAD END
idExportOptions( const char *commandline, const char *ospath );
bool jointInExportGroup( const char *jointname );
};
/*
==============================================================================
idExportJoint
==============================================================================
*/
class idExportJoint {
public:
idStr name;
idStr realname;
idStr longname;
int index;
int exportNum;
bool keep;
float scale;
float invscale;
MFnDagNode *dagnode;
idHierarchy<idExportJoint> mayaNode;
idHierarchy<idExportJoint> exportNode;
idVec3 t;
idMat3 wm;
idVec3 idt;
idMat3 idwm;
idVec3 bindpos;
idMat3 bindmat;
int animBits;
int firstComponent;
jointFrame_t baseFrame;
int depth;
idExportJoint();
idExportJoint &operator=( const idExportJoint &other );
};
/*
==============================================================================
misc structures
==============================================================================
*/
typedef struct {
idExportJoint *joint;
float jointWeight;
idVec3 offset;
} exportWeight_t;
typedef struct {
idVec3 pos;
idVec2 texCoords;
int startweight;
int numWeights;
} exportVertex_t;
typedef struct {
int indexes[ 3 ];
} exportTriangle_t;
typedef struct {
idVec2 uv[ 3 ];
} exportUV_t;
ID_INLINE int operator==( exportVertex_t a, exportVertex_t b ) {
if ( a.pos != b.pos ) {
return false;
}
if ( ( a.texCoords[ 0 ] != b.texCoords[ 0 ] ) || ( a.texCoords[ 1 ] != b.texCoords[ 1 ] ) ) {
return false;
}
if ( ( a.startweight != b.startweight ) || ( a.numWeights != b.numWeights ) ) {
return false;
}
return true;
}
/*
========================================================================
.MD3 triangle model file format
========================================================================
*/
#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
#define MD3_VERSION 15
// limits
#define MD3_MAX_LODS 4
#define MD3_MAX_TRIANGLES 8192 // per surface
#define MD3_MAX_VERTS 4096 // per surface
#define MD3_MAX_SHADERS 256 // per surface
#define MD3_MAX_FRAMES 1024 // per model
#define MD3_MAX_SURFACES 32 // per model
#define MD3_MAX_TAGS 16 // per frame
// vertex scales
#define MD3_XYZ_SCALE (1.0/64)
// surface geometry should not exceed these limits
#define SHADER_MAX_VERTEXES 1000
#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
// the maximum size of game reletive pathnames
#define MAX_Q3PATH 64
typedef struct md3Frame_s {
idVec3 bounds[2];
idVec3 localOrigin;
float radius;
char name[16];
} md3Frame_t;
typedef struct md3Tag_s {
char name[MAX_Q3PATH]; // tag name
idVec3 origin;
idVec3 axis[3];
} md3Tag_t;
/*
** md3Surface_t
**
** CHUNK SIZE
** header sizeof( md3Surface_t )
** shaders sizeof( md3Shader_t ) * numShaders
** triangles[0] sizeof( md3Triangle_t ) * numTriangles
** st sizeof( md3St_t ) * numVerts
** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
*/
typedef struct {
int ident; //
char name[MAX_Q3PATH]; // polyset name
int flags;
int numFrames; // all surfaces in a model should have the same
int numShaders; // all surfaces in a model should have the same
int numVerts;
int numTriangles;
int ofsTriangles;
int ofsShaders; // offset from start of md3Surface_t
int ofsSt; // texture coords are common for all frames
int ofsXyzNormals; // numVerts * numFrames
int ofsEnd; // next surface follows
} md3Surface_t;
typedef struct {
char name[MAX_Q3PATH];
int shaderIndex; // for in-game use
} md3Shader_t;
typedef struct {
int indexes[3];
} md3Triangle_t;
typedef struct {
float st[2];
} md3St_t;
typedef struct {
short xyz[3];
short normal;
} md3XyzNormal_t;
typedef struct {
int ident;
int version;
char name[MAX_Q3PATH]; // model name
int flags;
int numFrames;
int numTags;
int numSurfaces;
int numSkins;
int ofsFrames; // offset for first frame
int ofsTags; // numFrames * numTags
int ofsSurfaces; // first surface, others follow
int ofsEnd; // end of file
} md3Header_t;
/*
==============================================================================
idExportMesh
==============================================================================
*/
class idExportMesh {
public:
idStr name;
idStr shader;
bool keep;
idList<exportVertex_t> verts;
idList<exportTriangle_t> tris;
idList<exportWeight_t> weights;
idList<exportUV_t> uv;
idExportMesh() { keep = true; };
void ShareVerts( void );
void GetBounds( idBounds &bounds ) const;
void Merge( idExportMesh *mesh );
};
/*
==============================================================================
idExportModel
==============================================================================
*/
class idExportModel {
public:
idExportJoint *exportOrigin;
idList<idExportJoint> joints;
idHierarchy<idExportJoint> mayaHead;
idHierarchy<idExportJoint> exportHead;
idList<int> cameraCuts;
idList<cameraFrame_t> camera;
idList<idBounds> bounds;
idList<jointFrame_t> jointFrames;
idList<jointFrame_t *> frames;
int frameRate;
int numFrames;
int skipjoints;
int export_joints;
idList<idExportMesh *> meshes;
idExportModel();
~idExportModel();
idExportJoint *FindJointReal( const char *name );
idExportJoint *FindJoint( const char *name );
bool WriteMesh( const char *filename, idExportOptions &options );
bool WriteAnim( const char *filename, idExportOptions &options );
bool WriteCamera( const char *filename, idExportOptions &options );
};
/*
==============================================================================
Maya
==============================================================================
*/
class idMayaExport {
private:
idExportModel model;
idExportOptions &options;
void FreeDagNodes( void );
float TimeForFrame( int num ) const;
int GetMayaFrameNum( int num ) const;
void SetFrame( int num );
void GetBindPose( MObject &jointNode, idExportJoint *joint, float scale );
void GetLocalTransform( idExportJoint *joint, idVec3 &pos, idMat3 &mat );
void GetWorldTransform( idExportJoint *joint, idVec3 &pos, idMat3 &mat, float scale );
void CreateJoints( float scale );
void PruneJoints( idStrList &keepjoints, idStr &prefix );
void RenameJoints( idList<idNamePair> &renamejoints, idStr &prefix );
bool RemapParents( idList<idNamePair> &remapjoints );
MObject FindShader( MObject& setNode );
void GetTextureForMesh( idExportMesh *mesh, MFnDagNode &dagNode );
idExportMesh *CopyMesh( MFnSkinCluster &skinCluster, float scale );
void CreateMesh( float scale );
void CombineMeshes( void );
void GetAlignment( idStr &alignName, idMat3 &align, float rotate, int startframe );
const char *GetObjectType( MObject object );
float GetCameraFov( idExportJoint *joint );
void GetCameraFrame( idExportJoint *camera, idMat3 &align, cameraFrame_t *cam );
void CreateCameraAnim( idMat3 &align );
void GetDefaultPose( idMat3 &align );
void CreateAnimation( idMat3 &align );
public:
idMayaExport( idExportOptions &exportOptions ) : options( exportOptions ) { };
~idMayaExport();
void ConvertModel( void );
void ConvertToMD3( void );
};
+47
View File
@@ -0,0 +1,47 @@
#ifdef _WIN32
#define _BOOL
#include <maya/MStatus.h>
#include <maya/MString.h>
#include <maya/MFileIO.h>
#include <maya/MLibrary.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MEulerRotation.h>
#include <maya/MObject.h>
#include <maya/MArgList.h>
#include <maya/MGlobal.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MItDag.h>
#include <maya/MTime.h>
#include <maya/MAnimControl.h>
#include <maya\MFnGeometryFilter.h>
#include <maya\MFnSet.h>
#include <maya\MSelectionList.h>
#include <maya\MFloatArray.h>
#include <maya\MFnWeightGeometryFilter.h>
#include <maya\MFnSkinCluster.h>
#include <maya\MItDependencyNodes.h>
#include <maya\MFnMesh.h>
#include <maya\MDagPathArray.h>
#include <maya\MItGeometry.h>
#include <maya\MPlugArray.h>
#include <maya\MPlug.h>
#include <maya\MFloatPointArray.h>
#include <maya\MFnAttribute.h>
#include <maya\MFnMatrixData.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MFnTransform.h>
#include <maya/MQuaternion.h>
#include <maya/MFnCamera.h>
#include <maya/MFloatMatrix.h>
#include <maya/MFnEnumAttribute.h>
#undef _BOOL
#endif // _WIN32
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
#ifndef __MAYA_MAIN_H__
#define __MAYA_MAIN_H__
/*
==============================================================
Maya Import
==============================================================
*/
typedef bool ( *exporterDLLEntry_t )( int version, idCommon *common, idSys *sys );
typedef const char *( *exporterInterface_t )( const char *ospath, const char *commandline );
typedef void ( *exporterShutdown_t )( void );
#endif /* !__MAYA_MAIN_H__ */
+4
View File
@@ -0,0 +1,4 @@
EXPORTS
dllEntry
Maya_ConvertModel
Maya_Shutdown
+268
View File
@@ -0,0 +1,268 @@
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "prey_local.h"
/*
=================
hhNavigator::hhNavigator()
=================
*/
hhNavigator::hhNavigator(void) {
hhSelf = NULL;
// followStateFunction = FollowAllyStay;
} //. hhNavigator::hhNavigator(void)
/*
========================
hhNavigator::Spawn(void)
========================
*/
// Required for CLASS_DECLARATION
void hhNavigator::Spawn(void) {
} //. hhNavigator::hhNavigator(void)
/*
=======================================
hhNavigator::SetOwner(idAI *owner)
=======================================
*/
void hhNavigator::SetOwner(idAI *owner) {
idNavigator::SetOwner(owner);
if (owner->IsType(hhAI::Type)) {
hhSelf = static_cast<hhAI *>(owner);
}
} //. hhNavigator::SetOwner(idAI *)
/* JRM- Removed because brain stuff handles this logic now
//
//===============================
//hhNavigator::SetAlly(idActor *)
//===============================
//
void hhNavigator::SetAlly(idActor *ally) {
if (ally != NULL) {
FollowAlly(ally);
}
} //. hhNavigator::SetAlly(idActor *)
//
//=============================
//hhNavigator::FollowAlly(ally)
//=============================
//
void hhNavigator::FollowAlly(idActor *ally) {
// If we aren't on an hhAI, we can't follow, so leave
if (hhSelf == NULL) {
return;
}
(this->*followStateFunction)(ally);
} //. hhNavigator::FollowAlly(idActor *ally)
*/
/* HUMANHEAD JRM - REMOVED
//
//===================================
//hhNavigator::FollowAllyStay(void)
//===================================
//
void hhNavigator::FollowAllyStay(idActor *ally) {
static bool first = true;
if (first) {
if (ai_debug->integer > 0) {
gameLocal.Printf("in FollowAllyStay\n");
}
first = false;
}
if (hhSelf->AI_ALLY_FAR ||
!hhSelf->AI_ALLY_VISIBLE) {
followStateFunction = FollowAllyFollow;
first = true;
}
else if (hhSelf->AI_ALLY_TOUCHED) {
followStateFunction = FollowAllyLead;
first = true;
}
else { // Just stay still
moveType = MOVE_NONE;
}
} //. hhNavigator::FollowAllyStay(void)
//
//===================================
//hhNavigator::FollowAllyFollow(void)
//===================================
//
void hhNavigator::FollowAllyFollow(idActor *ally) {
static bool first = true;
hhSelf->AI_FOLLOW_ALLY = true;
if (first) {
if (ai_debug->integer > 0) {
gameLocal.Printf("in FollowAllyFollow\n");
}
first = false;
}
if (hhSelf->AI_ALLY_NEAR) {
StopMove();
followStateFunction = FollowAllyStay;
hhSelf->AI_FOLLOW_ALLY = false;
first = true;
}
// In case the min_dist is too close
else if (hhSelf->AI_ALLY_TOUCHED) {
followStateFunction = FollowAllyLead;
hhSelf->AI_FOLLOW_ALLY = false;
first = true;
}
else {
moveDest = ally->GetFloorPos();
goal = ally;
moveType = MOVE_TO_ALLY;
if (aas) {
toAreaNum = aas->PointReachableAreaNum( moveDest );
toAreaEnemy = false;
}
} //. Follow the player
} //. hhNavigator::FollowAllyFollow(void)
//
//===================================
//hhNavigator::FollowAllyLead(void)
//===================================
//
void hhNavigator::FollowAllyLead(idActor *ally) {
static bool first = true;
static int nextUpdateTime;
idVec3 leadPosition;
hhSelf->AI_LEAD_ALLY = true;
if (first) {
if (ai_debug->integer > 0) {
gameLocal.Printf("in FollowAllyLead\n");
}
first = false;
}
// Reset this variable, as it was used to get here.
if (hhSelf->AI_ALLY_TOUCHED) {
hhSelf->AI_ALLY_TOUCHED = false;
nextUpdateTime = 0;
}
if (gameLocal.time * 1000.0f >= nextUpdateTime) {
//if (nextUpdateTime == 0) {
leadPosition = FindNewLeadPosition(ally);
if (leadPosition != vec3_origin) {
moveDest = leadPosition;
moveType = MOVE_TO_ALLY;
goal = NULL;
if (aas) {
toAreaNum = aas->PointReachableAreaNum(moveDest);
toAreaEnemy = false;
}
nextUpdateTime = gameLocal.time * 1000.0f +
hhSelf->follow_lead_update_time;
}
} //. Time to update position
if (!hhSelf->AI_ALLY_NEAR) {
followStateFunction = FollowAllyStay;
hhSelf->AI_LEAD_ALLY = false;
first = true;
}
} //. hhNavigator::FollowAllyLead(void)
//
//================================
//hhNavigator::FindNewLeadPosition
//================================
//
idVec3 hhNavigator::FindNewLeadPosition(idActor *ally) {
idVec3 direction;
aasTrace_t trace;
direction = hhSelf->GetFloorPos() - ally->GetFloorPos();
direction.Normalize();
direction *= hhSelf->follow_min_dist;
if (aas) {
idVec3 bestPos;
bestPos = aas->FindNearestPoint(ally->GetFloorPos(),
hhSelf->GetFloorPos(),
hhSelf->follow_min_dist);
if (bestPos != vec3_origin) {
return(bestPos);
}
// Didn't find a good point
// Just move as far as we can in the direction nudged
aas->Trace(trace, hhSelf->GetPhysics()->GetOrigin(),
hhSelf->GetPhysics()->GetOrigin() + direction);
//? How does this work on slopes?
//! Do we want to use the floor position?
return(ally->GetFloorPos() + direction * trace.fraction);
}
return(ally->GetFloorPos() + direction);
} //. hhNavigator::FindNewLeadPosition(idActor *)
*/
+41
View File
@@ -0,0 +1,41 @@
#ifndef __PREY_AI_NAVIGATOR_H__
#define __PREY_AI_NAVIGATOR_H__
// Forward declaration for hhAI
class hhAI;
class hhNavigator : public idNavigator {
public:
hhNavigator(void);
void Spawn(void);
//virtual void SetAlly(idActor *ally); JRM removed
virtual void SetOwner(idAI *owner);
virtual boolean IsNearDest( void );
protected:
hhAI * hhSelf;
//virtual void FollowAlly(idActor *ally); JRM removed
/* JRM removed
void FollowAllyStay(idActor *ally);
void FollowAllyFollow(idActor *ally);
void FollowAllyLead(idActor *ally);
*/
// void (hhNavigator::* followStateFunction) (idActor *ally); JRM removed
//idVec3 FindNewLeadPosition(idActor *ally); JRM removed
};
#endif /* __PREY_AI_NAVIGATOR_H__ */
+529
View File
@@ -0,0 +1,529 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef AI_CenturionLaunch("centurionFire", "d"); //called from anims to handle firing for centurion
const idEventDef AI_CenturionRoar("centurionRoar"); //called from level-script to cause centurion to roar
const idEventDef AI_CenturionArmChop("centurionArmChop"); //called from level-script to actually cause centurion to loose arm
const idEventDef AI_CenturionLooseArm("centurionLooseArm"); //internal: used to actually 'loose' arm
const idEventDef AI_CenturionForceFieldNotify("preForcefieldNotify");
const idEventDef AI_CenturionForceFieldToggle("forcefieldToggle", "d");
const idEventDef AI_CenturionInTunnel("playerInBox", "dE");
const idEventDef AI_CenturionReachedTunnel("reachedTunnel");
const idEventDef AI_CenturionMoveToTunnel("moveToTunnel", NULL, 'd');
const idEventDef AI_CheckForObstructions("checkForObstructions", "d", 'd');
const idEventDef AI_DestroyObstruction("destroyObstruction");
const idEventDef AI_MoveToObstruction("moveToObstruction");
const idEventDef AI_ReachedObstruction("reachedObstruction");
const idEventDef AI_CloseToObstruction("closeToObstruction", 0, 'd');
const idEventDef AI_BackhandImpulse("<backhandImpulse>", "e");
const idEventDef AI_EnemyCloseToObstruction("enemyCloseToObstruction", NULL, 'd');
const idEventDef AI_TakeDamage("takeDamage", "d");
const idEventDef AI_FindNearbyEnemy("findNearbyEnemy", "f", 'e');
CLASS_DECLARATION( hhMonsterAI, hhCenturion )
EVENT( AI_CenturionLaunch, hhCenturion::Event_CenturionLaunch )
EVENT( AI_CenturionRoar, hhCenturion::Event_ScriptedRoar )
EVENT( AI_CenturionArmChop, hhCenturion::Event_ScriptedArmChop )
EVENT( AI_CenturionLooseArm, hhCenturion::Event_CenturionLooseArm )
EVENT( AI_CenturionInTunnel, hhCenturion::Event_PlayerInTunnel )
EVENT( AI_CenturionReachedTunnel, hhCenturion::Event_ReachedTunnel )
EVENT( AI_CenturionMoveToTunnel, hhCenturion::Event_MoveToTunnel )
EVENT( AI_CenturionForceFieldNotify, hhCenturion::Event_ForceFieldNotify )
EVENT( AI_CenturionForceFieldToggle, hhCenturion::Event_ForceFieldToggle )
EVENT( AI_CheckForObstructions, hhCenturion::Event_CheckForObstruction )
EVENT( AI_MoveToObstruction, hhCenturion::Event_MoveToObstruction )
EVENT( AI_DestroyObstruction, hhCenturion::Event_DestroyObstruction )
EVENT( AI_ReachedObstruction, hhCenturion::Event_ReachedObstruction )
EVENT( AI_CloseToObstruction, hhCenturion::Event_CloseToObstruction )
EVENT( AI_BackhandImpulse, hhCenturion::Event_BackhandImpulse )
EVENT( AI_EnemyCloseToObstruction, hhCenturion::Event_EnemyCloseToObstruction )
EVENT( AI_TakeDamage, hhCenturion::Event_TakeDamage )
EVENT( AI_FindNearbyEnemy, hhCenturion::Event_FindNearbyEnemy )
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void hhCenturion::Spawn() {
AI_CENTURION_ARM_MISSING = false;
AI_CENTURION_REQUIRE_ROAR = false;
AI_CENTURION_ARM_TUNNEL = false;
AI_CENTURION_SCRIPTED_ROAR = 0;
AI_CENTURION_FORCEFIELD_WAIT = false;
AI_CENTURION_SCRIPTED_TUNNEL = 0;
}
void hhCenturion::Event_PostSpawn( void ) {
hhMonsterAI::Event_PostSpawn();
const idKeyValue *kv = spawnArgs.MatchPrefix( "aasObstacle" );
idEntityPtr<idEntity> ent;
while ( kv ) {
ent = gameLocal.FindEntity( kv->GetValue() );
if ( ent.IsValid() ) {
obstacles.AddUnique( ent );
}
kv = spawnArgs.MatchPrefix( "aasObstacle", kv );
}
}
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
void hhCenturion::LinkScriptVariables( void ) {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable(AI_CENTURION_ARM_MISSING);
LinkScriptVariable(AI_CENTURION_REQUIRE_ROAR);
LinkScriptVariable(AI_CENTURION_ARM_TUNNEL);
LinkScriptVariable(AI_CENTURION_SCRIPTED_ROAR);
LinkScriptVariable(AI_CENTURION_SCRIPTED_TUNNEL);
LinkScriptVariable(AI_CENTURION_FORCEFIELD_WAIT);
}
void hhCenturion::Event_ForceFieldNotify() {
if( !armchop_Target.GetEntity() ) {
return; //must not be in arm-chop mode, so we don't care yet
}
AI_CENTURION_REQUIRE_ROAR = true;
AI_CENTURION_FORCEFIELD_WAIT = true;
}
void hhCenturion::Event_ForceFieldToggle( int toggle ) {
if( !armchop_Target.GetEntity() ) {
return;
}
AI_CENTURION_FORCEFIELD_WAIT = false;
if (!toggle) {
AI_CENTURION_REQUIRE_ROAR = false;
} else if( AI_CENTURION_ARM_TUNNEL ) {
Event_ScriptedArmChop();
return;
}
}
void hhCenturion::Event_PlayerInTunnel( int toggle, idEntity* ent ) {
if( AI_CENTURION_ARM_MISSING ) { //don't care if the player goes back in tunnel once we already lost our arm
return;
}
if( toggle ) {
if( !ent ) {
gameLocal.DWarning( "entity needs to be present for tunnel event" );
return;
}
armchop_Target = ent;
AI_CENTURION_SCRIPTED_TUNNEL = 1;
}
else {
armchop_Target = NULL;
AI_CENTURION_SCRIPTED_TUNNEL = 0;
}
}
void hhCenturion::Event_MoveToTunnel() {
if (!armchop_Target.IsValid()) {
idThread::ReturnInt(0);
return;
}
StopMove(MOVE_STATUS_DONE);
MoveToPosition(armchop_Target->GetOrigin());
idThread::ReturnInt(1);
}
void hhCenturion::Event_ReachedTunnel() {
if( armchop_Target.IsValid() ) {
idAngles faceAngles = armchop_Target->GetAxis()[0].ToAngles();
ideal_yaw = faceAngles.yaw;
current_yaw = faceAngles.yaw;
SetAxis( armchop_Target->GetAxis() );
}
}
void hhCenturion::Event_ScriptedRoar() {
if ( AI_CENTURION_SCRIPTED_ROAR > 0 ) {
gameLocal.Warning( "centurionRoar() called more than once!\n");
} else {
AI_CENTURION_SCRIPTED_ROAR = 1;
}
}
void hhCenturion::Event_ScriptedArmChop() {
const function_t* newstate = NULL;
newstate = GetScriptFunction( "state_ScriptedArmChop" );
if( newstate ) {
SetState( newstate );
}
else {
gameLocal.Warning( "Unable to find 'state_ScriptedArmChop' on centurion" );
}
}
void hhCenturion::Event_CenturionLooseArm() {
idDict args;
idEntity* ent = NULL;
idVec3 jointLoc;
idMat3 jointAxis;
animator.GetJointTransform( spawnArgs.GetString("arm_severjoint", ""), gameLocal.time, jointLoc, jointAxis );
jointLoc = renderEntity.origin + jointLoc * renderEntity.axis;
args.SetVector( "origin", jointLoc );
args.SetMatrix( "rotation", renderEntity.axis );
args.SetBool( "spin", 0 );
args.SetFloat( "triggersize", 48.f );
args.SetBool( "enablePickup", true );
args.SetFloat( "respawn", 0.f );
ent = gameLocal.SpawnObject( spawnArgs.GetString("def_arm_weaponclass", ""), &args );
SetSkinByName( spawnArgs.GetString( "skin_arm_gone" ) );
hhFxInfo fx;
fx.SetEntity( this );
fx.RemoveWhenDone( true );
SpawnFxLocal( spawnArgs.GetString( "fx_armchop" ), jointLoc, mat3_identity, &fx );
//drop any stuck arrows
idEntity *next;
for( ent = teamChain; ent != NULL; ent = next ) {
next = ent->GetTeamChain();
if ( ent && ent->IsType( hhProjectile::Type ) ) {
ent->Unbind();
ent->Hide();
ent->PostEventSec( &EV_Remove, 5 );
next = teamChain;
}
}
AI_CENTURION_ARM_MISSING = true;
}
void hhCenturion::Event_CenturionLaunch( const idList<idStr>* parmList ) {
const idDict* projDef = NULL;
const idSoundShader* soundShader = NULL;
// parms: joint, projectileDef, sound, fx
if( !parmList || parmList->Num() != 5 ) {
gameLocal.Warning( "Incorrect paramater number" );
return;
}
//Rbarrel_A projectile_centurion_autocannon snd_fire fx_muzzleFlash
const char* jointName = (*parmList)[ 0 ].c_str();
const char* projectileDefName = (*parmList)[ 1 ].c_str();
const char* soundName = (*parmList)[ 2 ].c_str();
const char* fxName = (*parmList)[ 3 ].c_str();
int autoAim = atoi( (*parmList)[ 4 ].c_str() );
if( AI_CENTURION_ARM_MISSING ) { //skip firing if joint is on the severed arm
if( !idStr::Icmp(jointName, spawnArgs.GetString("severed_jointA", "")) || !idStr::Icmp(jointName, spawnArgs.GetString("severed_jointB", "")) ) {
return;
}
}
projDef = gameLocal.FindEntityDefDict( projectileDefName, false );
HH_ASSERT( !shootTarget.IsValid() );
// If autoAim is true and we're not blending, and we're facing the enemy, auto-aim
if ( ( autoAim == 1 || ( autoAim == 2 && gameLocal.random.RandomInt(100) < 50 ) ) && torsoAnim.animBlendFrames == 0 && FacingEnemy( 5.0f ) ) {
AimedAttackMissile( jointName, projDef );
} else { // Otherwise do a normal missile attack
Event_AttackMissile( jointName, projDef, 1 );
}
if(idStr::Cmpn( soundName, "snd_", 4)) {
soundShader = declManager->FindSound( soundName );
if( soundShader->GetState() == DS_DEFAULTED ) {
gameLocal.Warning( "Sound '%s' not found", soundName );
}
StartSoundShader( soundShader, SND_CHANNEL_WEAPON, 0, false, NULL );
}
else {
if( !StartSound(soundName, SND_CHANNEL_WEAPON, 0, false, NULL) ) {
gameLocal.Warning( "Framecommand 'centurionFire' on entity '%s' could not find sound '%s'", GetName(), soundName );
}
}
BroadcastFxInfoAlongBone( spawnArgs.GetString(fxName), jointName );
}
void hhCenturion::Event_DestroyObstruction() {
if( pillarEntity.IsValid() ) {
pillarEntity->PostEventMS( &EV_Activate, 0.f, this );
}
}
void hhCenturion::Event_CheckForObstruction( int checkPathToPillar ) {
bool obstacle = false;
predictedPath_t path;
if( enemy.IsValid() ) {
idVec3 end = enemy->GetPhysics()->GetOrigin();
if ( !checkPathToPillar ) {
trace_t tr;
idVec3 toPos, eye = GetEyePosition();
if ( enemy->IsType( idActor::Type ) ) {
toPos = ( ( idActor * )enemy.GetEntity() )->GetEyePosition();
} else {
toPos = enemy->GetPhysics()->GetOrigin();
}
gameLocal.clip.TracePoint( tr, eye, toPos, MASK_SHOT_BOUNDINGBOX, this );
idEntity *traceEnt = gameLocal.GetTraceEntity( tr );
if ( traceEnt && ( tr.fraction < 1.0f || traceEnt != enemy.GetEntity() ) ) {
//check to see if the other object is an pillar...
if( traceEnt->spawnArgs.GetInt("centurion_pillar", "0") == 1 ) {
pillarEntity = traceEnt;
obstacle = true;
}
}
} else if ( pillarEntity.IsValid() ) {
idAI::PredictPath( this, this->aas, physicsObj.GetOrigin(), enemy->GetPhysics()->GetOrigin() - physicsObj.GetOrigin(), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : (SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
if( path.endEvent != 0 && path.blockingEntity ) {
//check to see if the other object is an pillar...
if( path.blockingEntity->spawnArgs.GetInt("centurion_pillar", "0") == 1 ) {
//check to see if we can path to the obstacle clearly
pillarEntity = path.blockingEntity;
//idAI::PredictPath( this, this->aas, physicsObj.GetOrigin(), pillarEntity->GetPhysics()->GetOrigin() - physicsObj.GetOrigin(), 1000, 1000, (SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA), path );
//if( path.endEvent != 0 && path.blockingEntity == pillarEntity.GetEntity() ) {
obstacle = true;
//}
}
}
}
}
idThread::ReturnInt( (int)obstacle );
}
void hhCenturion::Event_CloseToObstruction() {
if( physicsObj.GetAbsBounds().IntersectsBounds(pillarEntity->GetPhysics()->GetAbsBounds()) ) {
idThread::ReturnInt( 1 );
return;
}
idThread::ReturnInt( 0 );
}
void hhCenturion::Event_ReachedObstruction() {
FaceEntity( pillarEntity.GetEntity() );
}
void hhCenturion::Event_MoveToObstruction() {
idVec3 temp;
if ( aas ) {
int toAreaNum = PointReachableAreaNum( pillarEntity.GetEntity()->GetOrigin() );
temp = pillarEntity.GetEntity()->GetOrigin();
aas->PushPointIntoAreaNum( toAreaNum, temp );
MoveToPosition( temp );
} else {
gameLocal.Warning( "Centurion has no aas for MoveToObstruction\n" );
}
}
void hhCenturion::Think() {
PROFILE_SCOPE("AI", PROFMASK_NORMAL|PROFMASK_AI);
if (ai_skipThink.GetBool()) {
return;
}
hhMonsterAI::Think();
if(ai_debugBrain.GetInteger() > 0 && state) {
if ( enemy.IsValid() && enemy->GetHealth() > 0 ) {
float dist = ( GetPhysics()->GetOrigin() - enemy->GetPhysics()->GetOrigin() ).LengthFast();
gameRenderWorld->DrawText( va("%f", dist), this->GetEyePosition() + idVec3(0.0f, 0.0f, 40.0f), 0.75f, colorYellow, gameLocal.GetLocalPlayer()->viewAngles.ToMat3());
}
gameRenderWorld->DrawText(state->Name(), this->GetEyePosition() + idVec3(0.0f, 0.0f, 40.0f), 0.75f, colorYellow, gameLocal.GetLocalPlayer()->viewAngles.ToMat3());
gameRenderWorld->DrawText(torsoAnim.state, this->GetEyePosition() + idVec3(0.0f, 0.0f, 20.0f), 0.75f, colorYellow, gameLocal.GetLocalPlayer()->viewAngles.ToMat3());
gameRenderWorld->DrawText(legsAnim.state, this->GetEyePosition() + idVec3(0.0f, 0.0f, 0.0f), 0.75f, colorYellow, gameLocal.GetLocalPlayer()->viewAngles.ToMat3());
}
}
bool hhCenturion::AttackMelee( const char *meleeDefName ) {
const idDict *meleeDef;
idActor *enemyEnt = enemy.GetEntity();
const char *p;
const idSoundShader *shader;
meleeDef = gameLocal.FindEntityDefDict( meleeDefName, false );
if ( !meleeDef ) {
gameLocal.Error( "Unknown melee '%s'", meleeDefName );
}
if ( !enemyEnt ) {
p = meleeDef->GetString( "snd_miss" );
if ( p && *p ) {
shader = declManager->FindSound( p );
StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
}
return false;
}
// make sure the trace can actually hit the enemy
if ( !TestMelee() ) {
// missed
p = meleeDef->GetString( "snd_miss" );
if ( p && *p ) {
shader = declManager->FindSound( p );
StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
}
return false;
}
//
// do the damage
//
p = meleeDef->GetString( "snd_hit" );
if ( p && *p ) {
shader = declManager->FindSound( p );
StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
}
idVec3 kickDir;
meleeDef->GetVector( "kickDir", "0 0 0", kickDir );
idVec3 globalKickDir;
globalKickDir = ( viewAxis * physicsObj.GetGravityAxis() ) * kickDir;
enemyEnt->Damage( this, this, globalKickDir, meleeDefName, 1.0f, INVALID_JOINT );
if ( enemyEnt->IsActiveAF() && !enemyEnt->IsType( idPlayer::Type ) ) {
PostEventMS( &AI_BackhandImpulse, 0, enemyEnt );
}
lastAttackTime = gameLocal.time;
return true;
}
void hhCenturion::Event_BackhandImpulse( idEntity* ent ) {
const idDict *meleeDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_impulse_damage"), false );
if ( !meleeDef || !ent ) {
return;
}
idVec3 kickDir;
meleeDef->GetVector( "kickDir", "0 0 0", kickDir );
idVec3 globalKickDir = ( viewAxis * physicsObj.GetGravityAxis() ) * kickDir;
globalKickDir *= ent->spawnArgs.GetFloat( "kick_scale", "1.0" );
ent->ApplyImpulse( this, 0, ent->GetOrigin(), meleeDef->GetFloat( "push_ragdoll" ) * globalKickDir );
}
/*
=====================
hhCenturion::Save
=====================
*/
void hhCenturion::Save( idSaveGame *savefile ) const {
armchop_Target.Save( savefile );
pillarEntity.Save( savefile );
}
/*
=====================
hhCenturion::Restore
=====================
*/
void hhCenturion::Restore( idRestoreGame *savefile ) {
armchop_Target.Restore( savefile );
pillarEntity.Restore( savefile );
// Restore the obstacle list
const idKeyValue *kv = spawnArgs.MatchPrefix( "aasObstacle" );
idEntityPtr<idEntity> ent;
while ( kv ) {
ent = gameLocal.FindEntity( kv->GetValue() );
if ( ent.IsValid() ) {
obstacles.AddUnique( ent );
}
kv = spawnArgs.MatchPrefix( "aasObstacle", kv );
}
}
void hhCenturion::Event_EnemyCloseToObstruction(void) {
bool close = false;
if ( pillarEntity.IsValid() && enemy.IsValid() ) {
float obs_dist = ( pillarEntity->GetOrigin() - GetOrigin() ).Length();
float dist = ( enemy->GetOrigin() - GetOrigin() ).Length();
// If the enemy is further from me than the pillar...
if ( dist > obs_dist) {
dist = ( pillarEntity->GetOrigin() - enemy->GetOrigin() ).Length();
// If the enemy is less than 400 units from the pillar, then he's 'close'
if ( dist < 400.0f ) {
close = true;
}
}
}
idThread::ReturnInt( (int) close );
}
void hhCenturion::AimedAttackMissile( const char *jointname, const idDict *projDef) {
idProjectile *proj;
idVec3 target, origin = GetOrigin();
bool inShuttle = false;
if ( shootTarget.IsValid() ) {
target = shootTarget->GetOrigin();
} else if ( enemy.IsValid() ) {
target = enemy->GetOrigin();
if ( enemy->IsType( idActor::Type ) ) {
target.z += enemy->EyeHeight() / 4.0f;
}
} else {
// No target? Do the default attack
Event_AttackMissile( jointname, projDef, 1 );
return;
}
// If target is too close do a non-aimed attack
if ( fabsf( origin.x - target.x ) < 256 &&
fabsf( origin.y - target.y ) < 256 ) {
Event_AttackMissile( jointname, projDef, 1 );
return;
}
idVec3 dist = origin - target;
if ( shootTarget.IsValid() ) {
proj = LaunchProjectile( jointname, shootTarget.GetEntity(), true, projDef );
} else {
proj = LaunchProjectile( jointname, enemy.GetEntity(), true, projDef );
}
}
void hhCenturion::Event_TakeDamage(int takeDamage) {
// Set the takedamage flag
fl.takedamage = (takeDamage != 0);
}
void hhCenturion::Event_FindNearbyEnemy( float distance ) {
// Search for the monster nearest to us
idAI *nearest = NULL;
float dist, nearDist = idMath::INFINITY;
idAI *ai = reinterpret_cast<idAI *> (gameLocal.FindEntityOfType( idAI::Type, NULL ));
while (ai) {
if (ai != this) { // Don't target yourself
dist = (ai->GetOrigin() - GetOrigin()).Length();
if (dist < nearDist) {
nearDist = dist;
nearest = ai;
}
}
ai = reinterpret_cast<idAI *> (gameLocal.FindEntityOfType( idAI::Type, ai ));
}
// If we found one near us and it's near enough, return it
if (nearest && nearDist < distance) {
idThread::ReturnEntity(nearest);
} else {
idThread::ReturnEntity(NULL);
}
}
void hhCenturion::Event_Touch( idEntity *other, trace_t *trace ) {
if ( (!enemy.GetEntity() || other->IsType( hhPlayer::Type )) && !other->fl.notarget && ( ReactionTo( other ) & ATTACK_ON_ACTIVATE ) ) {
Activate( other );
SetEnemy( static_cast<idActor *> ( other ) );
}
AI_PUSHED = true;
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+84
View File
@@ -0,0 +1,84 @@
#ifndef __PREY_AI_CENTURION_H__
#define __PREY_AI_CENTURION_H__
/***********************************************************************
hhCenturion.
Centurion AI.
***********************************************************************/
class hhCenturion : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhCenturion);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_CenturionLaunch( const idList<idStr>* parmList ) {};
void Event_ScriptedRoar() {};
void Event_ScriptedArmChop() {};
void Event_CenturionLooseArm() {};
void Event_ForceFieldNotify() {};
void Event_ForceFieldToggle( int toggle ) {};
void Event_PlayerInTunnel( int toggle, idEntity* ent ) {};
void Event_ReachedTunnel() {};
void Event_MoveToTunnel() {};
bool AttackMelee( const char *meleeDefName ) { return true; };
void Event_CheckForObstruction( int checkPathToPillar ) {};
void Event_MoveToObstruction() {};
void Event_DestroyObstruction() {};
void Event_ReachedObstruction() {};
void Event_CloseToObstruction() {};
void Event_EnemyCloseToObstruction() {};
void Event_BackhandImpulse( idEntity* ent ) {};
virtual void Event_PostSpawn( void ) {};
void Event_TakeDamage( int takeDamage ) {};
void Event_FindNearbyEnemy( float distance ) {};
virtual void Event_Touch( idEntity *other, trace_t *trace ) {};
#else
public:
void Spawn();
void Think();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
protected:
void Event_CenturionLaunch( const idList<idStr>* parmList );
void Event_ScriptedRoar();
void Event_ScriptedArmChop();
void Event_CenturionLooseArm();
void Event_ForceFieldNotify();
void Event_ForceFieldToggle( int toggle );
void Event_PlayerInTunnel( int toggle, idEntity* ent );
void Event_ReachedTunnel();
void Event_MoveToTunnel();
void LinkScriptVariables( void );
bool AttackMelee( const char *meleeDefName );
void Event_CheckForObstruction( int checkPathToPillar );
void Event_MoveToObstruction();
void Event_DestroyObstruction();
void Event_ReachedObstruction();
void Event_CloseToObstruction();
void Event_EnemyCloseToObstruction();
void Event_BackhandImpulse( idEntity* ent );
virtual void Event_PostSpawn( void );
void Event_TakeDamage( int takeDamage );
void Event_FindNearbyEnemy( float distance );
virtual void Event_Touch( idEntity *other, trace_t *trace );
void AimedAttackMissile( const char *jointname, const idDict *projDef );
idEntityPtr<idEntity> armchop_Target;
idEntityPtr<idEntity> pillarEntity;
idScriptBool AI_CENTURION_ARM_MISSING;
idScriptBool AI_CENTURION_REQUIRE_ROAR;
idScriptBool AI_CENTURION_ARM_TUNNEL;
idScriptBool AI_CENTURION_FORCEFIELD_WAIT;
idScriptFloat AI_CENTURION_SCRIPTED_ROAR;
idScriptFloat AI_CENTURION_SCRIPTED_TUNNEL;
idList< idEntityPtr<idEntity> > obstacles;
#endif
};
#endif //__PREY_AI_CENTURION_H__
+115
View File
@@ -0,0 +1,115 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
CLASS_DECLARATION( hhMonsterAI, hhCrawler )
EVENT( EV_Touch, hhCrawler::Event_Touch )
END_CLASS
void hhCrawler::Spawn() {
if( spawnArgs.FindKey("def_pickup") ) {
if ( gameLocal.isMultiplayer ) {
GetPhysics()->SetContents( CONTENTS_TRIGGER | CONTENTS_MONSTERCLIP );
} else {
GetPhysics()->SetContents( CONTENTS_TRIGGER );
}
}
}
void hhCrawler::Event_Touch( idEntity *other, trace_t *trace ) {
hhPlayer *player;
if( !spawnArgs.FindKey("def_pickup") || !other->IsType(idPlayer::Type) ) {
return;
}
player = static_cast<hhPlayer *>(other);
Pickup( player );
}
void hhCrawler::Pickup( hhPlayer *player ) {
if( !GiveToPlayer( player ) ) {
return;
}
// play pickup sound
StartSoundShader( refSound.shader, SND_CHANNEL_ITEM, false ); // play what's defined in the entity
// trigger our targets
ActivateTargets( player );
// clear our contents so the object isn't picked up twice
GetPhysics()->SetContents( 0 );
// hide the model
Hide();
if (player->hud) {
player->hud->SetStateInt("item", 1);
player->hud->SetStateString("itemtext", spawnArgs.GetString("inv_name"));
player->hud->SetStateString("itemicon", spawnArgs.GetString("inv_icon"));
}
idStr str;
spawnArgs.GetString("inv_name", "Item", str);
if (player == gameLocal.GetClientByNum(gameLocal.localClientNum)) {
gameLocal.Printf("Picked up a %s\n", str.c_str());
}
PostEventMS( &EV_Remove, 2000 );
}
bool hhCrawler::GiveToPlayer( hhPlayer* player ) {
const char *pickupName = spawnArgs.GetString("def_pickup", NULL);
bool pickedUp = false;
if ( player && pickupName ) {
idEntity *ent = gameLocal.SpawnObject(pickupName, NULL);
if (ent->IsType(hhItem::Type)) {
pickedUp = player->GiveItem( static_cast<hhItem*>(ent) );
}
ent->Hide();
ent->PostEventMS(&EV_Remove, 2000);
}
return pickedUp;
}
void hhCrawler::Think( void ) {
PROFILE_SCOPE("AI", PROFMASK_NORMAL|PROFMASK_AI);
if (ai_skipThink.GetBool()) { //HUMANHEAD rww
return;
}
if ( thinkFlags & TH_THINK ) {
current_yaw += deltaViewAngles.yaw;
ideal_yaw = idMath::AngleNormalize180( ideal_yaw + deltaViewAngles.yaw );
deltaViewAngles.Zero();
viewAxis = idAngles( 0, current_yaw, 0 ).ToMat3();
// HUMANHEAD NLA
physicsObj.ResetNumTouchEnt(0);
// HUMANHEAD END
// animation based movement
UpdateAIScript();
AnimMove();
} else if ( thinkFlags & TH_PHYSICS ) {
RunPhysics();
}
UpdateAnimation();
Present();
LinkCombat();
}
bool hhCrawler::UpdateAnimationControllers() {
//do nothing
return false;
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef __PREY_AI_CRAWLER_H__
#define __PREY_AI_CRAWLER_H__
/***********************************************************************
hhCrawler.
Crawler AI.
***********************************************************************/
class hhCrawler : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhCrawler);
public:
void Spawn();
protected:
void Event_Touch( idEntity *other, trace_t *trace );
void Pickup( hhPlayer *player );
bool GiveToPlayer( hhPlayer* player );
void Think();
bool UpdateAnimationControllers();
};
#endif //__PREY_AI_CRAWLER_H__
File diff suppressed because it is too large Load Diff
+139
View File
@@ -0,0 +1,139 @@
#ifndef __PREY_AI_CREATURE_H__
#define __PREY_AI_CREATURE_H__
class hhCreatureX : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhCreatureX);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_GunRecharge( int onOff ) {};
void Event_LaserOn() {};
void Event_LaserOff() {};
void Event_UpdateLasers() {};
void Event_SetGunOffset( const idAngles &ang ) {};
void Event_EndLeftBeams() {};
void Event_EndRightBeams() {};
void Event_AssignRightMuzzleFx( hhEntityFx* fx ) {};
void Event_AssignLeftMuzzleFx( hhEntityFx* fx ) {};
void Event_AssignRightImpactFx( hhEntityFx* fx ) {};
void Event_AssignLeftImpactFx( hhEntityFx* fx ) {};
void Event_AssignLeftRechargeFx( hhEntityFx* fx ) {};
void Event_AssignRightRechargeFx( hhEntityFx* fx ) {};
void Event_AttackMissile( const char *jointname, const idDict *projDef, int boneDir ) {};
void Event_HudEvent( const char *eventName ) {};
void Event_RechargeHealth() {};
void Event_EndRecharge() {};
void Event_ResetRechargeBeam() {};
void Event_SparkLeft() {};
void Event_SparkRight() {};
void Event_LeftGunDeath() {};
void Event_RightGunDeath() {};
void Event_StartRechargeBeams() {};
#else
~hhCreatureX();
void Spawn();
void LinkScriptVariables( void );
void Think();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
idScriptBool AI_GUN_TRACKING;
idScriptBool AI_RECHARGING;
idScriptBool AI_LEFT_FIRE;
idScriptBool AI_RIGHT_FIRE;
idScriptBool AI_LEFT_DAMAGED;
idScriptBool AI_RIGHT_DAMAGED;
idScriptBool AI_FIRING_LASER;
idScriptBool AI_HEALTH_TICK;
idScriptBool AI_GUN_EXPLODE;
protected:
void Event_GunRecharge( int onOff );
void Event_LaserOn();
void Event_LaserOff();
void Event_UpdateLasers();
void Event_SetGunOffset( const idAngles &ang );
void Event_EndLeftBeams();
void Event_EndRightBeams();
void Event_AssignRightMuzzleFx( hhEntityFx* fx );
void Event_AssignLeftMuzzleFx( hhEntityFx* fx );
void Event_AssignRightImpactFx( hhEntityFx* fx );
void Event_AssignLeftImpactFx( hhEntityFx* fx );
void Event_AssignLeftRechargeFx( hhEntityFx* fx );
void Event_AssignRightRechargeFx( hhEntityFx* fx );
void Event_AttackMissile( const char *jointname, const idDict *projDef, int boneDir );
void Event_HudEvent( const char *eventName );
void Event_RechargeHealth();
void Event_EndRecharge();
void Event_ResetRechargeBeam();
void Event_SparkLeft();
void Event_SparkRight();
void Event_LeftGunDeath();
void Event_RightGunDeath();
void Event_StartRechargeBeams();
void MuzzleLeftOn();
void MuzzleRightOn();
void MuzzleLeftOff();
void MuzzleRightOff();
bool UpdateAnimationControllers( void );
virtual void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
void Show();
void Activate( idEntity *activator );
idEntityPtr<hhBeamSystem> laserRight;
idEntityPtr<hhBeamSystem> laserLeft;
idEntityPtr<hhBeamSystem> preLaserRight;
idEntityPtr<hhBeamSystem> preLaserLeft;
idList< idEntityPtr<hhBeamSystem> > leftBeamList;
idList< idEntityPtr<hhBeamSystem> > rightBeamList;
idEntityPtr<hhBeamSystem> leftRechargeBeam;
idEntityPtr<hhBeamSystem> rightRechargeBeam;
idEntityPtr<hhBeamSystem> leftDamageBeam;
idEntityPtr<hhBeamSystem> rightDamageBeam;
idEntityPtr<hhBeamSystem> leftRetractBeam;
idEntityPtr<hhBeamSystem> rightRetractBeam;
idEntityPtr<hhEntityFx> muzzleLeftFx;
idEntityPtr<hhEntityFx> muzzleRightFx;
idEntityPtr<hhEntityFx> impactLeftFx;
idEntityPtr<hhEntityFx> impactRightFx;
idEntityPtr<hhEntityFx> rechargeLeftFx;
idEntityPtr<hhEntityFx> rechargeRightFx;
idEntityPtr<hhEntityFx> retractLeftFx;
idEntityPtr<hhEntityFx> retractRightFx;
int numBurstBeams;
bool bLaserLeftActive;
bool bLaserRightActive;
idVec3 targetStart_L;
idVec3 targetEnd_L;
idVec3 targetCurrent_L;
idVec3 targetStart_R;
idVec3 targetEnd_R;
idVec3 targetCurrent_R;
float targetAlpha_L;
float targetAlpha_R;
int leftGunHealth;
int rightGunHealth;
int leftGunLives;
int rightGunLives;
idAngles gunShake;
int nextBeamTime;
int nextLeftZapTime;
int nextRightZapTime;
idVec3 laserEndLeft;
idVec3 laserEndRight;
int nextLaserLeft;
int nextLaserRight;
int nextHealthTick;
int leftRechargerHealth;
int rightRechargerHealth;
idEntityPtr<hhMonsterAI> leftRecharger;
idEntityPtr<hhMonsterAI> rightRecharger;
bool bScripted;
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif /* __PREY_AI_CREATURE_H__ */
+660
View File
@@ -0,0 +1,660 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_StartBurst("startBurst");
const idEventDef EV_EndBurst("endBurst");
const idEventDef EV_StartStaticBeam("startStaticBeam");
const idEventDef EV_EndStaticBeam("endStaticBeam");
const idEventDef EV_StartChargeShot("startChargeShot");
const idEventDef EV_EndChargeShot("endChargeShot");
const idEventDef EV_StartPathing("startPathing");
const idEventDef EV_EndPathing("endPathing");
const idEventDef EV_EndZipBeams("<endZipBeams>");
const idEventDef EV_HealerReset("<healerReset>");
CLASS_DECLARATION(hhMonsterAI, hhDroid)
EVENT(EV_StartStaticBeam, hhDroid::Event_StartStaticBeam)
EVENT(EV_EndStaticBeam, hhDroid::Event_EndStaticBeam)
EVENT(EV_StartBurst, hhDroid::Event_StartBurst)
EVENT(EV_EndBurst, hhDroid::Event_EndBurst)
EVENT(EV_StartChargeShot, hhDroid::Event_StartChargeShot)
EVENT(EV_EndChargeShot, hhDroid::Event_EndChargeShot)
EVENT(EV_StartPathing, hhDroid::Event_StartPathing)
EVENT(EV_EndPathing, hhDroid::Event_EndPathing)
EVENT(EV_EndZipBeams, hhDroid::Event_EndZipBeams)
EVENT(EV_HealerReset, hhDroid::Event_HealerReset)
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
hhDroid::hhDroid() {
burstLength = 0.0;
burstSpread = 0.0;
burstDuration = 0.0;
staticDuration = 0.0;
staticRange = 0.0;
numBurstBeams = 0;
beamOffset = vec3_zero;
chargeShotSize = 0.0;
old_fly_bob_strength = 0.0;
spinAngle = 0.0f;
}
hhDroid::~hhDroid() {
for ( int i = 0; i < numBurstBeams; i ++ ) {
SAFE_REMOVE( beamBurstList[i] );
}
}
void hhDroid::Show( void ) {
hhMonsterAI::Show();
PostEventSec(&EV_StartStaticBeam, gameLocal.random.RandomFloat() * spawnArgs.GetFloat( "staticFreq", "2.5" ) );
}
void hhDroid::Spawn(void)
{
Event_SetMoveType(MOVETYPE_FLY);
lives = spawnArgs.GetInt( "lives", "3" );
numBurstBeams = spawnArgs.GetInt( "numBurstBeams", "5" );
burstLength = spawnArgs.GetFloat( "burstLength", "250" );
staticDuration = spawnArgs.GetFloat( "staticDuration", "2.0" );
burstDuration = spawnArgs.GetFloat( "burstDuration", "2.0" );
beamOffset = spawnArgs.GetVector( "beamOffset", "0 0 0" );
burstSpread = spawnArgs.GetFloat( "burstSpread", "1.0" );
enemyRange = spawnArgs.GetFloat( "enemy_range", "3000" );
flyDampening = spawnArgs.GetFloat( "fly_dampening", "0.01" );
bHealer = spawnArgs.GetBool( "healer" );
beamZip = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamZip" ) );
if( beamZip.IsValid() ) {
beamZip->Activate( false );
beamZip->SetOrigin( GetPhysics()->GetOrigin() + beamOffset );
beamZip->Bind( this, false );
}
for ( int i = 0; i < numBurstBeams; i ++ ) {
if ( gameLocal.random.RandomFloat() > 0.5f ) {
beamBurstList.Append( hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamBurst1" ) ) );
} else {
beamBurstList.Append( hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamBurst2" ) ) );
}
if( beamBurstList[i].IsValid() ) {
beamBurstList[i]->Activate( false );
beamBurstList[i]->SetOrigin( GetPhysics()->GetOrigin() + beamOffset );
beamBurstList[i]->Bind( this, false );
}
}
PostEventSec(&EV_StartStaticBeam, gameLocal.random.RandomFloat() * spawnArgs.GetFloat( "staticFreq", "2.5" ) );
}
bool hhDroid::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
bool bPain = hhMonsterAI::Pain( inflictor, attacker, damage, dir, location );
if ( !bPain ) {
return bPain;
}
//activate some beams for damage fx
for ( int i = 0; i < beamBurstList.Num(); i ++ ) {
if ( beamBurstList[i].IsValid() ) {
beamBurstList[i]->Activate( true );
beamBurstList[i]->SetTargetLocation( beamBurstList[i]->GetOrigin() + burstLength * hhUtils::RandomSpreadDir( dir.ToMat3(), burstSpread ) );
PostEventSec(&EV_EndBurst, staticDuration);
}
}
return bPain;
}
void hhDroid::Think() {
PROFILE_SCOPE("AI", PROFMASK_NORMAL|PROFMASK_AI);
if (ai_skipThink.GetBool()) {
return;
}
hhMonsterAI::Think();
//update burst beams
idMat3 dir;
if ( enemy.IsValid() ) {
dir = (enemy->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin()).ToMat3();
} else {
dir = GetPhysics()->GetAxis();
}
for ( int i = 0; i < beamBurstList.Num(); i ++ ) {
if ( beamBurstList[i].IsValid() && beamBurstList[i]->IsActivated() ) {
beamBurstList[i]->SetTargetLocation( beamBurstList[i]->GetOrigin() + burstLength * hhUtils::RandomSpreadDir( hhUtils::RandomVector().ToMat3(), burstSpread ) );
}
}
if ( staticPoint.IsValid() && beamBurstList[0].IsValid() ) {
beamBurstList[0]->SetTargetLocation( staticPoint->GetPhysics()->GetOrigin() );
}
if ( chargeShot.IsValid() ) {
chargeShot->SetShaderParm( 9, 1 );
chargeShot->SetShaderParm( 10, chargeShotSize );
chargeShotSize += spawnArgs.GetFloat( "chargeSizeDelta" );
chargeShot->GetPhysics()->DisableClip();
}
}
void hhDroid::Event_StartChargeShot(void) {
//spawn chargeshot projectile
const idDict *projectileDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_chargeshot") );
if ( projectileDef ) {
chargeShot = hhProjectile::SpawnProjectile( projectileDef );
if ( chargeShot.IsValid() ) {
chargeShotSize = spawnArgs.GetFloat( "chargeSizeStart", "1.0" );
idVec3 launchStart = GetPhysics()->GetOrigin() + spawnArgs.GetVector( "chargeOffset", "15 0 0" ) * GetRenderEntity()->axis;
chargeShot->Create(this, launchStart, GetRenderEntity()->axis);
chargeShot->Launch(chargeShot->GetPhysics()->GetOrigin(), chargeShot->GetPhysics()->GetAxis(), vec3_zero );
chargeShot->Bind(this, true);
}
}
}
void hhDroid::Event_EndChargeShot(void) {
//launch projectile
if ( chargeShot.IsValid() ) {
chargeShot->Unbind();
chargeShot->StartTracking();
chargeShot.Clear();
}
}
void hhDroid::Event_StartBurst(void) {
gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, this, this, this, spawnArgs.GetString("def_burstdamage") );
//burst effect
idMat3 dir;
if ( enemy.IsValid() ) {
dir = (enemy->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin()).ToMat3();
} else {
dir = GetPhysics()->GetAxis();
}
for ( int i = 0; i < beamBurstList.Num(); i++ ) {
if ( beamBurstList[i].IsValid() ) {
beamBurstList[i]->Activate( true );
beamBurstList[i]->SetTargetLocation( beamBurstList[i]->GetOrigin() + burstLength * hhUtils::RandomSpreadDir( hhUtils::RandomVector().ToMat3(), burstSpread ) );
}
}
PostEventSec(&EV_EndBurst, burstDuration);
}
void hhDroid::Event_EndBurst(void) {
for ( int i = 0; i < beamBurstList.Num(); i ++ ) {
if ( beamBurstList[i].IsValid() ) {
beamBurstList[i]->Activate( false );
}
}
}
void hhDroid::Event_EndStaticBeam(void) {
if ( beamBurstList[0].IsValid() ) {
beamBurstList[0]->Activate( false );
}
if ( staticPoint.IsValid() ) {
staticPoint.Clear();
}
//wait random time until next static beam
if ( !IsHidden() && !AI_DEAD ) {
PostEventSec(&EV_StartStaticBeam, gameLocal.random.RandomFloat() * spawnArgs.GetFloat( "staticFreq", "2.5" ) );
}
}
void hhDroid::Event_StartStaticBeam(void) {
idVec3 targetPoint;
idEntity *entityList[ MAX_GENTITIES ];
if ( IsHidden() || AI_DEAD ) {
return;
}
//find nearest staticPoint
float radius = spawnArgs.GetFloat( "staticRange" );
int listedEntities = gameLocal.EntitiesWithinRadius( GetPhysics()->GetOrigin(), radius, entityList, MAX_GENTITIES );
for( int i = 0; i < listedEntities; i++ ) {
if ( entityList[ i ] && entityList[ i ]->spawnArgs.GetInt( "droidBeam", "0" ) ) {
staticPoint = entityList[ i ];
break;
}
}
//activate one beam
if ( staticPoint.IsValid() && beamBurstList[0].IsValid() ) {
StartSound( "snd_staticBeam", SND_CHANNEL_BODY, 0, true, NULL );
beamBurstList[0]->Activate( true );
beamBurstList[0]->SetTargetLocation( beamBurstList[0]->GetOrigin() + burstLength * hhUtils::RandomVector() );
staticPoint->ActivateTargets( this );
PostEventSec(&EV_EndStaticBeam, staticDuration);
}
}
void hhDroid::FlyTurn( void ) {
if ( AI_PATHING ) {
hhMonsterAI::FlyTurn();
return;
}
if ( AI_ENEMY_VISIBLE || move.moveCommand == MOVE_FACE_ENEMY ) {
TurnToward( lastVisibleEnemyPos );
} else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) {
TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() );
} else if ( move.speed > 0.0f ) {
const idVec3 &vel = physicsObj.GetLinearVelocity();
if ( vel.ToVec2().LengthSqr() > 0.1f ) {
TurnToward( vel.ToYaw() );
}
}
Turn();
}
void hhDroid::Event_StartPathing(void) {
AI_PATHING = true;
old_fly_bob_strength = fly_bob_strength;
fly_bob_strength = 0.0;
ignore_obstacles = true;
}
void hhDroid::Event_EndPathing(void) {
AI_PATHING = false;
fly_bob_strength = old_fly_bob_strength;
ignore_obstacles = false;
}
void hhDroid::FlyMove( void ) {
idVec3 goalPos;
idVec3 oldorigin;
idVec3 newDest;
AI_BLOCKED = false;
if ( ( move.moveCommand != MOVE_NONE ) && ReachedPos( move.moveDest, move.moveCommand ) ) {
if ( AI_PATHING ) {
physicsObj.SetLinearVelocity( idVec3(0,0,0) );
}
StopMove( MOVE_STATUS_DONE );
}
if ( move.moveCommand != MOVE_TO_POSITION_DIRECT ) {
idVec3 vel = physicsObj.GetLinearVelocity();
if ( GetMovePos( goalPos ) ) {
move.obstacle = NULL;
}
if ( move.speed ) {
FlySeekGoal( vel, goalPos );
}
// add in bobbing
AddFlyBob( vel );
if ( enemy.GetEntity() && ( move.moveCommand != MOVE_TO_POSITION ) ) {
float dist = ( GetPhysics()->GetOrigin() - enemy->GetPhysics()->GetOrigin() ).LengthFast();
if ( dist < enemyRange && enemyRange > 0 ) {
AdjustFlyHeight( vel, goalPos );
}
}
AdjustFlySpeed( vel );
physicsObj.SetLinearVelocity( vel );
}
// turn
FlyTurn();
// run the physics for this frame
oldorigin = physicsObj.GetOrigin();
physicsObj.UseFlyMove( true );
physicsObj.UseVelocityMove( false );
physicsObj.SetDelta( vec3_zero );
physicsObj.ForceDeltaMove( disableGravity );
RunPhysics();
monsterMoveResult_t moveResult = physicsObj.GetMoveResult();
if ( !af_push_moveables && attack.Length() && TestMelee() ) {
DirectDamage( attack, enemy.GetEntity() );
} else {
idEntity *blockEnt = physicsObj.GetSlideMoveEntity();
if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) {
KickObstacles( viewAxis[ 0 ], kickForce, blockEnt );
} else if ( moveResult == MM_BLOCKED ) {
move.blockTime = gameLocal.time + 500;
AI_BLOCKED = true;
}
}
idVec3 org = physicsObj.GetOrigin();
if ( oldorigin != org ) {
TouchTriggers();
}
if ( ai_debugMove.GetBool() ) {
gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 4000 );
gameRenderWorld->DebugBounds( colorOrange, physicsObj.GetBounds(), org, gameLocal.msec );
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec );
gameRenderWorld->DebugLine( colorRed, org, org + physicsObj.GetLinearVelocity(), gameLocal.msec, true );
gameRenderWorld->DebugLine( colorBlue, org, goalPos, gameLocal.msec, true );
gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true );
DrawRoute();
}
}
idProjectile *hhDroid::LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef ) {
//jsh overridden to allow per-projectile accuracy
idVec3 muzzle;
idVec3 dir;
idVec3 start;
trace_t tr;
idBounds projBounds;
float distance;
const idClipModel *projClip;
float attack_accuracy;
float attack_cone;
float projectile_spread;
float diff;
float angle;
float spin;
idAngles ang;
int num_projectiles;
int i;
idMat3 axis;
idVec3 tmp;
idProjectile *lastProjectile;
//HUMANHEAD mdc - added to support multiple projectiles
if( desiredProjectileDef ) { //try to set our projectile to the desiredProjectile
int projIndex = FindProjectileInfo( desiredProjectileDef );
if( projIndex >= 0 ) {
SetCurrentProjectile( projIndex );
}
}
//HUMANHEAD END
if ( !projectileDef ) {
gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
return NULL;
}
if ( projectileDef->GetFloat( "attack_accuracy" ) ) {
attack_accuracy = projectileDef->GetFloat( "attack_accuracy", "7" );
} else {
attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" );
}
attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
if ( projectileDef->GetFloat( "projectile_spread" ) ) {
projectile_spread = projectileDef->GetFloat( "projectile_spread", "0" );
} else {
projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" );
}
if ( projectileDef->GetFloat( "num_projectiles" ) ) {
num_projectiles = projectileDef->GetFloat( "num_projectiles", "1" );
} else {
num_projectiles = spawnArgs.GetFloat( "num_projectiles", "1" );
}
GetMuzzle( jointname, muzzle, axis );
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, axis[ 0 ] );
}
lastProjectile = projectile.GetEntity();
if ( target != NULL ) {
tmp = target->GetPhysics()->GetAbsBounds().GetCenter() - muzzle;
tmp.Normalize();
axis = tmp.ToMat3();
} else {
axis = viewAxis;
}
// rotate it because the cone points up by default
tmp = axis[2];
axis[2] = axis[0];
axis[0] = -tmp;
// make sure the projectile starts inside the monster bounding box
const idBounds &ownerBounds = physicsObj.GetAbsBounds();
projClip = lastProjectile->GetPhysics()->GetClipModel();
projBounds = projClip->GetBounds().Rotate( axis );
// check if the owner bounds is bigger than the projectile bounds
if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
start = muzzle + distance * viewAxis[ 0 ];
} else {
start = ownerBounds.GetCenter();
}
} else {
// projectile bounds bigger than the owner bounds, so just start it from the center
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this );
muzzle = tr.endpos;
// set aiming direction
GetAimDir( muzzle, target, this, dir );
ang = dir.ToAngles();
// adjust his aim so it's not perfect. uses sine based movement so the tracers appear less random in their spread.
float t = MS2SEC( gameLocal.time + entityNumber * 497 );
ang.pitch += idMath::Sin16( t * 5.1 ) * attack_accuracy;
ang.yaw += idMath::Sin16( t * 6.7 ) * attack_accuracy;
if ( !AI_WALLWALK && clampToAttackCone ) {
// clamp the attack direction to be within monster's attack cone so he doesn't do
// things like throw the missile backwards if you're behind him
diff = idMath::AngleDelta( ang.yaw, current_yaw );
if ( diff > attack_cone ) {
ang.yaw = current_yaw + attack_cone;
} else if ( diff < -attack_cone ) {
ang.yaw = current_yaw - attack_cone;
}
}
axis = ang.ToMat3();
float spreadRad = DEG2RAD( projectile_spread );
for( i = 0; i < num_projectiles; i++ ) {
// spread the projectiles out
angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
dir = axis[ 0 ] + axis[ 2 ] * ( angle * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir.Normalize();
// launch the projectile
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, dir );
}
lastProjectile = projectile.GetEntity();
lastProjectile->Launch( muzzle, dir, vec3_origin );
projectile = NULL;
}
TriggerWeaponEffects( muzzle, axis );
lastAttackTime = gameLocal.time;
//HUMANHEAD mdc - added to support multiple projectiles
projectile = NULL;
SetCurrentProjectile( projectileDefaultDefIndex ); //set back to our default projectile to be on the safe side
//HUMANHEAD END
return lastProjectile;
}
void hhDroid::Event_FlyZip() {
idVec3 old_origin = GetOrigin();
hhMonsterAI::Event_FlyZip();
if ( old_origin != GetOrigin() ) {
if ( beamZip.IsValid() ) {
beamZip->SetTargetLocation( old_origin );
}
if ( beamZip.IsValid() ) {
beamZip->Activate( true );
}
PostEventSec( &EV_EndZipBeams, spawnArgs.GetFloat( "zip_beam_duration", "1.0" ) );
}
}
void hhDroid::Event_EndZipBeams() {
if ( beamZip.IsValid() ) {
beamZip->Activate( false );
}
}
void hhDroid::Event_HealerReset() {
fl.takedamage = true;
}
void hhDroid::Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
if ( bHealer ) {
lives--;
if ( lives <= 0 ) {
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
} else {
const char *defName = spawnArgs.GetString( "fx_pain" );
if (defName && defName[0]) {
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone( true );
idEntityFx *painFx = SpawnFxLocal( defName, GetOrigin(), GetAxis(), &fxInfo, gameLocal.isClient );
if ( painFx ) {
painFx->Bind( this, true );
}
}
health = spawnArgs.GetInt( "health" );
fl.takedamage = false;
PostEventSec( &EV_HealerReset, spawnArgs.GetFloat( "reset_delay", "0.8" ) );
}
return;
}
if ( AI_DEAD ) {
AI_DAMAGE = true;
return;
}
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
for ( int i = 0; i < beamBurstList.Num(); i ++ ) {
if ( beamBurstList[i].IsValid() ) {
beamBurstList[i]->Activate( true );
beamBurstList[i]->SetTargetLocation( beamBurstList[i]->GetOrigin() + burstLength * hhUtils::RandomSpreadDir( dir.ToMat3(), burstSpread ) );
PostEventSec(&EV_EndBurst, staticDuration);
}
}
}
void hhDroid::AdjustFlySpeed( idVec3 &vel ) {
float speed;
// apply dampening
vel -= vel * flyDampening * MS2SEC( gameLocal.msec );
// gradually speed up/slow down to desired speed
speed = vel.Normalize();
speed += ( move.speed - speed ) * MS2SEC( gameLocal.msec );
if ( speed < 0.0f ) {
speed = 0.0f;
} else if ( move.speed && ( speed > move.speed ) ) {
speed = move.speed;
}
vel *= speed;
}
void hhDroid::UpdateModelTransform( void ) {
idVec3 origin;
idMat3 axis;
if ( GetPhysicsToVisualTransform( origin, axis ) ) {
renderEntity.axis = axis * GetPhysics()->GetAxis();
renderEntity.origin = GetPhysics()->GetOrigin() + origin * renderEntity.axis;
if ( bHealer ) {
renderEntity.axis = idAngles( 0, 0, spinAngle ).ToMat3() * renderEntity.axis;
spinAngle += 10;
if ( spinAngle > 360.0f ) {
spinAngle = 0.0f;
}
}
} else {
renderEntity.axis = GetPhysics()->GetAxis();
renderEntity.origin = GetPhysics()->GetOrigin();
}
}
/*
=====================
hhDroid::Save
=====================
*/
void hhDroid::Save( idSaveGame *savefile ) const {
int num = beamBurstList.Num();
savefile->WriteInt( num );
for ( int i = 0; i < num; i++ ) {
beamBurstList[i].Save( savefile );
}
staticPoint.Save( savefile );
chargeShot.Save( savefile );
beamZip.Save( savefile );
savefile->WriteVec3( savedGravity );
savefile->WriteFloat( chargeShotSize );
savefile->WriteFloat( burstLength );
savefile->WriteFloat( burstSpread );
savefile->WriteFloat( burstDuration );
savefile->WriteFloat( staticDuration );
savefile->WriteFloat( staticRange );
savefile->WriteInt( numBurstBeams );
savefile->WriteVec3( beamOffset );
savefile->WriteFloat( old_fly_bob_strength );
savefile->WriteFloat( enemyRange );
savefile->WriteFloat( flyDampening );
savefile->WriteFloat( spinAngle );
savefile->WriteBool( bHealer );
savefile->WriteInt( lives );
}
/*
=====================
hhDroid::Restore
=====================
*/
void hhDroid::Restore( idRestoreGame *savefile ) {
int num;
savefile->ReadInt( num );
beamBurstList.SetNum( num );
for ( int i = 0; i < num; i++ ) {
beamBurstList[i].Restore( savefile );
}
staticPoint.Restore( savefile );
chargeShot.Restore( savefile );
beamZip.Restore( savefile );
savefile->ReadVec3( savedGravity );
savefile->ReadFloat( chargeShotSize );
savefile->ReadFloat( burstLength );
savefile->ReadFloat( burstSpread );
savefile->ReadFloat( burstDuration );
savefile->ReadFloat( staticDuration );
savefile->ReadFloat( staticRange );
savefile->ReadInt( numBurstBeams );
savefile->ReadVec3( beamOffset );
savefile->ReadFloat( old_fly_bob_strength );
savefile->ReadFloat( enemyRange );
savefile->ReadFloat( flyDampening );
savefile->ReadFloat( spinAngle );
savefile->ReadBool( bHealer );
savefile->ReadInt( lives );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+73
View File
@@ -0,0 +1,73 @@
#ifndef __PREY_AI_DROID_H__
#define __PREY_AI_DROID_H__
class hhDroid : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhDroid);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_StartBurst(void) {};
void Event_EndBurst(void) {};
void Event_StartStaticBeam(void) {};
void Event_EndStaticBeam(void) {};
void Event_StartChargeShot(void) {};
void Event_EndChargeShot(void) {};
void Event_StartPathing(void) {};
void Event_EndPathing(void) {};
void Event_FlyZip() {};
void Event_EndZipBeams() {};
void Event_HealerReset() {}
#else
hhDroid();
~hhDroid();
void Spawn( void );
virtual void Think( void );
void FlyTurn( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void AdjustFlySpeed( idVec3 &vel );
protected:
idList< idEntityPtr<hhBeamSystem> > beamBurstList;
idEntityPtr<hhBeamSystem> beamZip;
idEntityPtr<idEntity> staticPoint;
idEntityPtr<hhProjectileTracking> chargeShot;
void Event_StartBurst(void);
void Event_EndBurst(void);
void Event_StartStaticBeam(void);
void Event_EndStaticBeam(void);
void Event_StartChargeShot(void);
void Event_EndChargeShot(void);
void Event_StartPathing(void);
void Event_EndPathing(void);
void Event_FlyZip();
void Event_EndZipBeams();
void Event_HealerReset();
idProjectile *LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef );
virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
virtual void Show( void );
void FlyMove( void );
void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
void UpdateModelTransform();
idVec3 savedGravity;
float chargeShotSize;
float burstLength;
float burstSpread;
float burstDuration;
float staticDuration; //how long staticbeam lasts
float staticRange; //distance to check for staticbeam points
int numBurstBeams;
idVec3 beamOffset;
float old_fly_bob_strength;
float enemyRange;
float flyDampening;
int lives;
float spinAngle;
bool bHealer;
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif
+801
View File
@@ -0,0 +1,801 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_AcidBlast("acidBlast");
const idEventDef EV_AcidDrip("<acidDrip>");
const idEventDef EV_DeathCloud("<deathCloud>");
const idEventDef EV_LaunchPod("launchPod");
const idEventDef EV_NewPod("<newPod>", "e");
const idEventDef EV_SpawnBlastDebris("<spawnBlastDebris>");
const idEventDef EV_ChargeEnemy("chargeEnemy");
const idEventDef EV_GrabEnemy("grabEnemy", NULL, 'f');
const idEventDef EV_BiteEnemy("biteEnemy");
const idEventDef EV_DirectMoveToPosition("directMoveToPosition", "v");
const idEventDef EV_BindUnfroze("<bindUnfroze>", "e");
const idEventDef EV_GrabCheck("grabCheck", "", 'd');
const idEventDef EV_MoveToGrabPosition("moveToGrabPosition");
const idEventDef EV_CheckRange("checkRange", "", 'd');
const idEventDef EV_EnemyRangeZ("enemyRangeZ", "", 'f');
CLASS_DECLARATION(hhMonsterAI, hhGasbagSimple)
EVENT(EV_AcidBlast, hhGasbagSimple::Event_AcidBlast)
EVENT(EV_AcidDrip, hhGasbagSimple::Event_AcidDrip)
EVENT(EV_DeathCloud, hhGasbagSimple::Event_DeathCloud)
EVENT(EV_LaunchPod, hhGasbagSimple::Event_LaunchPod)
EVENT(EV_NewPod, hhGasbagSimple::Event_NewPod)
EVENT(EV_SpawnBlastDebris, hhGasbagSimple::Event_SpawnBlastDebris)
EVENT(EV_ChargeEnemy, hhGasbagSimple::Event_ChargeEnemy)
EVENT(EV_GrabEnemy, hhGasbagSimple::Event_GrabEnemy)
EVENT(EV_BiteEnemy, hhGasbagSimple::Event_BiteEnemy)
EVENT(EV_DirectMoveToPosition, hhGasbagSimple::Event_DirectMoveToPosition)
EVENT(EV_BindUnfroze, hhGasbagSimple::Event_BindUnfroze)
EVENT(EV_GrabCheck, hhGasbagSimple::Event_GrabCheck)
EVENT(EV_MoveToGrabPosition, hhGasbagSimple::Event_MoveToGrabPosition)
EVENT(EV_CheckRange, hhGasbagSimple::Event_CheckRange)
EVENT(EV_EnemyRangeZ, hhGasbagSimple::Event_EnemyRangeZ)
END_CLASS
static const idEventDef EV_Unfreeze( "<unfreeze>" );
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
//
// ~hhGasbagSimple()
//
hhGasbagSimple::~hhGasbagSimple(void) {
// Make sure to unbind the player if we've grabbed him to prevent deleting him
if (enemy.IsValid() && enemy->IsBoundTo(this) && enemy->IsType(hhPlayer::Type)) {
enemy->Unbind();
enemy->PostEventMS(&EV_Unfreeze, 0);
}
}
//
// Spawn()
//
void hhGasbagSimple::Spawn(void) {
Event_SetMoveType(MOVETYPE_FLY); // So we ignore gravity zones from the beginning
podOffset = spawnArgs.GetVector("pod_offset", "0 0 64");
podRange = spawnArgs.GetFloat("podRange", "250");
dripCount = 0;
nextWoundTime = 0;
bindController = static_cast<hhBindController *>( gameLocal.SpawnClientObject(spawnArgs.GetString("def_bindController"), NULL) );
HH_ASSERT( bindController.IsValid() );
bindController->fl.networkSync = false;
float yawLimit = spawnArgs.GetFloat("yawlimit", "180");
const char *handName = spawnArgs.GetString("def_tractorhand");
const char *animName = spawnArgs.GetString("boundanim");
bindController->SetRiderParameters(animName, handName, yawLimit, 0.0f);
bindController->Bind(this, true);
bindController->SetOrigin(spawnArgs.GetVector("grab_offset"));
bindController->fl.neverDormant = true;
}
//
// Ticker()
//
void hhGasbagSimple::Ticker(void) {
for (int i = 0; i < podList.Num(); i++) {
if (!podList[i].IsValid()) {
podList.RemoveIndex(i);
i--; // This index is gone, so don't increment
continue;
}
}
// Update the podcount
AI_PODCOUNT = podList.Num();
if (podList.Num() == 0) {
BecomeInactive(TH_TICKER);
}
}
//
// Save()
//
void hhGasbagSimple::Save(idSaveGame *savefile) const {
savefile->WriteInt(dripCount);
savefile->WriteInt(podList.Num());
for (int i = 0; i < podList.Num(); i++) {
podList[i].Save(savefile);
}
bindController.Save(savefile);
}
//
// Restore()
//
void hhGasbagSimple::Restore(idRestoreGame *savefile) {
Spawn();
savefile->ReadInt(dripCount);
int num;
savefile->ReadInt(num);
podList.SetNum(num);
for (int i = 0; i < num; i++) {
podList[i].Restore(savefile);
}
bindController.Restore(savefile);
nextWoundTime = 0;
}
//
// Event_AcidBlast()
//
void hhGasbagSimple::Event_AcidBlast(void) {
if (health <= 0) { // Don't launch a pod if we're dead
return;
}
if (!enemy.IsValid()) {
return;
}
idEntity *target = enemy.GetEntity();
idVec3 targetOrigin = target->GetOrigin();
float len, nearest = podRange;
// See if we have a pod near the enemy. If we do, target it instead.
idEntity *entList[100];
int num = gameLocal.EntitiesWithinRadius(targetOrigin, podRange, entList, 100);
for (int i = 0; i < num; i++) {
if (!entList[i]->IsType(hhPod::Type)) {
continue;
}
len = (entList[i]->GetOrigin() - targetOrigin).Length();
// Always target the pod nearest to the enemy
if (len < nearest) {
target = entList[i];
nearest = len;
}
}
// Spawn a "muzzle flash"-like fx
hhFxInfo fx;
fx.SetEntity(this);
fx.RemoveWhenDone(true);
SpawnFxLocal(spawnArgs.GetString("fx_fire"), GetOrigin() + idVec3(0, 0, -400), enemy->GetPhysics()->GetGravityNormal().ToMat3(), &fx);
// Spawn an acid blob in the player's general direction
const idDict *projDef = gameLocal.FindEntityDefDict(spawnArgs.GetString("def_projectile"), false);
LaunchProjectile(spawnArgs.GetString("acidbone", "LmbRt"), target, false, projDef);
PostEventMS(&EV_SpawnBlastDebris, 100 + gameLocal.random.RandomInt(100));
dripCount = gameLocal.random.RandomInt(3) + 1;
PostEventMS(&EV_AcidDrip, 200 + gameLocal.random.RandomInt(100)); // Drip acid after firing
}
//
// Event_SpawnBlastDebris()
//
void hhGasbagSimple::Event_SpawnBlastDebris(void) {
idDict args;
args.Clear();
args.Set("origin", (GetPhysics()->GetOrigin() + spawnArgs.GetVector("blast_debris_offset", "0 0 128")).ToString());
gameLocal.SpawnObject("debrisSpawner_gasbag_fire", &args);
}
//
// Event_AcidDrip()
//
void hhGasbagSimple::Event_AcidDrip(void) {
assert(dripCount > 0);
dripCount--;
idVec3 target = GetPhysics()->GetOrigin();
target.z -= 128;
idVec3 rndVec = hhUtils::RandomVector() * gameLocal.random.RandomInt(20);
const idDict *projDef = gameLocal.FindEntityDefDict(spawnArgs.GetString("def_drip_projectile", "projectile_acidspray_gasbag"), false);
LaunchProjectileAtVec(spawnArgs.GetString("acidbone", "LmbRt"), target + rndVec, false, projDef);
if (dripCount > 0) {
PostEventMS(&EV_AcidDrip, 200 + gameLocal.random.RandomInt(100)); // Fire again in 200-300ms
}
}
//
// Event_DeathCloud()
//
void hhGasbagSimple::Event_DeathCloud(void) {
const char *fx = spawnArgs.GetString("fx_death");
if (!fx || !fx[0]) {
return;
}
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone(true);
BroadcastFxInfo(fx, GetOrigin(), GetAxis(), &fxInfo);
}
//
// Event_LaunchPod()
//
void hhGasbagSimple::Event_LaunchPod() {
if (health <= 0) { // Don't launch a pod if we're dying
return;
}
idVec3 target, origin, offset = vec3_origin;
if (enemy.IsValid()) {
// Target a random area around the enemy
origin = enemy->GetEyePosition();
if (gameLocal.random.RandomInt(100) > 30) { // Possibly target the enemy exactly
offset.x = (gameLocal.random.RandomFloat() * 100.0f) - 50.0f;
offset.y = (gameLocal.random.RandomFloat() * 100.0f) - 50.0f;
}
} else {
// Target a random area beneath us
origin = GetOrigin();
offset.x = gameLocal.random.RandomFloat() * 10.0f;
offset.y = gameLocal.random.RandomFloat() * 10.0f;
offset.z = -10.0f;
}
target = origin + offset;
const idDict *projDef = gameLocal.FindEntityDefDict(spawnArgs.GetString("def_pod_projectile", "projectile_gasbag_pod"), false);
LaunchProjectileAtVec(spawnArgs.GetString("acidbone", "LmbRt"), target, false, projDef);
}
//
// Event_NewPod
//
void hhGasbagSimple::Event_NewPod(hhPod *pod) {
HH_ASSERT(pod && pod->IsType(hhPod::Type));
podList.Append(idEntityPtr<hhPod>(pod));
// Update the podcount
AI_PODCOUNT = podList.Num();
BecomeActive(TH_TICKER);
}
//
// Killed
//
void hhGasbagSimple::Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location) {
bool wasDead = (AI_DEAD != 0);
hhMonsterAI::Killed(inflictor, attacker, damage, dir, location);
if (wasDead) {
return;
}
CancelEvents(&EV_AcidDrip);
CancelEvents(&EV_AcidBlast);
CancelEvents(&EV_LaunchPod);
dripCount = 0;
// Release any grabbed enemy
idEntity *rider;
if ((rider = bindController->GetRider()) != NULL) {
bindController->Detach();
if (rider->IsType(hhPlayer::Type)) {
rider->ProcessEvent(&EV_Unfreeze);
}
}
int deathAnim = GetAnimator()->GetAnim("death");
GetAnimator()->PlayAnim(ANIMCHANNEL_TORSO, deathAnim, gameLocal.time, 300.0f);
int ttl = GetAnimator()->AnimLength(deathAnim);
// Freeze
physicsObj.EnableGravity(false);
physicsObj.PutToRest();
SetSkinByName( spawnArgs.GetString( "skin_death" ) );
SetDeformation(DEFORMTYPE_DEATHEFFECT, gameLocal.time + 2500, 8000); // starttime, duration
PostEventSec( &EV_StartSound, 1.5f, "snd_acid", SND_CHANNEL_ANY, 1 );
// Spawn gas cloud
PostEventMS(&EV_DeathCloud, ttl);
PostEventMS(&EV_Dispose, 0);
}
//
// LaunchProjectile
//
idProjectile *hhGasbagSimple::LaunchProjectileAtVec( const char *jointname, const idVec3 &target, bool clampToAttackCone, const idDict* desiredProjectileDef ) { //HUMANHEAD mdc - added desiredProjectileDef for supporting multiple projs.
idVec3 muzzle;
idVec3 dir;
idVec3 start;
trace_t tr;
idBounds projBounds;
float distance;
const idClipModel *projClip;
float attack_accuracy;
float attack_cone;
float projectile_spread;
float diff;
float angle;
float spin;
idAngles ang;
int num_projectiles;
int i;
idMat3 axis;
idVec3 tmp;
idProjectile *lastProjectile;
//HUMANHEAD mdc - added to support multiple projectiles
if( desiredProjectileDef ) { //try to set our projectile to the desiredProjectile
int projIndex = FindProjectileInfo( desiredProjectileDef );
if( projIndex >= 0 ) {
SetCurrentProjectile( projIndex );
}
}
//HUMANHEAD END
if ( !projectileDef ) {
gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
return NULL;
}
attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" );
attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" );
num_projectiles = spawnArgs.GetInt( "num_projectiles", "1" );
GetMuzzle( jointname, muzzle, axis );
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, axis[ 0 ] );
}
lastProjectile = projectile.GetEntity();
tmp = target - muzzle;
tmp.Normalize();
axis = tmp.ToMat3();
// rotate it because the cone points up by default
tmp = axis[2];
axis[2] = axis[0];
axis[0] = -tmp;
// make sure the projectile starts inside the monster bounding box
const idBounds &ownerBounds = physicsObj.GetAbsBounds();
projClip = lastProjectile->GetPhysics()->GetClipModel();
projBounds = projClip->GetBounds().Rotate( axis );
// check if the owner bounds is bigger than the projectile bounds
if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
start = muzzle + distance * viewAxis[ 0 ];
} else {
start = ownerBounds.GetCenter();
}
} else {
// projectile bounds bigger than the owner bounds, so just start it from the center
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this );
muzzle = tr.endpos;
// set aiming direction
//GetAimDir( muzzle, target, this, dir );
dir = target - muzzle;
ang = dir.ToAngles();
// adjust his aim so it's not perfect. uses sine based movement so the tracers appear less random in their spread.
float t = MS2SEC( gameLocal.time + entityNumber * 497 );
ang.pitch += idMath::Sin16( t * 5.1 ) * attack_accuracy;
ang.yaw += idMath::Sin16( t * 6.7 ) * attack_accuracy;
if ( clampToAttackCone ) {
// clamp the attack direction to be within monster's attack cone so he doesn't do
// things like throw the missile backwards if you're behind him
diff = idMath::AngleDelta( ang.yaw, current_yaw );
if ( diff > attack_cone ) {
ang.yaw = current_yaw + attack_cone;
} else if ( diff < -attack_cone ) {
ang.yaw = current_yaw - attack_cone;
}
}
axis = ang.ToMat3();
float spreadRad = DEG2RAD( projectile_spread );
for( i = 0; i < num_projectiles; i++ ) {
// spread the projectiles out
angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
dir = axis[ 0 ] + axis[ 2 ] * ( angle * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir.Normalize();
// launch the projectile
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, dir );
}
lastProjectile = projectile.GetEntity();
lastProjectile->Launch( muzzle, dir, vec3_origin );
projectile = NULL;
}
TriggerWeaponEffects( muzzle, axis );
lastAttackTime = gameLocal.time;
//HUMANHEAD mdc - added to support multiple projectiles
projectile = NULL;
SetCurrentProjectile( projectileDefaultDefIndex ); //set back to our default projectile to be on the safe side
//HUMANHEAD END
return lastProjectile;
}
//
// LaunchProjectile
//
idProjectile *hhGasbagSimple::LaunchProjectileAtVec( const idVec3 &startOrigin, const idMat3 &startAxis, const idVec3 &target, bool clampToAttackCone, const idDict* desiredProjectileDef ) { //HUMANHEAD mdc - added desiredProjectileDef for supporting multiple projs.
idVec3 muzzle;
idVec3 dir;
idVec3 start;
trace_t tr;
idBounds projBounds;
float distance;
const idClipModel *projClip;
//float attack_accuracy;
//float attack_cone;
float projectile_spread;
float angle;
float spin;
idAngles ang;
int num_projectiles;
int i;
idMat3 axis;
idVec3 tmp;
idProjectile *lastProjectile;
//HUMANHEAD mdc - added to support multiple projectiles
if( desiredProjectileDef ) { //try to set our projectile to the desiredProjectile
int projIndex = FindProjectileInfo( desiredProjectileDef );
if( projIndex >= 0 ) {
SetCurrentProjectile( projIndex );
}
}
//HUMANHEAD END
if ( !projectileDef ) {
gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
return NULL;
}
//attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" );
//attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" );
num_projectiles = spawnArgs.GetInt( "num_projectiles", "1" );
muzzle = startOrigin;
axis = startAxis;
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, axis[ 0 ] );
}
lastProjectile = projectile.GetEntity();
// make sure the projectile starts inside the monster bounding box
const idBounds &ownerBounds = physicsObj.GetAbsBounds();
projClip = lastProjectile->GetPhysics()->GetClipModel();
projBounds = projClip->GetBounds().Rotate( axis );
// check if the owner bounds is bigger than the projectile bounds
if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
start = muzzle + distance * viewAxis[ 0 ];
} else {
start = ownerBounds.GetCenter();
}
} else {
// projectile bounds bigger than the owner bounds, so just start it from the center
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this );
muzzle = tr.endpos;
float spreadRad = DEG2RAD( projectile_spread );
for( i = 0; i < num_projectiles; i++ ) {
// spread the projectiles out
angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
dir = axis[ 0 ] + axis[ 2 ] * ( angle * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir.Normalize();
// launch the projectile
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, dir );
}
lastProjectile = projectile.GetEntity();
lastProjectile->Launch( muzzle, dir, vec3_origin );
projectile = NULL;
}
TriggerWeaponEffects( muzzle, axis );
lastAttackTime = gameLocal.time;
//HUMANHEAD mdc - added to support multiple projectiles
projectile = NULL;
SetCurrentProjectile( projectileDefaultDefIndex ); //set back to our default projectile to be on the safe side
//HUMANHEAD END
return lastProjectile;
}
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
void hhGasbagSimple::LinkScriptVariables(void) {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable(AI_PODCOUNT);
LinkScriptVariable(AI_CHARGEDONE);
LinkScriptVariable(AI_SWOOP);
LinkScriptVariable(AI_DODGEDAMAGE);
}
//
// Event_GrabEnemy()
//
void hhGasbagSimple::Event_GrabEnemy(void) {
idThread::ReturnFloat( GrabEnemy() );
}
//
// GrabEnemy()
//
bool hhGasbagSimple::GrabEnemy(void) {
if (!enemy.IsValid() || enemy->IsBound() || bindController->GetRider()) {
return false;
}
// Don't grab Talon
if (enemy->IsType(hhTalon::Type)) {
return false;
}
if (enemy->IsType(hhPlayer::Type)) {
hhPlayer *player = reinterpret_cast<hhPlayer *> (enemy.GetEntity());
if (player->IsSpiritOrDeathwalking() || player->InGravityZone()) { // Refuse to grab spirit players, or players affected by a gravity zone
return false;
}
player->Freeze();
}
bindController->Attach(enemy.GetEntity());
enemy->SetOrigin(vec3_origin);
return true;
}
//
// Event_BiteEnemy()
//
void hhGasbagSimple::Event_BiteEnemy(void) {
if (!enemy.IsValid() || bindController->GetRider() != enemy.GetEntity()) {
return;
}
if (enemy->IsType(hhSpiritProxy::Type)) {
float diff = gameLocal.GetTime() - reinterpret_cast<hhSpiritProxy *> (enemy.GetEntity())->GetActivationTime();
if (diff < 1150.0f) {
// Don't allow the spirit proxy to ignore damage
scriptThread->WaitMS(diff + 250.0f);
CancelEvents(&EV_BiteEnemy);
PostEventMS(&EV_BiteEnemy, diff + 100.0f);
return;
}
}
// Direct damage
bindController->Detach();
enemy->Damage(this, this, vec3_origin, spawnArgs.GetString("def_damage_bite"), 1.0f, INVALID_JOINT);
}
//
// Damage()
//
void hhGasbagSimple::Damage(idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location) {
int curHealth = health;
idEntity *enemyEnt = enemy.GetEntity();
hhMonsterAI::Damage(inflictor, attacker, dir, damageDefName, damageScale, location);
if (health < curHealth) {
if (gameLocal.time > nextWoundTime && location != INVALID_JOINT) {
hhFxInfo fx;
fx.SetEntity(this);
fx.RemoveWhenDone(true);
SpawnFxLocal(spawnArgs.GetString("fx_damage"), inflictor->GetOrigin(), dir.ToMat3(), &fx);
nextWoundTime = gameLocal.time + 250;
}
// Only release enemy if we actually took damage
idEntity *rider;
if ((rider = bindController->GetRider()) != NULL) {
bindController->Detach();
if (rider->IsType(hhPlayer::Type)) {
rider->PostEventMS(&EV_Unfreeze, 0);
}
}
AI_DODGEDAMAGE = AI_DODGEDAMAGE + (curHealth - health);
}
}
//
// Event_DirectMoveToPosition()
//
void hhGasbagSimple::Event_DirectMoveToPosition(const idVec3 &pos) {
StopMove(MOVE_STATUS_DONE);
DirectMoveToPosition(pos);
}
//
// Event_ChargeEnemy
//
void hhGasbagSimple::Event_ChargeEnemy(void) {
AI_CHARGEDONE = true;
StopMove(MOVE_STATUS_DEST_NOT_FOUND);
if (!enemy.IsValid() || enemy->IsBound()) {
return;
}
idVec3 enemyOrg;
fly_offset = 0.0f;
// position destination so that we're in the enemy's view
enemyOrg = enemy->GetEyePosition();
enemyOrg -= enemy->GetPhysics()->GetGravityNormal() * fly_offset;
DirectMoveToPosition(enemyOrg);
HH_ASSERT(move.bEnemyBlocks == false);
}
void hhGasbagSimple::Event_EnemyIsSpirit( hhPlayer *player, hhSpiritProxy *proxy ) {
hhMonsterAI::Event_EnemyIsSpirit(player, proxy);
if (bindController->GetRider() == player) {
bindController->Detach();
player->Unfreeze();
GrabEnemy();
}
}
void hhGasbagSimple::Event_EnemyIsPhysical( hhPlayer *player, hhSpiritProxy *proxy ) {
hhMonsterAI::Event_EnemyIsPhysical(player, proxy);
if (bindController->GetRider() == player) {
player->Freeze();
}
}
//
// Event_BindUnfroze
//
void hhGasbagSimple::Event_BindUnfroze(idEntity *unfrozenBind) {
if (!enemy.IsValid() || unfrozenBind != enemy.GetEntity() || bindController->GetRider() != enemy.GetEntity()) {
gameLocal.Warning("Gasbag received BindUnfroze event but enemy is not bound to it.\n");
return;
}
bindController->Detach();
}
//
// FlyTurn
//
void hhGasbagSimple::FlyTurn(void) {
if (!AI_SWOOP && (AI_ENEMY_VISIBLE || move.moveCommand == MOVE_FACE_ENEMY)) {
TurnToward( lastVisibleEnemyPos );
} else if ((move.moveCommand == MOVE_FACE_ENTITY) && move.goalEntity.GetEntity()) {
TurnToward(move.goalEntity.GetEntity()->GetPhysics()->GetOrigin());
} else if (move.speed > 0.1f) {
const idVec3 &vel = physicsObj.GetLinearVelocity();
if (vel.ToVec2().LengthSqr() > 0.1f) {
TurnToward(vel.ToYaw());
}
}
Turn();
}
//
// Event_GrabCheck()
//
void hhGasbagSimple::Event_GrabCheck(void) {
idThread::ReturnInt(enemy.IsValid() && enemy->IsBoundTo(this));
}
void hhGasbagSimple::Event_MoveToGrabPosition(void) {
StopMove(MOVE_STATUS_DEST_NOT_FOUND);
if (!enemy.IsValid() || enemy->IsBound()) {
return;
}
fly_offset = 0.0f;
// position destination so that we're right on the enemy when we grab him
DirectMoveToPosition(enemy->GetOrigin() - spawnArgs.GetVector( "grab_offset" ));
HH_ASSERT(move.bEnemyBlocks == false);
}
void hhGasbagSimple::SetEnemy(idActor *newEnemy) {
idEntity *rider;
if ((rider = bindController->GetRider())) { // This is usually caused by Talon
if (rider->IsType(hhPlayer::Type)) {
rider->PostEventMS(&EV_Unfreeze, 0);
}
bindController->Detach();
}
hhMonsterAI::SetEnemy(newEnemy);
}
void hhGasbagSimple::Event_CheckRange(void) {
if (!enemy.IsValid()) {
idThread::ReturnInt(0);
return;
}
int retval;
float dist = ( enemy->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).Length();
if (enemy->IsType(hhPlayer::Type)) {
float min = spawnArgs.GetFloat( "dda_range_min" );
float max = spawnArgs.GetFloat( "dda_range_max" );
float player_dist = min + (max - min) * gameLocal.GetDDAValue();
retval = (int) (dist <= player_dist);
} else {
retval = (int) (dist <= 100.0f);
}
idThread::ReturnInt(retval);
}
void hhGasbagSimple::Gib( const idVec3 &dir, const char *damageDefName ) {
// Bypass idActor::Gib()
idAFEntity_Gibbable::Gib( dir, damageDefName );
}
int hhGasbagSimple::ReactionTo( const idEntity *ent ) {
//gasbags skip the spirit stuff in hhMonsterAI::ReactionTo()
if ( bNoCombat ) {
return ATTACK_IGNORE;
}
const idActor *actor = static_cast<const idActor *>( ent );
if( actor && actor->IsType(hhDeathProxy::Type) ) {
return ATTACK_IGNORE;
}
if ( ent->IsType( hhMonsterAI::Type ) ) {
const hhMonsterAI *entAI = static_cast<const hhMonsterAI *>( ent );
if ( entAI && entAI->bNeverTarget ) {
return ATTACK_IGNORE;
}
}
return idAI::ReactionTo( ent );
}
void hhGasbagSimple::Event_EnemyRangeZ( void ) {
idThread::ReturnFloat( lastVisibleEnemyPos.z - GetOrigin().z );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+90
View File
@@ -0,0 +1,90 @@
#ifndef __PREY_AI_GASBAG_SIMPLE_H__
#define __PREY_AI_GASBAG_SIMPLE_H__
extern const idEventDef EV_NewPod;
class hhPod;
class hhGasbagSimple : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhGasbagSimple);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_AcidBlast(void) {};
void Event_AcidDrip(void) {};
void Event_DeathCloud(void) {};
void Event_NewPod(hhPod *pod) {};
void Event_LaunchPod(void) {};
void Event_SpawnBlastDebris(void) {};
void Event_ChargeEnemy(void) {};
void Event_GrabEnemy(void) {};
void Event_BiteEnemy(void) {};
void Event_DirectMoveToPosition(const idVec3 &pos) {};
void Event_BindUnfroze(idEntity *unfrozenBind) {};
virtual void Event_EnemyIsSpirit( hhPlayer *player, hhSpiritProxy *proxy ) {};
virtual void Event_EnemyIsPhysical( hhPlayer *player, hhSpiritProxy *proxy ) {};
void Event_GrabCheck(void) {};
void Event_MoveToGrabPosition(void) {};
void Event_CheckRange(void) {};
void Event_EnemyRangeZ(void) {};
#else
virtual ~hhGasbagSimple(void);
void Spawn(void);
void Save(idSaveGame *savefile) const;
void Restore(idRestoreGame *savefile);
virtual void FlyTurn(void);
virtual void Gib(const idVec3 &dir, const char *damageDefName);
int ReactionTo( const idEntity *ent );
protected:
void Event_AcidBlast(void);
void Event_AcidDrip(void);
void Event_DeathCloud(void);
void Event_NewPod(hhPod *pod);
void Event_LaunchPod(void);
void Event_SpawnBlastDebris(void);
void Event_ChargeEnemy(void);
void Event_GrabEnemy(void);
void Event_BiteEnemy(void);
void Event_DirectMoveToPosition(const idVec3 &pos);
void Event_BindUnfroze(idEntity *unfrozenBind);
virtual void Event_EnemyIsSpirit( hhPlayer *player, hhSpiritProxy *proxy );
virtual void Event_EnemyIsPhysical( hhPlayer *player, hhSpiritProxy *proxy );
void Event_GrabCheck(void);
void Event_MoveToGrabPosition(void);
void Event_CheckRange(void);
void Event_EnemyRangeZ(void);
bool GrabEnemy(void);
virtual void LinkScriptVariables(void);
virtual void Ticker(void);
virtual idProjectile *LaunchProjectileAtVec(const char *jointname, const idVec3 &target, bool clampToAttackCone, const idDict* desiredProjectileDef);
virtual idProjectile *LaunchProjectileAtVec(const idVec3 &startOrigin, const idMat3 &startAxis, const idVec3 &target, bool clampToAttackCone, const idDict* desiredProjectileDef);
virtual void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location);
virtual void Damage(idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location);
virtual void SetEnemy(idActor *newEnemy);
idVec3 podOffset;
float podRange;
int dripCount;
idList< idEntityPtr<hhPod> > podList;
idScriptInt AI_PODCOUNT;
idScriptBool AI_CHARGEDONE;
idScriptBool AI_SWOOP;
idScriptInt AI_DODGEDAMAGE;
int nextWoundTime;
idEntityPtr<hhBindController> bindController; // Bind controller for tractor beam
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif
+838
View File
@@ -0,0 +1,838 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef MA_AntiProjectileAttack("<antiProjectileAttack>", "e");
const idEventDef MA_StartPreDeath("<startPreDeath>" );
const idEventDef MA_HandlePassageway("<handlePassageway>", NULL);
const idEventDef MA_EnterPassageway("<enterPassageway>", "e",NULL);
const idEventDef MA_ExitPassageway("<exitPassageway>", "e",NULL);
const idEventDef MA_UseThisPassageway("useThisPassageway", "ed",NULL);
const idEventDef MA_GibOnDeath("gibOnDeath", "d");
CLASS_DECLARATION( hhMonsterAI, hhHarvesterSimple )
EVENT( MA_OnProjectileLaunch, hhHarvesterSimple::Event_OnProjectileLaunch )
EVENT( MA_AntiProjectileAttack, hhHarvesterSimple::Event_AntiProjectileAttack )
EVENT( MA_StartPreDeath, hhHarvesterSimple::Event_StartPreDeath )
EVENT( MA_HandlePassageway, hhHarvesterSimple::Event_HandlePassageway )
EVENT( MA_EnterPassageway, hhHarvesterSimple::Event_EnterPassageway )
EVENT( MA_ExitPassageway, hhHarvesterSimple::Event_ExitPassageway )
EVENT( MA_UseThisPassageway, hhHarvesterSimple::Event_UseThisPassageway )
EVENT( EV_Broadcast_AppendFxToList, hhHarvesterSimple::Event_AppendFxToList )
EVENT( MA_GibOnDeath, hhHarvesterSimple::Event_GibOnDeath )
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
//
// Spawn()
//
void hhHarvesterSimple::Spawn(void) {
allowPreDeath = true;
lastAntiProjectileAttack = 0;
lastPassagewayTime = 0;
passageCount = spawnArgs.GetInt("passage_count", "0"); // Used for passing to and from torso
bSmokes = spawnArgs.GetBool("smokes", "0");
bGibOnDeath = false;
}
//
// Event_OnProjectileLaunch()
//
void hhHarvesterSimple::Event_OnProjectileLaunch(hhProjectile *proj) {
// Can't launch again yet
float min = spawnArgs.GetFloat( "dda_delay_min" );
float max = spawnArgs.GetFloat( "dda_delay_max" );
float delay = min + (max - min) * (1.0f - gameLocal.GetDDAValue());
if(gameLocal.GetTime() - lastAntiProjectileAttack < delay)
return;
// The person who launched this projectile wasn't someone to worry about
if(proj->GetOwner() && !(ReactionTo(proj->GetOwner()) & (ATTACK_ON_SIGHT | ATTACK_ON_DAMAGE)))
return;
// TODO: more intelligent checks for if we should launch the anti-projectile chaff
idVec3 fw = viewAxis[0];
idVec3 projFw = proj->GetAxis()[0];
if(proj->GetOwner())
projFw = proj->GetOwner()->GetAxis()[0];
float dot = fw * projFw;
if(dot > -.7f)
return;
ProcessEvent(&MA_AntiProjectileAttack, proj);
}
//
// Event_AntiProjectileAttack()
//
void hhHarvesterSimple::Event_AntiProjectileAttack(hhProjectile *proj) {
if(!spawnArgs.GetBool("block_projectiles", "1")) {
return;
}
const idDict *projectileDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_chaff") );
if ( !projectileDef ) {
gameLocal.Error( "Unknown def_chaff: %s\n", spawnArgs.GetString("def_chaff") );
}
hhProjectile* projectile = NULL;
//bjk: new parms
int numProj = spawnArgs.GetInt("shieldNumProj", "10");
float spread = DEG2RAD( spawnArgs.GetFloat("shieldSpread", "10") );
float yaw = DEG2RAD( spawnArgs.GetFloat("shieldYawSpread", "10") );
//StartSound("snd_fire_chaff", SND_CHANNEL_ANY, 0, true, NULL);
torsoAnim.PlayAnim( GetAnimator()->GetAnim( "antiprojectile_attack" ) );
idVec3 dir = proj->GetOrigin() - GetOrigin();
dir.Normalize();
dir = dir+idVec3(0.f, 0.f, -.3f); // bjk: bias towards ground
dir.Normalize();
idMat3 muzzleAxis = dir.ToMat3();
// todo: read this in from a bone
idVec3 launchPos = GetOrigin() + idVec3(0.0f, 0.0f, 64.0f);
for(int i=0; i<numProj; i++) {
projectile = hhProjectile::SpawnProjectile( projectileDef );
HH_ASSERT( projectile );
//bjk: uses random now
float ang = spread * hhMath::Sqrt( gameLocal.random.RandomFloat() );
float spin = hhMath::TWO_PI * gameLocal.random.RandomFloat();
dir = muzzleAxis[ 0 ] + muzzleAxis[ 2 ] * ( hhMath::Sin(ang) * hhMath::Sin(spin) ) - muzzleAxis[ 1 ] * ( hhMath::Sin(ang+yaw) * hhMath::Cos(spin) );
dir.Normalize();
projectile->Create(this, launchPos, dir);
projectile->Launch(launchPos, dir, idVec3(0.0f, 0.0f, 0.0f));
}
lastAntiProjectileAttack = gameLocal.GetTime();
}
bool hhHarvesterSimple::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
int preDeathThresh = spawnArgs.GetInt("predeath_thresh", "-1");
if(allowPreDeath && !bGibOnDeath && preDeathThresh > 0 && health < preDeathThresh) {
allowPreDeath = false; // We've tried, cannot try anymore
float preDeathFreq = spawnArgs.GetFloat("predeath_freq", "1");
if(gameLocal.random.RandomFloat() < preDeathFreq) {
ProcessEvent(&MA_StartPreDeath);
}
}
if ( bSmokes ) {
if ( !fxSmoke[0].IsValid() && health <= AI_PASSAGEWAY_HEALTH ) {
SpawnSmoke();
} else if (fxSmoke[0].IsValid() && health > AI_PASSAGEWAY_HEALTH) {
ClearSmoke();
}
}
return( idAI::Pain(inflictor, attacker, damage, dir, location) );
}
void hhHarvesterSimple::Event_StartPreDeath(void) {
int i;
// No torso? Just kill myself .....
if(!spawnArgs.GetString("def_torso")) {
ProcessEvent(&AI_Kill);
return;
}
// Spawn death fx, if any
const char *fx = spawnArgs.GetString("fx_death");
if (fx && fx[0]) {
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone(true);
BroadcastFxInfo(fx, GetOrigin(), GetAxis(), &fxInfo);
}
// do blood splats
float size = spawnArgs.GetFloat("decal_torso_pop_size","96");
// copy my target keys to the keys that will spawn the torso
idDict dict;
const idDict *torsoDict = gameLocal.FindEntityDefDict(spawnArgs.GetString("def_torso"));
if ( !torsoDict ) {
gameLocal.Error("Unknown def_torso: %s\n", spawnArgs.GetString("def_torso"));
}
dict.Copy(*torsoDict);
for(i=0;i<targets.Num();i++)
{
if(!targets[i].GetEntity()) {
continue;
}
idStr key("target");
if(i > 0) {
sprintf(key, "target%i", i);
}
dict.Set((const char*)key, (const char*)targets[i].GetEntity()->name);
}
// Passageway variables
dict.SetInt("passage_health", AI_PASSAGEWAY_HEALTH);
dict.SetInt("passage_count", passageCount);
dict.SetVector("origin", GetOrigin());
dict.SetMatrix("rotation", GetAxis());
// remove my target keys (so they don't get fired)
targets.Clear();
// Spawn the torso
idEntity *e;
hhMonsterAI *aiTorso;
if(!gameLocal.SpawnEntityDef(dict, &e))
gameLocal.Error("Failed to spawn ai torso.");
HH_ASSERT(e && e->IsType(hhMonsterAI::Type));
aiTorso = static_cast<hhMonsterAI*>(e);
HH_ASSERT(aiTorso != NULL);
// Throw gibs
idStr debrisDef = spawnArgs.GetString("def_gibDebrisSpawnerPreDeath");
if(debrisDef.Length() > 0) {
hhUtils::SpawnDebrisMass(debrisDef.c_str(), this, 1.0f);
}
health = 0;
// remove myself
Hide();
PostEventMS(&EV_Remove, 3000);
}
void hhHarvesterSimple::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
if ( attacker == this ) {
return;
}
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
if ( !AI_DEAD ) {
if ( damageDef && damageDef->GetBool( "ice" ) && spawnArgs.GetBool( "can_freeze", "0" ) ) {
spawnArgs.Set( "bAlwaysGib", "0" );
allowPreDeath = false;
} else {
allowPreDeath = true;
}
if ( damageDef && damageDef->GetBool( "no_special_death" ) ) {
allowPreDeath = false;
}
}
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
}
int hhHarvesterSimple::EvaluateReaction( const hhReaction *react ) {
// Let the script limit the distance of Climb reactions we consider
if ( react->desc->effect == hhReactionDesc::Effect_Climb && AI_CLIMB_RANGE >= 0.0f && ( react->causeEntity->GetOrigin() - GetOrigin()).LengthSqr() > AI_CLIMB_RANGE ) {
return 0;
}
// If we're supposed to use a specific passageway, only accept it and reject the others
if ( nextPassageway.IsValid() && react->desc->effect == hhReactionDesc::Effect_Passageway ) {
if (react->causeEntity.GetEntity() == nextPassageway.GetEntity()) {
return 100;
} else {
return 0;
}
}
int rank = hhMonsterAI::EvaluateReaction( react );
if ( react->desc->effect == hhReactionDesc::Effect_Passageway &&
react->causeEntity.GetEntity() == lastPassageway.GetEntity() ) {
if ( lastPassagewayTime + 10000 > gameLocal.time ) {
if (rank > 10) {
// Discourage entering the same passageway we just left
return 10;
}
} else {
// Ignore previous passageway for 10 seconds
return 0;
}
}
return rank;
}
#define CheckPassageFreqInitial 6000
void hhHarvesterSimple::Event_EnterPassageway(hhAIPassageway *pn) {
CancelEvents( &MA_OnProjectileLaunch ); // Clear any anti-projectile attacks
CancelEvents( &MA_AntiProjectileAttack ); // Clear any anti-projectile attacks
if (nextPassageway.IsValid()) {
if (nextPassageway.GetEntity() != pn) {
gameLocal.Warning("hhAIPassageway entered was not the specified one!\n");
}
nextPassageway.Clear();
}
if(currPassageway != NULL) {
gameLocal.Error("%s tried to ENTER a passageway but already had a passageway!", (const char*)name);
}
HH_ASSERT(currPassageway == NULL);
Hide(); // Should already be hidden but just to make sure
// Only consider passageCount if damaged (ignores scripted passage sequences) or if it's the torso
if (health < spawnHealth || !idStr::Icmp(spawnArgs.GetString("classname"), "monster_harvester_torso") ) {
passageCount++;
if (passageCount > 1) {
//TODO make this affected by the DDA system
AI_PASSAGEWAY_HEALTH = AI_PASSAGEWAY_HEALTH * 0.75f; // Reduce passageway seeking health level to 3/4 of it's original value
}
}
GetAnimator()->ClearAllAnims(gameLocal.GetTime(), 0);
Event_AnimState(ANIMCHANNEL_LEGS, "Legs_Idle", (int)0);
Event_AnimState(ANIMCHANNEL_TORSO, "Torso_Idle", (int)0);
torsoAnim.UpdateState();
legsAnim.UpdateState();
StartSound("snd_inside_passage", SND_CHANNEL_VOICE, SSF_LOOPING, true, NULL);
currPassageway = pn;
if(GetPhysics())
GetPhysics()->SetContents(0);
// Does this passage way give us health?
int h = 0;
pn->spawnArgs.GetInt("give_health", "0", h);
health += h;
health = idMath::ClampInt(0, spawnArgs.GetInt("health"), health);
// Should we transform to another monster when entering?
idStr transTo;
if(spawnArgs.GetString("passage_transform_to", "", transTo)) {
const idDict *def = gameLocal.FindEntityDefDict( transTo );
if(!def) {
gameLocal.Error("Unknown def : %s", (const char*)transTo);
}
// copy my target keys to the keys of the transformed-to entity
idDict dict;
dict.Copy(*def);
for(int i=0;i<targets.Num();i++)
{
if(!targets[i].GetEntity())
continue;
idStr key("target");
if(i > 0)
sprintf(key, "target%i", i);
dict.Set((const char*)key, (const char*)targets[i].GetEntity()->name);
}
// Passageway variables
dict.SetInt("passage_health", AI_PASSAGEWAY_HEALTH);
dict.SetInt("passage_count", passageCount);
idEntity *e = NULL;
gameLocal.SpawnEntityDef(dict, &e);
HH_ASSERT( e->IsType( hhHarvesterSimple::Type ) );
hhHarvesterSimple *ai = static_cast<hhHarvesterSimple*>(e);
ai->SetOrigin(GetOrigin());
ai->SetAxis(GetAxis());
ai->Event_EnterPassageway(pn);
targets.Clear();
PostEventSec(&EV_Remove, 0.1f);
return;
}
PostEventMS(&MA_HandlePassageway, CheckPassageFreqInitial);
}
void hhHarvesterSimple::Event_ExitPassageway(hhAIPassageway *pn) {
if(currPassageway == NULL) {
gameLocal.Error("%s tried to EXIT a passageway but did NOT have a curr passageway!", (const char*)name);
}
HH_ASSERT(currPassageway != NULL);
// Store this passageway so we don't jump right back into it.
lastPassageway = idEntityPtr<idEntity> (pn);
lastPassagewayTime = gameLocal.time;
if(GetPhysics())
GetPhysics()->SetContents(CONTENTS_BODY);
currPassageway = NULL;
AI_ACTIVATED = true; // Sometimes this is NOT true?!?!
StopSound(SND_CHANNEL_VOICE, true);
// Teleport to new pos
idAngles angs = pn->GetAxis().ToAngles();
idVec3 pos = pn->GetExitPos();
Teleport( pos, angs, pn );
Show();
current_yaw = angs.yaw;
ideal_yaw = angs.yaw;
turnVel = 0.0f;
HH_ASSERT(FacingIdeal());
// Exit anim to play?
idStr exitAnim = pn->spawnArgs.GetString("exit_anim");
if(exitAnim.Length() && GetAnimator()->HasAnim(exitAnim)) {
GetAnimator()->ClearAllAnims(gameLocal.GetTime(), 0);
torsoAnim.UpdateState();
legsAnim.UpdateState();
torsoAnim.PlayAnim( GetAnimator()->GetAnim( exitAnim ) );
legsAnim.PlayAnim( GetAnimator()->GetAnim( exitAnim ) );
}
}
//
// Event_HandlePassageway()
//
#define MaxExits 32
#define CheckPassageFreq 3000
void hhHarvesterSimple::Event_HandlePassageway(void) {
if(currPassageway == NULL) {
gameLocal.Error("%s tried to handle a passageway but did NOT have a passageway!", (const char*)name);
}
HH_ASSERT(currPassageway != NULL);
hhAIPassageway *exitNode = NULL;
// CATCH 'went inside hole - never came out' bug
if(currPassageway.GetEntity()->lastEntered == this && gameLocal.GetTime() - currPassageway.GetEntity()->timeLastEntered > 30000) {
gameLocal.Warning("%s has been stuck in a passageway for >30 secs, killing it off.", (const char*)name);
fl.takedamage = true;
// Use hhMonsterAI::Damage because our Damage returns if we're the attacker
hhMonsterAI::Damage(this, this, vec3_origin, "damage_gib", 1.0f, INVALID_JOINT);
return;
}
// No other way out - gotta go out the way we came in
if(currPassageway->targets.Num() <= 0) {
exitNode = currPassageway.GetEntity();
}
// We can go out another way
else {
hhAIPassageway *possibleExits[MaxExits];
hhAIPassageway *tmp;
int count = 0;
bool isRandom;
if (gameLocal.GetTime() - currPassageway.GetEntity()->timeLastEntered > SEC2MS(10)) {
// Try to prevent us from being stuck after 10 seconds
isRandom = true;
} else {
// Choose possibleExits[] randomly if we have no enemy or based on chance. Otherwise choose based on line-of-sight to the player
isRandom = !enemy.IsValid() || gameLocal.random.RandomInt(100) > 50;
}
trace_t tr;
idVec3 toPos;
if (!isRandom) {
toPos = enemy->GetOrigin();
}
// We've tried once, now we can use our entrance as an exit
if(gameLocal.GetTime() - currPassageway.GetEntity()->timeLastEntered > CheckPassageFreqInitial + 1000) {
count = 1;
possibleExits[0] = currPassageway.GetEntity(); // We can always go out the same way we came in
}
for(int i=0;i<currPassageway->targets.Num();i++) {
if(currPassageway->targets[i] != NULL && currPassageway->targets[i].GetEntity()->IsType(hhAIPassageway::Type)) {
if (isRandom) {
possibleExits[count++] = static_cast<hhAIPassageway*>(currPassageway->targets[i].GetEntity());
} else {
tmp = static_cast<hhAIPassageway*>(currPassageway->targets[i].GetEntity());
// Choose based on visibility to our enemy
gameLocal.clip.TracePoint( tr, tmp->GetOrigin(), toPos, MASK_SHOT_BOUNDINGBOX, tmp );
if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == enemy.GetEntity() ) ) {
lastVisibleEnemyPos = toPos; // Can now see enemy
possibleExits[count++] = tmp;
}
}
}
// We've got enough
if(count >= MaxExits)
break;
}
if(count == 0) {
exitNode = currPassageway.GetEntity();
} else if ( enemy.IsValid() && gameLocal.random.RandomInt(100) > 70 ) {
// Find the one closest to the last known enemy pos
if (!exitNode) {
float bestDistance = -1.0f, distSq;
for (int i = 0; i < count; i++) {
distSq = ( possibleExits[i]->GetOrigin() - lastVisibleEnemyPos ).LengthSqr();
if ( bestDistance == -1.0f || distSq < bestDistance ) {
exitNode = possibleExits[i];
bestDistance = distSq;
}
}
}
} else {
// Pick a random one
int randExit = gameLocal.random.RandomInt(count); // TODO: Randomness isn't very random! Fix!
HH_ASSERT(randExit >= 0 && randExit < count);
exitNode = possibleExits[randExit];
}
}
if(!exitNode)
exitNode = currPassageway.GetEntity();
// The one we picked is disabled, so go out where we came in
// TODO: make this time based, try a few more times before going back out
if(!exitNode->IsPassagewayEnabled()) {
exitNode = currPassageway.GetEntity();
}
// Special case: The passageway is never meant to be exited from, use it's specified exit point instead
const char *altPassage = exitNode->spawnArgs.GetString("force_passageway", "");
if (altPassage && altPassage[0]) {
idEntity *node = gameLocal.FindEntity(altPassage);
if (node && node->IsType(hhAIPassageway::Type)) {
exitNode = reinterpret_cast<hhAIPassageway *> (node);
}
}
// Make sure no one is blocking where we want to go out
idBounds myBnds = GetPhysics()->GetBounds();
myBnds.Expand(12.0f);
myBnds.TranslateSelf(exitNode->GetExitPos());
idEntity *ents[MAX_GENTITIES];
int count = gameLocal.clip.EntitiesTouchingBounds(myBnds, -1, ents, MAX_GENTITIES);
for(int i=0;i<count;i++) {
// We'll have to try again later when the coast is clear
if(ents[i] && ents[i] != this && !ents[i]->IsHidden() && (ents[i]->IsType(idActor::Type) || ents[i]->IsType(hhMoveable::Type))) {
// Chunk moveables
if ( ents[i]->IsType(idMoveable::Type) ) {
ents[i]->Damage( this, this, vec3_origin, "damage_gib", 1.0f, INVALID_JOINT );
ents[i]->SquishedByDoor(this);
continue;
}
gameLocal.Warning("Passageway exit blocked.\n");
PostEventMS(&MA_HandlePassageway, CheckPassageFreq);
if(ai_debugBrain.GetInteger() != 0) {
gameRenderWorld->DebugBounds(colorYellow, myBnds, vec3_origin, 2000);
}
return;
}
}
// Else we can just exit now - its safe
exitNode->ProcessEvent(&EV_Activate, this);
}
#define LinkScriptVariable( name ) name.LinkTo(scriptObject, #name)
void hhHarvesterSimple::LinkScriptVariables() {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable(AI_CLIMB_RANGE);
LinkScriptVariable(AI_PASSAGEWAY_HEALTH);
}
void hhHarvesterSimple::Event_UseThisPassageway(hhAIPassageway *pn, bool force) {
nextPassageway.Assign(pn);
if (force) { // Snap to position
Event_FindReaction("passageway");
hhReaction *reaction = targetReaction.GetReaction();
if (!reaction) {
gameLocal.Warning("useThisPassageway could not find a valid reaction!\n");
} else {
idVec3 tp = GetTouchPos( reaction->causeEntity.GetEntity(), reaction->desc );
SetOrigin(tp);
}
}
}
/*
=====================
hhHarvesterSimple::Save
=====================
*/
void hhHarvesterSimple::Save( idSaveGame *savefile ) const {
savefile->WriteBool( allowPreDeath );
savefile->WriteInt( lastAntiProjectileAttack );
savefile->WriteInt( passageCount );
savefile->WriteBool( bGibOnDeath );
savefile->WriteInt( lastPassagewayTime );
lastPassageway.Save( savefile );
nextPassageway.Save( savefile );
}
/*
=====================
hhHarvesterSimple::Restore
=====================
*/
void hhHarvesterSimple::Restore( idRestoreGame *savefile ) {
savefile->ReadBool( allowPreDeath );
savefile->ReadInt( lastAntiProjectileAttack );
savefile->ReadInt( passageCount );
savefile->ReadBool( bGibOnDeath );
savefile->ReadInt( lastPassagewayTime );
lastPassageway.Restore( savefile );
nextPassageway.Restore( savefile );
bSmokes = spawnArgs.GetBool("smokes", "0");
}
void hhHarvesterSimple::SpawnSmoke(void) {
const char *bones[MAX_HARVESTER_LEGS];
bones[0] = spawnArgs.GetString( "bone_smoke_front_left" );
bones[1] = spawnArgs.GetString( "bone_smoke_front_right" );
bones[2] = spawnArgs.GetString( "bone_smoke_rear_left" );
bones[3] = spawnArgs.GetString( "bone_smoke_rear_right" );
const char *psystem = spawnArgs.GetString( "fx_smoke" );
if ( psystem && *psystem ) {
idVec3 bonePos;
idMat3 boneAxis;
for(int i = 0; i < MAX_HARVESTER_LEGS; i++) {
if( fxSmoke[i] != NULL ) {
gameLocal.Warning("Harvester already had smoke particles for leg %i.\n", i);
continue;
}
hhFxInfo fxInfo;
this->GetJointWorldTransform( bones[i], bonePos, boneAxis );
fxInfo.SetEntity( this );
fxInfo.SetBindBone( bones[i] );
fxInfo.Toggle();
fxInfo.RemoveWhenDone( false );
BroadcastFxInfo( psystem, bonePos, boneAxis, &fxInfo, &EV_Broadcast_AppendFxToList );
}
}
}
void hhHarvesterSimple::ClearSmoke(void) {
for(int i=0; i < MAX_HARVESTER_LEGS; i++) {
if(fxSmoke[i].IsValid()) {
fxSmoke[i]->Nozzle(false);
}
}
for(int i = 0; i < MAX_HARVESTER_LEGS; i++) {
SAFE_REMOVE(fxSmoke[MAX_HARVESTER_LEGS]);
}
}
void hhHarvesterSimple::Event_AppendFxToList(hhEntityFx *fx) {
for(int i = 0; i < MAX_HARVESTER_LEGS; ++i) {
if(fxSmoke[i] != NULL) {
continue;
}
fxSmoke[i] = fx;
return;
}
}
void hhHarvesterSimple::Event_GibOnDeath(const idList<idStr>* parmList) {
bGibOnDeath = (atoi((*parmList)[0].c_str()) != 0);
}
void hhHarvesterSimple::Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location) {
ClearSmoke();
hhMonsterAI::Killed(inflictor, attacker, damage, dir, location);
if (bGibOnDeath) {
Gib(vec3_origin, "damage_gib");
}
}
void hhHarvesterSimple::Event_Activate(idEntity *activator) {
if (fl.hidden) {
// If we're hidden, we're probably birthing out of passageway. Figure out which one.
hhAIPassageway *nearest = NULL;
float dist, nearDist = idMath::INFINITY;
hhAIPassageway *passage = reinterpret_cast<hhAIPassageway *> (gameLocal.FindEntityOfType( hhAIPassageway::Type, NULL ));
while (passage) {
dist = (passage->GetOrigin() - GetOrigin()).Length();
if (dist < nearDist) {
nearDist = dist;
nearest = passage;
}
passage = reinterpret_cast<hhAIPassageway *> (gameLocal.FindEntityOfType( hhAIPassageway::Type, passage ));
}
// If we found one near us and it's near enough, mark it as our last passageway
if (nearest && nearDist < 250.0f) {
lastPassageway = nearest;
lastPassagewayTime = gameLocal.time;
}
}
hhMonsterAI::Event_Activate(activator);
}
void hhHarvesterSimple::AnimMove( void ) {
idVec3 goalPos;
idVec3 delta;
idVec3 goalDelta;
float goalDist;
monsterMoveResult_t moveResult;
idVec3 newDest;
// Turn on physics to prevent flying harvesters
BecomeActive(TH_PHYSICS);
idVec3 oldorigin = physicsObj.GetOrigin();
#ifdef HUMANHEAD //jsh wallwalk
idMat3 oldaxis = GetGravViewAxis();
#else
idMat3 oldaxis = viewAxis;
#endif
AI_BLOCKED = false;
if ( move.moveCommand < NUM_NONMOVING_COMMANDS ){
move.lastMoveOrigin.Zero();
move.lastMoveTime = gameLocal.time;
}
move.obstacle = NULL;
if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemy.GetEntity() ) {
TurnToward( lastVisibleEnemyPos );
goalPos = oldorigin;
} else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) {
TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() );
goalPos = oldorigin;
} else if ( GetMovePos( goalPos ) ) {
if ( move.moveCommand != MOVE_WANDER ) {
CheckObstacleAvoidance( goalPos, newDest );
TurnToward( newDest );
} else {
TurnToward( goalPos );
}
}
Turn();
if ( move.moveCommand == MOVE_SLIDE_TO_POSITION ) {
if ( gameLocal.time < move.startTime + move.duration ) {
goalPos = move.moveDest - move.moveDir * MS2SEC( move.startTime + move.duration - gameLocal.time );
delta = goalPos - oldorigin;
delta.z = 0.0f;
} else {
delta = move.moveDest - oldorigin;
delta.z = 0.0f;
StopMove( MOVE_STATUS_DONE );
}
} else if ( allowMove ) {
#ifdef HUMANHEAD //jsh wallwalk
GetMoveDelta( oldaxis, GetGravViewAxis(), delta );
#else
GetMoveDelta( oldaxis, viewAxis, delta );
#endif
} else {
delta.Zero();
}
if ( move.moveCommand == MOVE_TO_POSITION ) {
goalDelta = move.moveDest - oldorigin;
goalDist = goalDelta.LengthFast();
if ( goalDist < delta.LengthFast() ) {
delta = goalDelta;
}
}
#ifdef HUMANHEAD //shrink functionality
float scale = renderEntity.shaderParms[SHADERPARM_ANY_DEFORM_PARM1];
if ( scale > 0.0f && scale < 2.0f ) {
delta *= scale;
}
#endif
physicsObj.SetDelta( delta );
physicsObj.ForceDeltaMove( disableGravity );
RunPhysics();
if ( ai_debugMove.GetBool() ) {
// HUMANHEAD JRM - so we can see if grav is on or off
if(disableGravity) {
gameRenderWorld->DebugLine( colorRed, oldorigin, physicsObj.GetOrigin(), 5000 );
} else {
gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 5000 );
}
}
moveResult = physicsObj.GetMoveResult();
if ( !af_push_moveables && attack.Length() && TestMelee() ) {
DirectDamage( attack, enemy.GetEntity() );
} else {
idEntity *blockEnt = physicsObj.GetSlideMoveEntity();
if ( blockEnt && blockEnt->IsType( hhHarvesterSimple::Type ) ) {
StopMove( MOVE_STATUS_BLOCKED_BY_MONSTER );
return;
}
if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) {
KickObstacles( viewAxis[ 0 ], kickForce, blockEnt );
}
}
BlockedFailSafe();
AI_ONGROUND = physicsObj.OnGround();
idVec3 org = physicsObj.GetOrigin();
if ( oldorigin != org ) {
TouchTriggers();
}
if ( ai_debugMove.GetBool() ) {
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), org, gameLocal.msec );
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec );
gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true );
DrawRoute();
}
}
void hhHarvesterSimple::Event_CanBecomeSolid( void ) {
int i;
int num;
idEntity * hit;
idClipModel *cm;
idClipModel *clipModels[ MAX_GENTITIES ];
num = gameLocal.clip.ClipModelsTouchingBounds( physicsObj.GetAbsBounds(), MASK_MONSTERSOLID, clipModels, MAX_GENTITIES );
for ( i = 0; i < num; i++ ) {
cm = clipModels[ i ];
// don't check render entities
if ( cm->IsRenderModel() ) {
continue;
}
hit = cm->GetEntity();
if ( hit == this ) {
continue;
}
// Special case, crush any moveables blocking our start point
if ( hit->IsType( idMoveable::Type ) ) {
hit->Damage( this, this, vec3_origin, "damage_gib", 1.0f, INVALID_JOINT );
hit->SquishedByDoor(this);
}
if ( !hit->fl.takedamage ) {
continue;
}
if ( physicsObj.ClipContents( cm ) ) {
idThread::ReturnFloat( false );
return;
}
}
idThread::ReturnFloat( true );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+79
View File
@@ -0,0 +1,79 @@
#ifndef __PREY_AI_HARVESTERSIMPLE_H__
#define __PREY_AI_HARVESTERSIMPLE_H__
extern const idEventDef AI_OnProjectileLaunch;
extern const idEventDef MA_EnterPassageway;
extern const idEventDef MA_ExitPassageway;
#define MAX_HARVESTER_LEGS 4
class hhHarvesterSimple : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhHarvesterSimple);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
virtual void Event_StartPreDeath(void) {};
void Event_OnProjectileLaunch(hhProjectile *proj) {};
void Event_AntiProjectileAttack(hhProjectile *proj) {};
void Event_EnterPassageway(hhAIPassageway *pn) {};
void Event_ExitPassageway(hhAIPassageway *pn) {};
void Event_HandlePassageway(void) {};
void Event_UseThisPassageway(hhAIPassageway *pn, bool force) {};
void Event_AppendFxToList(hhEntityFx *fx) {};
void Event_GibOnDeath(const idList<idStr>* parmList) {};
virtual void Event_Activate(idEntity *activator) {};
virtual void Event_CanBecomeSolid(void) {};
#else
virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
virtual void LinkScriptVariables(void);
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
virtual void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location);
protected:
void Spawn(void);
virtual int EvaluateReaction( const hhReaction *react );
void SpawnSmoke(void);
void ClearSmoke(void);
//predeath torso code
virtual void Event_StartPreDeath(void);
virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
bool allowPreDeath; // TRUE if we will allow predeath
virtual void AnimMove(void);
//anti-projectile chaff
void Event_OnProjectileLaunch(hhProjectile *proj);
void Event_AntiProjectileAttack(hhProjectile *proj);
void Event_EnterPassageway(hhAIPassageway *pn);
void Event_ExitPassageway(hhAIPassageway *pn);
void Event_HandlePassageway(void);
void Event_UseThisPassageway(hhAIPassageway *pn, bool force);
void Event_AppendFxToList(hhEntityFx *fx);
void Event_GibOnDeath(const idList<idStr>* parmList);
virtual void Event_Activate(idEntity *activator);
virtual void Event_CanBecomeSolid(void);
int lastAntiProjectileAttack;
int lastPassagewayTime;
idEntityPtr<idEntity> lastPassageway;
idEntityPtr<idEntity> nextPassageway;
idScriptFloat AI_CLIMB_RANGE;
idScriptFloat AI_PASSAGEWAY_HEALTH;
idEntityPtr<hhEntityFx> fxSmoke[MAX_HARVESTER_LEGS];
int passageCount;
bool bSmokes;
bool bGibOnDeath;
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
#ifndef __PREY_AI_HUNTER_SIMPLE_H__
#define __PREY_AI_HUNTER_SIMPLE_H__
#define HUNTER_N 0
#define HUNTER_NE 1
#define HUNTER_E 2
#define HUNTER_SE 3
#define HUNTER_S 4
#define HUNTER_SW 5
#define HUNTER_W 6
#define HUNTER_NW 7
class hhHunterSimple : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhHunterSimple);
hhHunterSimple();
void Event_OnProjectileLaunch(hhProjectile *proj);
void Event_OnProjectileHit(hhProjectile *proj);
void Event_LaserOn();
void Event_LaserOff();
void Event_FindReaction( const char* effect );
void Spawn();
void Think();
idProjectile *LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef );
void AnimMove();
bool UpdateAnimationControllers();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
virtual void PrintDebug();
virtual void LinkScriptVariables();
bool TurnToward( const idVec3 &pos );
virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
bool StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length );
void SetNextVoiceTime( int newTime ) { nextVoiceTime = newTime; }
void Show();
void BlockedFailSafe();
void UpdateEnemyPosition();
void Distracted( idActor *newEnemy );
bool ReachedPos( const idVec3 &pos, const moveCommand_t moveCommand ) const;
void Event_EscapePortal();
void Event_AssignSniperFx( hhEntityFx* fx );
void Event_AssignMuzzleFx( hhEntityFx* fx );
void Event_AssignFlashLightFx( hhEntityFx* fx );
void Event_KickAngle( const idAngles &ang );
void Event_FlashLightOn();
void Event_FlashLightOff();
void Event_PostSpawn();
void Event_EnemyCanSee();
void Event_PrintAction( const char *action );
void Event_GetAlly();
void Event_TriggerDelay( idEntity *ent, float delay );
void Event_CallBackup( float delay );
virtual bool CanSee( idEntity *ent, bool useFov );
void Event_GetAdvanceNode();
void Event_GetRetreatNode();
void Event_OnProjectileLand(hhProjectile *proj);
void Event_SaySound( const char *soundName );
void Event_CheckRush();
void Event_CheckRetreat();
void Event_SayEnemyInfo();
void Event_SetNextVoiceTime( int nextTime );
void Event_GiveOrders( const char *orders );
void Event_AllowOrders( bool orders );
void Event_GetCoverNode();
void Event_GetCoverPoint();
void Event_GetSightNode();
void Event_GetNearSightPoint();
void Event_Blocked();
void Event_EnemyPortal( idEntity *portal );
void Event_GetEnemyPortal();
void Event_EnemyVehicleDocked();
void Event_EnemyIsSpirit( hhPlayer *player, hhSpiritProxy *proxy ); //HUMANHEAD jsh PCF 5/2/06 hunter combat fixes
idEntityPtr<hhMonsterAI> ally;
idScriptBool AI_ALLOW_ORDERS;
idScriptBool AI_SHOTBLOCK;
protected:
idVec3 nextMovePos;
idEntityPtr<hhBeamSystem> beamLaser;
idAngles kickAngles;
idAngles kickSpeed;
idEntityPtr<hhEntityFx> sniperFx;
idEntityPtr<hhEntityFx> muzzleFx;
idEntityPtr<hhEntityFx> flashLightFx;
idList< idEntityPtr< idEntity > > nodeList;
bool alternateAccuracy;
bool bFlashLight;
idScriptInt AI_DIR;
idScriptFloat AI_LAST_DAMAGE_TIME;
idStr currentAction;
idStr currentSpeech;
int endSpeechTime;
idScriptBool AI_DIR_MOVEMENT;
idScriptBool AI_ENEMY_RUSH;
idScriptBool AI_ENEMY_RETREAT;
idScriptBool AI_ENEMY_HEALTH_LOW;
idScriptBool AI_ENEMY_RESURRECTED;
idScriptBool AI_ONGROUND;
idScriptBool AI_ENEMY_SHOOTABLE;
idScriptBool AI_BLOCKED_FAILSAFE;
idScriptInt AI_ENEMY_LAST_SEEN;
idScriptInt AI_NEXT_DIR_TIME;
idScriptBool AI_KNOCKBACK;
int nextEnemyCheck;
float lastEnemyDistance;
int enemyRushCount;
int enemyRetreatCount;
int enemyHiddenCount;
int lastChargeTime;
int nextVoiceTime;
idVec3 initialOrigin;
float flashlightLength;
int flashlightTime;
idEntityPtr<idEntity> enemyPortal;
idVec3 lastMoveOrigin;
int nextBlockCheckTime;
int nextSpiritCheck; //HUMANHEAD jsh PCF 5/2/06 hunter combat fixes
};
#endif /* __PREY_AI_HUNTER_SIMPLE_H__ */
+136
View File
@@ -0,0 +1,136 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef MA_CheckReactions( "<checkreactions>", "e" );
CLASS_DECLARATION( hhMonsterAI, hhAIInspector )
EVENT( EV_PostSpawn, hhAIInspector::Event_PostSpawn )
EVENT( MA_CheckReactions, hhAIInspector::Event_CheckReactions )
END_CLASS
void hhAIInspector::Spawn() {
}
void hhAIInspector::Event_PostSpawn() {
const function_t* func = GetScriptFunction( "state_InspectorIdle" );
if( !func ) {
gameLocal.Warning( "unable to find state_InspectorIdle" );
return;
}
SetState( func );
}
void hhAIInspector::CheckReactions( idEntity* entity ) {
PostEventMS( &MA_CheckReactions, 1000, entity );
}
void hhAIInspector::Event_CheckReactions( idEntity* entity ) {
checkReaction = entity;
targetReaction.entity = entity;
targetReaction.reactionIndex = 0;
if( !targetReaction.GetReaction() ) {
targetReaction.reactionIndex = -1;
gameLocal.Warning( "unable to properly use requested reaction... possibly no reactions on this entity" );
return;
}
const function_t* func = GetScriptFunction( "state_InspectorReactions" );
if( !func ) {
gameLocal.Warning( "unable to find checkreaction state on inspector..." );
return;
}
SetState( func );
}
void hhAIInspector::RestartInspector( const char* inspectClass, idEntity* newReaction, idPlayer* starter ) {
float yaw;
idVec3 org;
idDict spawnDict;
idEntity* react_scout;
idEntity* use_reaction = NULL;
//Find our dictionary to use
const idDict* edict = gameLocal.FindEntityDefDict( inspectClass, false );
if( !edict ) {
gameLocal.Printf( "Unable to find entitfydef '%s'", inspectClass );
return;
}
spawnDict = *edict; //copy the values to an editable dict
//Setup values for position/orientation
yaw = starter->viewAngles.yaw;
org = starter->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 180 + idVec3( 0, 0, 1 );
// Set dictionary values...
spawnDict.Set( "angle", va("%f", yaw + 180) );
spawnDict.Set( "origin", org.ToString() );
spawnDict.Set( "spawnClass", "hhAIInspector" );
// Perform actual spawn
react_scout = static_cast<hhAIInspector*>(gameLocal.SpawnEntityType(hhAIInspector::Type, &spawnDict));
if( !react_scout ) {
gameLocal.Printf( "failed to spawn inspector monster..." );
return;
}
use_reaction = newReaction;
if( gameLocal.inspector != NULL ) {
//save our old use_reaction if we haven't specified one
if( !use_reaction && gameLocal.inspector.IsValid() && gameLocal.inspector->checkReaction.IsValid() ) {
use_reaction = gameLocal.inspector->checkReaction.GetEntity();
}
// Remove our old inspector
gameLocal.inspector->PostEventMS( &EV_Remove, 0 );
}
gameLocal.inspector = react_scout;
if( use_reaction ) {
gameLocal.inspector->CheckReactions( use_reaction );
}
}
void hhAIInspector::RestartInspector( idEntity* newReaction, idPlayer* starter ) {
idEntity* react_scout;
float yaw;
idVec3 org;
yaw = starter->viewAngles.yaw;
org = starter->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 180 + idVec3( 0, 0, 1 );
idDict dict = gameLocal.inspector.GetEntity()->spawnArgs;
dict.Set( "angle", va("%f", yaw + 180) );
dict.Set( "origin", org.ToString() );
react_scout = static_cast<hhAIInspector*>(gameLocal.SpawnEntityType(hhAIInspector::Type, &dict));
if( !react_scout ) {
gameLocal.Printf( "failed to spawn inspector monster..." );
return;
}
if( gameLocal.inspector != NULL ) {
gameLocal.inspector->PostEventMS( &EV_Remove, 0 );
}
gameLocal.inspector = react_scout;
gameLocal.inspector->CheckReactions( newReaction );
}
/*
=====================
hhAIInspector::Save
=====================
*/
void hhAIInspector::Save( idSaveGame *savefile ) const {
checkReaction.Save( savefile );
}
/*
=====================
hhAIInspector::Restore
=====================
*/
void hhAIInspector::Restore( idRestoreGame *savefile ) {
checkReaction.Restore( savefile );
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef __PREY_AI_INSPECTOR_H__
#define __PREY_AI_INSPECTOR_H__
class hhAIInspector : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhAIInspector);
public:
void Spawn();
void CheckReactions( idEntity* entity );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
static void RestartInspector( const char* inspectClass, idEntity* newReaction, idPlayer* starter );
static void RestartInspector( idEntity* newReaction, idPlayer* starter );
public:
// Events.
void Event_PostSpawn();
void Event_CheckReactions( idEntity* entity );
protected:
idEntityPtr<idEntity> checkReaction;
};
#endif
@@ -0,0 +1,662 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef AI_RemoveJetFx("removeJetFx");
const idEventDef AI_CreateJetFx("createJetFx");
const idEventDef AI_LaunchMine("launchMine", "d");
const idEventDef MA_IsEnemySniping("isEnemySniping", NULL, 'd');
const idEventDef MA_NumMines("numMines", NULL, 'f');
const idEventDef MA_DodgeProjectile("<dodgeProjectile>", "e");
const idEventDef MA_AppendHoverFx( "<appendHoverFx>", "e" );
CLASS_DECLARATION( hhMonsterAI, hhJetpackHarvesterSimple )
EVENT( AI_RemoveJetFx, hhJetpackHarvesterSimple::Event_RemoveJetFx )
EVENT( EV_Activate, hhJetpackHarvesterSimple::Event_Activate)
EVENT( AI_CreateJetFx, hhJetpackHarvesterSimple::Event_CreateJetFx )
EVENT( AI_LaunchMine, hhJetpackHarvesterSimple::Event_LaunchMine )
EVENT( EV_Broadcast_AppendFxToList, hhJetpackHarvesterSimple::Event_AppendToThrusterList )
EVENT( MA_OnProjectileLaunch, hhJetpackHarvesterSimple::Event_OnProjectileLaunch )
EVENT( MA_DodgeProjectile, hhJetpackHarvesterSimple::Event_DodgeProjectile )
EVENT( MA_IsEnemySniping, hhJetpackHarvesterSimple::Event_IsEnemySniping )
EVENT( MA_NumMines, hhJetpackHarvesterSimple::Event_NumMines )
EVENT( MA_AppendHoverFx, hhJetpackHarvesterSimple::Event_AppendHoverFx )
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
hhJetpackHarvesterSimple::~hhJetpackHarvesterSimple() {
for ( int i=0;i<mineList.Num();i++ ) {
if ( mineList[i].IsValid() ) {
trace_t collision;
memset( &collision, 0, sizeof( collision ) );
collision.endAxis = mineList[i]->GetPhysics()->GetAxis();
collision.endpos = mineList[i]->GetPhysics()->GetOrigin();
collision.c.point = mineList[i]->GetPhysics()->GetOrigin();
collision.c.normal.Set( 0, 0, 1 );
mineList[i]->Explode( &collision, idVec3(0,0,0), 0 );
}
}
}
void hhJetpackHarvesterSimple::Spawn(void) {
lastAntiProjectileAttack = gameLocal.GetTime();
for(int i=0;i<ThrustSide_Total;i++) {
fxThrusters[ThrustType_Idle][i] = NULL;
fxThrusters[ThrustType_Hover][i] = NULL;
}
if ( !spawnArgs.GetBool( "bAlwaysGib" ) && !spawnArgs.GetBool( "no_pre_death" ) ) {
allowPreDeath = true;
} else {
allowPreDeath = false;
}
freezeDamage = false;
specialDamage = false;
Event_CreateJetFx();
//give random model offset
float offset_min = spawnArgs.GetFloat( "offset_z_min", "0" );
float offset_max = spawnArgs.GetFloat( "offset_z_max", "0" );
modelOffset.z = gameLocal.random.RandomFloat() * (offset_max-offset_min) + offset_min;
walkIK.Init( this, IK_ANIM, modelOffset );
}
void hhJetpackHarvesterSimple::Event_RemoveJetFx(void) {
for(int i=0;i<ThrustSide_Total;i++) {
SAFE_REMOVE(fxThrusters[ThrustType_Idle][i]);
SAFE_REMOVE(fxThrusters[ThrustType_Hover][i]);
}
}
void hhJetpackHarvesterSimple::Event_CreateJetFx(void) {
const char *bones[ThrustSide_Total];
bones[ThrustSide_Left] = spawnArgs.GetString( "bone_thrust_left" );
bones[ThrustSide_Right] = spawnArgs.GetString( "bone_thrust_right" );
const char *psystem = spawnArgs.GetString( "fx_thruster_idle" );
if ( psystem && *psystem ) {
for(int i=0;i<ThrustSide_Total;i++) {
hhFxInfo fxInfo;
idVec3 bonePos;
idMat3 boneAxis;
this->GetJointWorldTransform( bones[i], bonePos, boneAxis );
fxInfo.SetEntity( this );
fxInfo.SetBindBone( bones[i] );
fxInfo.Toggle();
fxInfo.RemoveWhenDone( false );
if( fxThrusters[ThrustType_Idle][i] != NULL ) {
gameLocal.Warning("Jetpack harvester already had flamejet made.");
}
BroadcastFxInfo( psystem, bonePos, boneAxis, &fxInfo, &EV_Broadcast_AppendFxToList );
}
}
psystem = spawnArgs.GetString( "fx_thruster_hover" );
if ( psystem && *psystem ) {
for(int i=0;i<ThrustSide_Total;i++) {
hhFxInfo fxInfo;
idVec3 bonePos;
idMat3 boneAxis;
GetJointWorldTransform( bones[i], bonePos, boneAxis );
fxInfo.SetEntity( this );
fxInfo.SetBindBone( bones[i] );
fxInfo.Toggle();
fxInfo.RemoveWhenDone( false );
if( fxThrusters[ThrustType_Hover][i] != NULL ) {
gameLocal.Warning("Jetpack harvester already had flamejet made.");
}
BroadcastFxInfo( psystem, bonePos, boneAxis, &fxInfo, &MA_AppendHoverFx );
}
}
}
void hhJetpackHarvesterSimple::Event_AppendToThrusterList( hhEntityFx* fx ) {
for( int ix = 0; ix < ThrustSide_Total; ++ix ) {
if( fxThrusters[ThrustType_Idle][ix] != NULL ) {
continue;
}
fxThrusters[ThrustType_Idle][ix] = fx;
return;
}
}
void hhJetpackHarvesterSimple::Event_AppendHoverFx( hhEntityFx* fx ) {
for( int ix = 0; ix < ThrustSide_Total; ++ix ) {
if( fxThrusters[ThrustType_Hover][ix] != NULL ) {
continue;
}
fxThrusters[ThrustType_Hover][ix] = fx;
return;
}
}
void hhJetpackHarvesterSimple::Event_LaunchMine( const idList<idStr>* parmList ) {
if( !parmList || parmList->Num() != 2 ) {
return;
}
idVec3 jointPos;
idMat3 jointAxis;
const char* projectileDefName = (*parmList)[0].c_str();
const char* jointName = (*parmList)[1].c_str();
if( !projectileDefName || !projectileDefName[0] ) {
return;
}
if( !GetJointWorldTransform(jointName, jointPos, jointAxis) ) {
return;
}
hhHarvesterMine* mine = static_cast<hhHarvesterMine*>( gameLocal.SpawnObject(projectileDefName) );
mine->Create( this, jointPos, jointAxis );
mine->Launch( jointPos, jointAxis, physicsObj.GetPushedLinearVelocity() );
}
void hhJetpackHarvesterSimple::Hide( void ) {
hhMonsterAI::Hide();
for(int i=0;i<ThrustSide_Total;i++) {
if(fxThrusters[ThrustType_Idle][i].GetEntity()) {
fxThrusters[ThrustType_Idle][i]->Nozzle(FALSE);
}
if(fxThrusters[ThrustType_Hover][i].GetEntity()) {
fxThrusters[ThrustType_Hover][i]->Nozzle(FALSE);
}
}
}
void hhJetpackHarvesterSimple::Show( void ) {
hhMonsterAI::Show();
for(int i=0;i<ThrustSide_Total;i++) {
if(fxThrusters[ThrustType_Idle][i].GetEntity()) {
fxThrusters[ThrustType_Idle][i]->Nozzle(TRUE);
}
if(fxThrusters[ThrustType_Hover][i].GetEntity()) {
fxThrusters[ThrustType_Hover][i]->Nozzle(FALSE);
}
}
}
idProjectile *hhJetpackHarvesterSimple::LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef ) { //HUMANHEAD mdc - added desiredProjectileDef for supporting multiple projs.
idVec3 muzzle;
idVec3 dir;
idVec3 start;
trace_t tr;
idBounds projBounds;
float distance;
const idClipModel *projClip;
float attack_accuracy;
float attack_cone;
float projectile_spread;
float diff;
float angle;
float spin;
idAngles ang;
int num_projectiles;
int i;
idMat3 axis;
idVec3 tmp;
idProjectile *lastProjectile;
//HUMANHEAD mdc - added to support multiple projectiles
if( desiredProjectileDef ) { //try to set our projectile to the desiredProjectile
int projIndex = FindProjectileInfo( desiredProjectileDef );
if( projIndex >= 0 ) {
SetCurrentProjectile( projIndex );
}
}
//HUMANHEAD END
if ( !projectileDef ) {
gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
return NULL;
}
attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" );
attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
projectile_spread = desiredProjectileDef->GetFloat( "projectile_spread", "0" );
num_projectiles = desiredProjectileDef->GetInt( "num_projectiles", "1" );
idVec3 launch_velocity = vec3_zero;
if ( desiredProjectileDef->GetFloat( "launch_y", "0" ) > 0.0f ) {
if ( gameLocal.random.RandomFloat() < 0.5 ) {
launch_velocity.y = -desiredProjectileDef->GetFloat( "launch_y", "0" );
} else {
launch_velocity.y = desiredProjectileDef->GetFloat( "launch_y", "0" );
}
launch_velocity *= viewAxis;
}
GetMuzzle( jointname, muzzle, axis );
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, axis[ 0 ] );
}
lastProjectile = projectile.GetEntity();
if ( target != NULL ) {
tmp = target->GetPhysics()->GetAbsBounds().GetCenter() - muzzle;
tmp.Normalize();
axis = tmp.ToMat3();
} else {
axis = viewAxis;
}
// rotate it because the cone points up by default
tmp = axis[2];
axis[2] = axis[0];
axis[0] = -tmp;
// make sure the projectile starts inside the monster bounding box
const idBounds &ownerBounds = physicsObj.GetAbsBounds();
projClip = lastProjectile->GetPhysics()->GetClipModel();
projBounds = projClip->GetBounds().Rotate( axis );
// check if the owner bounds is bigger than the projectile bounds
if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
start = muzzle + distance * viewAxis[ 0 ];
} else {
start = ownerBounds.GetCenter();
}
} else {
// projectile bounds bigger than the owner bounds, so just start it from the center
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this );
muzzle = tr.endpos;
// set aiming direction
GetAimDir( muzzle, target, this, dir );
ang = dir.ToAngles();
// adjust his aim so it's not perfect. uses sine based movement so the tracers appear less random in their spread.
float t = MS2SEC( gameLocal.time + entityNumber * 497 );
ang.yaw += idMath::Sin16( t * 6.7 ) * attack_accuracy;
if ( clampToAttackCone ) {
// clamp the attack direction to be within monster's attack cone so he doesn't do
// things like throw the missile backwards if you're behind him
diff = idMath::AngleDelta( ang.yaw, current_yaw );
if ( diff > attack_cone ) {
ang.yaw = current_yaw + attack_cone;
} else if ( diff < -attack_cone ) {
ang.yaw = current_yaw - attack_cone;
}
}
axis = ang.ToMat3();
float spreadRad = DEG2RAD( projectile_spread );
for( i = 0; i < num_projectiles; i++ ) {
// spread the projectiles out
angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
//dir = axis[ 0 ] + axis[ 2 ] * ( 0 * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir = axis[ 0 ] - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir.Normalize();
// launch the projectile
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, dir );
}
lastProjectile = projectile.GetEntity();
lastProjectile->Launch( muzzle, dir, launch_velocity );
projectile = NULL;
if ( projectileDef->GetBool( "mine", "0" ) ) {
idEntityPtr<hhProjectile> &entityPtr = mineList.Alloc();
entityPtr = lastProjectile;
}
}
TriggerWeaponEffects( muzzle, axis );
lastAttackTime = gameLocal.time;
//HUMANHEAD mdc - added to support multiple projectiles
projectile = NULL;
SetCurrentProjectile( projectileDefaultDefIndex ); //set back to our default projectile to be on the safe side
//HUMANHEAD END
return lastProjectile;
}
void hhJetpackHarvesterSimple::AnimMove( void ) {
idVec3 goalPos;
idVec3 delta;
idVec3 goalDelta;
float goalDist;
monsterMoveResult_t moveResult;
idVec3 newDest;
idVec3 oldorigin = physicsObj.GetOrigin();
#ifdef HUMANHEAD //jsh wallwalk
idMat3 oldaxis = GetGravViewAxis();
#else
idMat3 oldaxis = viewAxis;
#endif
physicsObj.UseFlyMove( false );
AI_BLOCKED = false;
if ( move.moveCommand < NUM_NONMOVING_COMMANDS ){
move.lastMoveOrigin.Zero();
move.lastMoveTime = gameLocal.time;
}
move.obstacle = NULL;
if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemy.GetEntity() ) {
TurnToward( lastVisibleEnemyPos );
goalPos = oldorigin;
} else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) {
TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() );
goalPos = oldorigin;
} else if ( GetMovePos( goalPos ) ) {
if ( move.moveCommand != MOVE_WANDER ) {
CheckObstacleAvoidance( goalPos, newDest );
TurnToward( newDest );
} else {
TurnToward( goalPos );
}
}
Turn();
if ( move.moveCommand == MOVE_SLIDE_TO_POSITION ) {
if ( gameLocal.time < move.startTime + move.duration ) {
goalPos = move.moveDest - move.moveDir * MS2SEC( move.startTime + move.duration - gameLocal.time );
delta = goalPos - oldorigin;
delta.z = 0.0f;
} else {
delta = move.moveDest - oldorigin;
delta.z = 0.0f;
StopMove( MOVE_STATUS_DONE );
}
} else if ( allowMove ) {
#ifdef HUMANHEAD //jsh wallwalk
GetMoveDelta( oldaxis, GetGravViewAxis(), delta );
#else
GetMoveDelta( oldaxis, viewAxis, delta );
#endif
} else {
delta.Zero();
}
if ( move.moveCommand == MOVE_TO_POSITION ) {
goalDelta = move.moveDest - oldorigin;
goalDist = goalDelta.LengthFast();
if ( goalDist < delta.LengthFast() ) {
delta = goalDelta;
}
}
delta *= spawnArgs.GetFloat( "fly_scale", "1.0" );
physicsObj.SetDelta( delta );
physicsObj.ForceDeltaMove( disableGravity );
RunPhysics();
if ( ai_debugMove.GetBool() ) {
// HUMANHEAD JRM - so we can see if grav is on or off
if(disableGravity) {
gameRenderWorld->DebugLine( colorRed, oldorigin, physicsObj.GetOrigin(), 5000 );
} else {
gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 5000 );
}
}
moveResult = physicsObj.GetMoveResult();
if ( !af_push_moveables && attack.Length() && TestMelee() ) {
DirectDamage( attack, enemy.GetEntity() );
} else {
idEntity *blockEnt = physicsObj.GetSlideMoveEntity();
if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) {
KickObstacles( viewAxis[ 0 ], kickForce, blockEnt );
}
}
BlockedFailSafe();
AI_ONGROUND = physicsObj.OnGround();
idVec3 org = physicsObj.GetOrigin();
if ( oldorigin != org ) {
TouchTriggers();
}
if ( ai_debugMove.GetBool() ) {
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), org, gameLocal.msec );
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec );
gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true );
DrawRoute();
}
}
void hhJetpackHarvesterSimple::Event_NumMines() {
//we only want valid mines, so remove dead ones
for ( int i=0;i<mineList.Num();i++ ) {
if ( !mineList[i].IsValid() || mineList[i].GetEntity()->health <= 0 ) {
mineList.RemoveIndex(i);
}
}
idThread::ReturnFloat( float(mineList.Num()) );
}
void hhJetpackHarvesterSimple::Event_DodgeProjectile( hhProjectile *proj ) {
if ( !proj || !enemy.IsValid() ) {
return;
}
float min = spawnArgs.GetFloat( "dda_dodge_min", "0.3" );
float max = spawnArgs.GetFloat( "dda_dodge_max", "0.8" );
float dodgeChance = (min + (max-min)*gameLocal.GetDDAValue() );
if ( ai_debugBrain.GetBool() ) {
gameLocal.Printf( "%s dodge chance %f\n", GetName(), dodgeChance );
}
if ( gameLocal.random.RandomFloat() > dodgeChance ) {
return;
}
idVec3 fw = viewAxis[0];
idVec3 projFw = proj->GetAxis()[0];
if(proj->GetOwner())
projFw = proj->GetOwner()->GetAxis()[0];
float dot = fw * projFw;
if(dot > -.7f)
return;
const function_t *newstate = NULL;
//determine which side to dodge to
idVec3 povPos, targetPos;
povPos = enemy->GetPhysics()->GetOrigin();
targetPos = GetPhysics()->GetOrigin();
idVec3 povToTarget = targetPos - povPos;
povToTarget.z = 0.f;
povToTarget.Normalize();
idVec3 povLeft, povUp;
povToTarget.OrthogonalBasis(povLeft, povUp);
povLeft.Normalize();
idVec3 projVel = proj->GetPhysics()->GetLinearVelocity();
projVel.Normalize();
dot = povLeft * projVel;
if ( dot < 0 ) {
newstate = GetScriptFunction( "state_DodgeRight" );
} else {
newstate = GetScriptFunction( "state_DodgeLeft" );
}
if ( newstate ) {
lastAntiProjectileAttack = gameLocal.GetTime();
SetState( newstate );
UpdateScript();
}
}
void hhJetpackHarvesterSimple::Event_OnProjectileLaunch( hhProjectile *proj ) {
if ( !proj || !spawnArgs.GetBool( "can_dodge", "1" ) || health <= 0 ) {
return;
}
if ( gameLocal.GetTime() - lastAntiProjectileAttack < 1000 * int(spawnArgs.GetFloat( "dodge_freq", "2.0" )) ) {
return;
}
if( proj->GetOwner() && !(ReactionTo(proj->GetOwner()) & (ATTACK_ON_SIGHT | ATTACK_ON_DAMAGE)) ) {
return; // The person who launched this projectile wasn't someone to worry about
}
if ( !enemy.IsValid() ) {
return;
}
PostEventSec( &MA_DodgeProjectile, spawnArgs.GetFloat( "dodge_delay", "0.5" ), proj );
}
bool hhJetpackHarvesterSimple::Collide( const trace_t &collision, const idVec3 &velocity ) {
if ( af.IsActive() && !IsHidden() && !freezeDamage && !specialDamage ) {
const char *fx = spawnArgs.GetString("fx_death");
if ( fx && *fx ) {
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone(true);
BroadcastFxInfo(fx, GetOrigin(), GetAxis(), &fxInfo);
Hide();
PostEventMS(&EV_Remove, 1000);
}
}
return false;
}
void hhJetpackHarvesterSimple::Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
if (!frozen) {
// Being tractored can mess up predeath
fl.canBeTractored = false;
}
HandleNoGore();
if ( AI_DEAD ) {
AI_PAIN = true;
AI_DAMAGE = true;
return;
}
//stop rocket fx and sounds
StopSound( SND_CHANNEL_BODY3, false );
for(int i=0;i<ThrustSide_Total;i++) {
SAFE_REMOVE(fxThrusters[ThrustType_Idle][i]);
SAFE_REMOVE(fxThrusters[ThrustType_Hover][i]);
}
if ( !frozen && allowPreDeath && !AI_BOUND ) {
allowPreDeath = false;
trace_t TraceInfo;
gameLocal.clip.TracePoint(TraceInfo, GetOrigin(), GetOrigin() + GetPhysics()->GetGravityNormal() * 800, MASK_MONSTERSOLID, this);
if( TraceInfo.fraction < 1.0f ) {
if ( HasPathTo( TraceInfo.endpos ) ) {
Event_SetMoveType( MOVETYPE_ANIM );
health += 30;
state = GetScriptFunction( "state_StartPreDeath" );
SetState( state );
SetWaitState( "" );
return;
}
}
}
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
//explode creature's mines upon death
for ( int i=0;i<mineList.Num();i++ ) {
if ( mineList[i].IsValid() ) {
trace_t collision;
memset( &collision, 0, sizeof( collision ) );
collision.endAxis = mineList[i]->GetPhysics()->GetAxis();
collision.endpos = mineList[i]->GetPhysics()->GetOrigin();
collision.c.point = mineList[i]->GetPhysics()->GetOrigin();
collision.c.normal.Set( 0, 0, 1 );
mineList[i]->Explode( &collision, idVec3(0,0,0), 0 );
}
}
}
void hhJetpackHarvesterSimple::Event_IsEnemySniping(void) {
idThread::ReturnInt( false );
}
/*
=====================
hhJetpackHarvesterSimple::Save
=====================
*/
void hhJetpackHarvesterSimple::Save( idSaveGame *savefile ) const {
int i;
for ( i = 0; i < ThrustSide_Total; i++ ) {
for ( int j = 0; j < ThrustType_Total; j++ ) {
fxThrusters[i][j].Save( savefile );
}
}
savefile->WriteInt( lastAntiProjectileAttack );
savefile->WriteBool( allowPreDeath );
int num = mineList.Num();
savefile->WriteInt( num );
savefile->WriteBool( specialDamage );
for ( i = 0; i < num; i++ ) {
mineList[i].Save( savefile );
}
}
/*
=====================
hhJetpackHarvesterSimple::Restore
=====================
*/
void hhJetpackHarvesterSimple::Restore( idRestoreGame *savefile ) {
int i;
for ( i = 0; i < ThrustSide_Total; i++ ) {
for ( int j = 0; j < ThrustType_Total; j++ ) {
fxThrusters[i][j].Restore( savefile );
}
}
savefile->ReadInt( lastAntiProjectileAttack );
savefile->ReadBool( allowPreDeath );
int num;
savefile->ReadInt( num );
savefile->ReadBool( specialDamage );
mineList.SetNum( num );
for ( i = 0; i < num; i++ ) {
mineList[i].Restore( savefile );
}
}
void hhJetpackHarvesterSimple::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
if ( !AI_DEAD ) {
if ( damageDef && damageDef->GetBool( "ice" ) && spawnArgs.GetBool( "can_freeze", "0" ) ) {
freezeDamage = true;
allowPreDeath = false;
} else {
freezeDamage = false;
}
if ( damageDef && damageDef->GetBool( "no_special_death" ) ) {
specialDamage = true;
allowPreDeath = false;
}
}
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
@@ -0,0 +1,66 @@
#ifndef __PREY_AI_JETPACK_HARVESTER_SIMPLE_H__
#define __PREY_AI_JETPACK_HARVESTER_SIMPLE_H__
class hhJetpackHarvesterSimple : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhJetpackHarvesterSimple);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_AppendHoverFx( hhEntityFx* fx ) {};
void Event_AppendToThrusterList( hhEntityFx* fx ) {};
void Event_RemoveJetFx(void) {};
void Event_CreateJetFx(void) {};
void Event_LaunchMine( const idList<idStr>* parmList ) {};
void Event_OnProjectileLaunch( hhProjectile *proj ) {};
void Event_DodgeProjectile( hhProjectile *proj ) {};
void Event_IsEnemySniping(void) {};
void Event_NumMines(void) {};
#else
protected:
enum ThrustSide
{
ThrustSide_Left,
ThrustSide_Right,
ThrustSide_Total
};
enum ThrustType
{
ThrustType_Idle = 0,
ThrustType_Hover,
ThrustType_Total
};
~hhJetpackHarvesterSimple();
void Spawn(void);
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void AnimMove( void );
void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
idProjectile* LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef );
void Event_AppendHoverFx( hhEntityFx* fx );
void Event_AppendToThrusterList( hhEntityFx* fx );
void Event_RemoveJetFx(void);
void Event_CreateJetFx(void);
void Event_LaunchMine( const idList<idStr>* parmList );
void Event_OnProjectileLaunch( hhProjectile *proj );
void Event_DodgeProjectile( hhProjectile *proj );
void Event_IsEnemySniping(void);
void Event_NumMines(void);
virtual void Hide( void );
virtual void Show( void );
virtual bool Collide( const trace_t &collision, const idVec3 &velocity );
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
idEntityPtr<hhEntityFx> fxThrusters[ThrustType_Total][ThrustSide_Total];
int lastAntiProjectileAttack;
bool allowPreDeath;
idList< idEntityPtr<hhProjectile> > mineList;
bool freezeDamage;
bool specialDamage;
#endif
};
#endif
+694
View File
@@ -0,0 +1,694 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef MA_KeeperStartBlast("keeper_StartBlast", "e");
const idEventDef MA_KeeperEndBlast("keeper_EndBlast", NULL);
const idEventDef MA_KeeperUpdateTelepathicThrow("keeper_UpdateTelepathicThrow", NULL, NULL);
const idEventDef MA_KeeperTelepathicThrow("keeper_TelepathicThrow", NULL, NULL);
const idEventDef MA_KeeperStartTeleport("keeper_StartTeleport", NULL);
const idEventDef MA_KeeperEndTeleport("keeper_EndTeleport", NULL);
const idEventDef MA_KeeperTeleportExit("keeper_TeleportExit", NULL);
const idEventDef MA_KeeperCreatePortal("keeper_createPortal", NULL);
const idEventDef MA_KeeperEnableShield("keeper_enableShield", NULL);
const idEventDef MA_KeeperDisableShield("keeper_disableShield", NULL);
const idEventDef MA_KeeperAssignShieldFx( "<assignShieldFx>", "e" );
const idEventDef MA_KeeperTrigger("keeper_Trigger", NULL, NULL);
const idEventDef MA_KeeperTeleportEnter("keeper_TeleportEnter", NULL);
const idEventDef MA_KeeperStartHeadFx("keeper_StartHeadFx");
const idEventDef MA_KeeperEndHeadFx("keeper_EndHeadFx");
const idEventDef MA_KeeperAssignHeadFx( "<assignHeadFx>", "e" );
const idEventDef MA_KeeperGetThrowEntity( "keeper_GetThrowEntity", NULL, 'e' );
const idEventDef MA_KeeperGetTriggerEntity( "keeper_GetTriggerEntity", NULL, 'e' );
const idEventDef MA_KeeperTriggerEntity( "keeper_TriggerEntity", "e" );
const idEventDef MA_KeeperThrowEntity( "keeper_ThrowEntity", "e" );
const idEventDef MA_KeeperForceDisableShield("keeper_forceDisableShield", NULL);
CLASS_DECLARATION( hhMonsterAI, hhKeeperSimple )
EVENT( MA_KeeperStartBlast, hhKeeperSimple::Event_StartBlast )
EVENT( MA_KeeperEndBlast, hhKeeperSimple::Event_EndBlast )
EVENT( MA_KeeperUpdateTelepathicThrow, hhKeeperSimple::Event_UpdateTelepathicThrow )
EVENT( MA_KeeperTelepathicThrow, hhKeeperSimple::Event_TelepathicThrow )
EVENT( MA_KeeperStartTeleport, hhKeeperSimple::Event_StartTeleport )
EVENT( MA_KeeperEndTeleport, hhKeeperSimple::Event_EndTeleport )
EVENT( MA_KeeperTeleportExit, hhKeeperSimple::Event_TeleportExit )
EVENT( MA_KeeperCreatePortal, hhKeeperSimple::Event_CreatePortal )
EVENT( MA_KeeperEnableShield, hhKeeperSimple::Event_EnableShield )
EVENT( MA_KeeperDisableShield, hhKeeperSimple::Event_DisableShield )
EVENT( MA_KeeperAssignShieldFx, hhKeeperSimple::Event_AssignShieldFx )
EVENT( MA_KeeperTrigger, hhKeeperSimple::Event_KeeperTrigger )
EVENT( MA_KeeperTeleportEnter, hhKeeperSimple::Event_TeleportEnter )
EVENT( MA_KeeperStartHeadFx, hhKeeperSimple::Event_StartHeadFx )
EVENT( MA_KeeperEndHeadFx, hhKeeperSimple::Event_EndHeadFx )
EVENT( MA_KeeperAssignHeadFx, hhKeeperSimple::Event_AssignHeadFx )
EVENT( MA_KeeperTriggerEntity, hhKeeperSimple::Event_TriggerEntity )
EVENT( MA_KeeperThrowEntity, hhKeeperSimple::Event_ThrowEntity )
EVENT( MA_KeeperGetTriggerEntity, hhKeeperSimple::Event_GetTriggerEntity )
EVENT( MA_KeeperGetThrowEntity, hhKeeperSimple::Event_GetThrowEntity )
EVENT( MA_KeeperForceDisableShield, hhKeeperSimple::Event_ForceDisableShield )
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
hhKeeperSimple::hhKeeperSimple() {
shieldAlpha = 0.0f;
}
hhKeeperSimple::~hhKeeperSimple() {
idEntity *ent = NULL;
if ( throwEntity.IsValid() ) {
ent = throwEntity.GetEntity();
} else if ( targetReaction.entity.IsValid() ) {
ent = targetReaction.entity.GetEntity();
} else {
return;
}
if ( ent && ent->IsType(hhMoveable::Type)) {
hhMoveable *throwMoveable = static_cast<hhMoveable*>(ent);
if ( throwMoveable ) {
throwMoveable->Event_Unhover();
}
}
}
void hhKeeperSimple::Spawn( void ) {
beamAttack = idEntityPtr<hhBeamSystem> ( hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "beamAttack" ) ) );
if(beamAttack.IsValid()) {
beamAttack->MoveToJoint( this, spawnArgs.GetString("bone_beamAttack"));
beamAttack->BindToJoint( this, spawnArgs.GetString("bone_beamAttack"), false );
beamAttack->Activate(FALSE);
}
beamTelepathic = idEntityPtr<hhBeamSystem> (hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "beamTelepathic" ) ) );
if(beamTelepathic.IsValid()) {
beamTelepathic->MoveToJoint( this, spawnArgs.GetString("bone_beamTelepathic"));
beamTelepathic->BindToJoint( this, spawnArgs.GetString("bone_beamTelepathic"), false );
beamTelepathic->Activate(FALSE);
beamTelepathic->Hide();
}
if ( spawnArgs.GetInt( "always_shield", "0" ) && !spawnArgs.GetBool( "hide", "0" ) ) {
Event_EnableShield();
}
nextShieldImpact = gameLocal.time;
bThrowing = false;
}
void hhKeeperSimple::Think() {
PROFILE_SCOPE("AI", PROFMASK_NORMAL|PROFMASK_AI);
if (ai_skipThink.GetBool()) {
return;
}
idEntity *ent = NULL;
if ( throwEntity.IsValid() ) {
ent = throwEntity.GetEntity();
} else if ( targetReaction.entity.IsValid() ) {
ent = targetReaction.entity.GetEntity();
}
// Draw beam from our brain to the object we are controlling
if ( beamTelepathic.IsValid() ) {
if( bThrowing && ent && !beamTelepathic->IsHidden() && beamTelepathic->IsActivated() ) {
beamTelepathic->SetTargetLocation(ent->GetOrigin());
} else {
beamTelepathic->Activate( false );
beamTelepathic->Hide();
}
}
if ( shieldFx.IsValid() ) {
if ( AI_SHIELD ) {
//fade on shield
shieldAlpha += spawnArgs.GetFloat( "shield_delta", "0.05" );
if ( shieldAlpha > 1.0 ) {
shieldAlpha = 1.0f;
}
} else {
//fade off shield
shieldAlpha -= spawnArgs.GetFloat( "shield_delta", "0.05" );
if ( shieldAlpha < 0.0 ) {
shieldAlpha = 0.0f;
}
}
shieldFx->SetParticleShaderParm( SHADERPARM_TIME_OF_DEATH, shieldAlpha );
}
hhMonsterAI::Think();
if ( physicsObj.HasGroundContacts() && !physicsObj.HadGroundContacts() ) {
AI_LANDED = true;
}
}
void hhKeeperSimple::Event_StartBlast( idEntity *ent) {
if( beamAttack.IsValid() ) {
hhFxInfo fxInfo;
fxInfo.SetEntity( ent );
fxInfo.RemoveWhenDone( true );
BroadcastFxInfo( spawnArgs.GetString("fx_portalstart"), ent->GetOrigin() + (spawnArgs.GetVector( "portal_start_offset" ) * ent->GetAxis()), ent->GetAxis(), &fxInfo );
beamAttack->SetTargetLocation( ent->GetOrigin() + ent->GetAxis() * spawnArgs.GetVector( "telepathic_beam_offset" ) );
beamAttack->Activate(TRUE);
}
}
void hhKeeperSimple::Event_EndBlast() {
if( beamAttack.IsValid() ) {
beamAttack->Activate(FALSE);
}
}
void hhKeeperSimple::Event_UpdateTelepathicThrow() {
idEntity *ent = NULL;
if ( throwEntity.IsValid() ) {
ent = throwEntity.GetEntity();
} else if ( targetReaction.entity.IsValid() ) {
ent = targetReaction.entity.GetEntity();
} else {
return;
}
if ( !ent || !ent->IsType(hhMoveable::Type) ) {
return;
}
bThrowing = true;
if ( beamTelepathic.IsValid() ) {
if ( beamTelepathic->IsHidden() ) {
beamTelepathic->Show();
}
beamTelepathic->Activate( true );
}
hhMoveable *throwMoveable = static_cast<hhMoveable*>(ent);
idVec3 hoverToPos;
if(GetEnemy()) {
UpdateEnemyPosition();
idVec3 toEnemy = GetLastEnemyPos() - GetOrigin();
float dist = toEnemy.Normalize();
hoverToPos = GetOrigin() + toEnemy * dist * 0.25f;
hoverToPos.z = GetOrigin().z + EyeHeight() + 200.0f;
}
else {
hoverToPos = throwMoveable->GetOrigin() + idVec3(0.0f, 0.0f, 128.0f);
}
throwMoveable->AllowImpact( true );
throwMoveable->Event_HoverTo(hoverToPos);
throwMoveable->GetPhysics()->SetAngularVelocity(idVec3(10.0f, 10.0f, 10.0f));
// HUMANHEAD mdl: Beef up the damage on movables thrown by the keeper
throwMoveable->SetDamageDef( spawnArgs.GetString( "moveableDamageDef", "damage_movable20" ) );
PostEventMS(&MA_KeeperUpdateTelepathicThrow, 100);
}
void hhKeeperSimple::Event_TelepathicThrow() {
idEntity *ent = NULL;
bThrowing = false;
if ( beamTelepathic.IsValid() ) {
beamTelepathic->Hide();
}
if ( throwEntity.IsValid() ) {
ent = throwEntity.GetEntity();
} else if ( targetReaction.entity.IsValid() ) {
ent = targetReaction.entity.GetEntity();
} else {
return;
}
// Start the object hovering
if ( !ent || !ent->IsType(hhMoveable::Type) ) {
return;
}
targetReaction.entity.Clear();
CancelEvents( &MA_KeeperUpdateTelepathicThrow );
hhMoveable *throwMoveable = static_cast<hhMoveable*>(ent);
if ( throwMoveable && throwMoveable->IsType( hhMoveable::Type ) ) {
throwMoveable->Event_Unhover();
}
// Throw it at an enemy if we have one
if(GetEnemy()) {
idVec3 toEnemy = GetEnemy()->GetAimPosition() - throwMoveable->GetOrigin();
toEnemy.Normalize();
throwMoveable->GetPhysics()->SetLinearVelocity(toEnemy * spawnArgs.GetFloat("telepathic_throw_velocity", "2000"));
}
}
void hhKeeperSimple::Event_TeleportExit() {
const function_t *newstate = NULL;
newstate = GetScriptFunction( "state_TeleportExit" );
if ( newstate ) {
SetState( newstate );
UpdateScript();
}
}
void hhKeeperSimple::Event_TeleportEnter() {
const function_t *newstate = NULL;
newstate = GetScriptFunction( "state_TeleportEnter" );
if ( newstate ) {
SetState( newstate );
UpdateScript();
}
}
void hhKeeperSimple::Event_StartTeleport() {
Hide();
}
void hhKeeperSimple::Event_EndTeleport() {
idVec3 newOrig;
idEntity *ent;
idList<idEntity*> nodeList;
float bestScore = -1;
float bestNodeIndex = -1;
// Find the best position to teleport to
// Find where we want to teleport to
idStr randomNode = spawnArgs.RandomPrefix( "teleport_info", gameLocal.random );
ent = gameLocal.FindEntity( randomNode );
if ( ent ) {
newOrig = ent->GetOrigin();
} else {
newOrig = GetOrigin();
gameLocal.Warning( "%s doesn't have any teleport infos", name.c_str() );
}
//teleport and face enemy
SetOrigin( newOrig );
if( GetEnemy() ) {
TurnToward(GetEnemy()->GetOrigin());
current_yaw = ideal_yaw;
Turn();
}
}
float hhKeeperSimple::GetTeleportDestRating(const idVec3 &pos) {
// Make sure this spot doesn't contain something else
idEntity *entList[MAX_GENTITIES];
idBounds myNewBnds = this->GetPhysics()->GetBounds();
myNewBnds = myNewBnds.Translate(pos);
myNewBnds.ExpandSelf(24.0f);
int numHit = gameLocal.clip.EntitiesTouchingBounds(myNewBnds, -1, entList, MAX_GENTITIES);
if(numHit > 0) {
for(int i=0;i<numHit;i++) {
if(entList[i] && !entList[i]->IsHidden() && (entList[i]->IsType(hhMoveable::Type) || entList[i]->IsType(idActor::Type))) {
return -1;
}
}
}
float w = gameLocal.random.RandomFloat();
return idMath::ClampFloat(-1.0f, 1.0f, w);
}
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
void hhKeeperSimple::LinkScriptVariables() {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable( AI_LANDED );
LinkScriptVariable( AI_SHIELD );
}
void hhKeeperSimple::Event_CreatePortal (void) {
static const char * passPrefix = "portal_";
const char * portalDef;
idEntity * portal;
idDict portalArgs;
idList<idStr> xferKeys;
idList<idStr> xferValues;
const idKeyValue *buddyKV = spawnArgs.FindKey( "portal_buddy" );
if ( buddyKV && buddyKV->GetValue().Length() && gameLocal.FindEntity(buddyKV->GetValue().c_str()) ) {
// Case of a valid portal_buddy key, make a real portal
portalDef = spawnArgs.GetString( "def_portal" );
} else if ( spawnArgs.FindKey( "portal_cameraTarget" ) ) { // The monster portal has a camera target, so use a real portal instead of the fake portal
portalDef = spawnArgs.GetString( "def_portal" );
} else {
portalDef = spawnArgs.GetString( "def_fakeportal" );
}
if ( !portalDef || !portalDef[0] ) {
return;
}
// Set the origin of the portal to us.
portalArgs.SetVector( "origin", GetOrigin() );
portalArgs.Set( "rotation", spawnArgs.GetString( "rotation" ) );
portalArgs.Set( "remove_on_close", "1" );
// Pass along all 'portal_' keys to the portal's spawnArgs;
hhUtils::GetKeysAndValues( spawnArgs, passPrefix, xferKeys, xferValues );
for ( int i = 0; i < xferValues.Num(); ++i ) {
xferKeys[ i ].StripLeadingOnce( passPrefix );
portalArgs.Set( xferKeys[ i ].c_str(), xferValues[ i ].c_str() );
}
// Spawn the portal
portal = gameLocal.SpawnObject( portalDef, &portalArgs );
if ( !portal ) {
return;
}
// Move the portal up some pre determinted amt, since its origin is in the middle of it
trace_t tr;
gameLocal.clip.TracePoint(tr, GetOrigin(), GetOrigin() + idVec3(0,0,-200), MASK_MONSTERSOLID, this);
if ( tr.fraction < 1.0f ) {
portal->GetPhysics()->SetOrigin( tr.c.point + idVec3( 0,0,2 ) );
} else {
float offset = spawnArgs.GetFloat( "offset_portal", 0 );
portal->GetPhysics()->SetOrigin( portal->GetPhysics()->GetOrigin() + (portal->GetAxis()[2] * offset) );
}
// Update the camera stuff
portal->ProcessEvent( &EV_UpdateCameraTarget );
// Open the portal - Need to delay this, so that PostSpawn gets called/sets up the partner portal
//? Should we always pass in the player?
portal->PostEventSec( &EV_Activate, 0, gameLocal.GetLocalPlayer() );
}
void hhKeeperSimple::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
if ( beamAttack.IsValid() ) {
SAFE_REMOVE( beamAttack );
}
if( beamTelepathic.IsValid() ) {
SAFE_REMOVE( beamTelepathic );
}
hhMoveable *throwMoveable = static_cast<hhMoveable*>(targetReaction.entity.GetEntity());
if ( throwMoveable && throwMoveable->IsType( hhMoveable::Type ) ) {
targetReaction.entity.Clear();
throwMoveable->Event_Unhover();
}
if ( renderEntity.customSkin == NULL ) {
SetSkinByName( "skins/monsters/keeper_nolegs" );
}
}
void hhKeeperSimple::Event_EnableShield(void) {
if ( spawnArgs.GetInt( "never_shield", "0" ) ) {
return;
}
fl.applyDamageEffects = false;
AI_SHIELD = true;
if ( shieldFx.IsValid() ) {
SAFE_REMOVE( shieldFx );
}
hhFxInfo fxInfo;
fxInfo.SetEntity( this );
fxInfo.SetBindBone( "head" );
fxInfo.RemoveWhenDone( true );
BroadcastFxInfo( spawnArgs.GetString("fx_shield"), GetOrigin(), mat3_identity, &fxInfo, &MA_KeeperAssignShieldFx );
}
void hhKeeperSimple::Event_ForceDisableShield(void) {
fl.applyDamageEffects = true;
AI_SHIELD = false;
}
void hhKeeperSimple::Event_DisableShield(void) {
if ( spawnArgs.GetInt( "always_shield", "0" ) ) {
return;
}
fl.applyDamageEffects = true;
AI_SHIELD = false;
}
void hhKeeperSimple::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int loc ) {
if ( AI_SHIELD ) {
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
if ( damageDef && damageDef->GetBool( "spirit_damage" ) ) {
hhMonsterAI::Damage(inflictor, attacker, dir, damageDefName, damageScale, loc);
}
if ( inflictor ) {
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone( true );
if ( gameLocal.time >= nextShieldImpact ) {
nextShieldImpact = gameLocal.time + int(spawnArgs.GetFloat( "shield_impact_freq", "0.4" ) * 1000);
BroadcastFxInfoPrefixed( "fx_shield_impact", inflictor->GetOrigin() + GetAxis()*idVec3(50,0,0), mat3_identity, &fxInfo );
}
StartSound( "snd_shield_impact", SND_CHANNEL_BODY );
if ( inflictor->IsType( idProjectile::Type ) ) {
inflictor->PostEventMS( &EV_Remove, 0 );
}
}
} else {
hhMonsterAI::Damage(inflictor, attacker, dir, damageDefName, damageScale, loc);
}
}
void hhKeeperSimple::Event_AssignShieldFx( hhEntityFx* fx ) {
shieldFx = fx;
}
void hhKeeperSimple::Event_StartHeadFx() {
hhFxInfo fxInfo;
fxInfo.SetEntity( this );
fxInfo.SetBindBone( spawnArgs.GetString( "bone_telepathic_fx", "head" ) );
fxInfo.RemoveWhenDone( true );
BroadcastFxInfo( spawnArgs.GetString("fx_telepathic"), GetOrigin(), mat3_identity, &fxInfo, &MA_KeeperAssignHeadFx );
}
void hhKeeperSimple::Event_EndHeadFx() {
SAFE_REMOVE( headFx );
}
void hhKeeperSimple::Event_AssignHeadFx( hhEntityFx* fx ) {
headFx = fx;
}
void hhKeeperSimple::Event_KeeperTrigger() {
if ( targetReaction.entity.IsValid() ) {
targetReaction.entity->ProcessEvent( &EV_Activate, this );
hhReaction *reaction = targetReaction.GetReaction();
if (reaction) {
reaction->active = false;
}
}
}
idProjectile *hhKeeperSimple::LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef ) { //HUMANHEAD mdc - added desiredProjectileDef for supporting multiple projs.
idVec3 muzzle;
idVec3 dir;
idVec3 start;
trace_t tr;
idBounds projBounds;
float distance;
const idClipModel *projClip;
float attack_accuracy;
float attack_cone;
float projectile_spread;
float diff;
float angle;
float spin;
idAngles ang;
int num_projectiles;
int i;
idMat3 axis;
idVec3 tmp;
idProjectile *lastProjectile;
//HUMANHEAD mdc - added to support multiple projectiles
if( desiredProjectileDef ) { //try to set our projectile to the desiredProjectile
int projIndex = FindProjectileInfo( desiredProjectileDef );
if( projIndex >= 0 ) {
SetCurrentProjectile( projIndex );
}
}
//HUMANHEAD END
if ( !projectileDef ) {
gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
return NULL;
}
attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" );
attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" );
num_projectiles = spawnArgs.GetInt( "num_projectiles", "1" );
GetMuzzle( jointname, muzzle, axis );
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, axis[ 0 ] );
}
lastProjectile = projectile.GetEntity();
if ( target != NULL ) {
tmp = target->GetPhysics()->GetAbsBounds().GetCenter() - muzzle;
tmp.Normalize();
axis = tmp.ToMat3();
} else {
axis = viewAxis;
}
// rotate it because the cone points up by default
tmp = axis[2];
axis[2] = axis[0];
axis[0] = -tmp;
// make sure the projectile starts inside the monster bounding box
const idBounds &ownerBounds = physicsObj.GetAbsBounds();
projClip = lastProjectile->GetPhysics()->GetClipModel();
projBounds = projClip->GetBounds().Rotate( axis );
// check if the owner bounds is bigger than the projectile bounds
if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
start = muzzle + distance * viewAxis[ 0 ];
} else {
start = ownerBounds.GetCenter();
}
} else {
// projectile bounds bigger than the owner bounds, so just start it from the center
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this );
muzzle = tr.endpos;
// set aiming direction
GetAimDir( muzzle, target, this, dir );
ang = dir.ToAngles();
// adjust his aim so it's not perfect. uses sine based movement so the tracers appear less random in their spread.
float t = MS2SEC( gameLocal.time + entityNumber * 497 );
ang.pitch += idMath::Sin16( t * 5.1 ) * attack_accuracy;
ang.yaw += idMath::Sin16( t * 6.7 ) * attack_accuracy;
if ( clampToAttackCone ) {
// clamp the attack direction to be within monster's attack cone so he doesn't do
// things like throw the missile backwards if you're behind him
diff = idMath::AngleDelta( ang.yaw, current_yaw );
if ( diff > attack_cone ) {
ang.yaw = current_yaw + attack_cone;
} else if ( diff < -attack_cone ) {
ang.yaw = current_yaw - attack_cone;
}
}
axis = ang.ToMat3();
float spreadRad = DEG2RAD( projectile_spread );
for( i = 0; i < num_projectiles; i++ ) {
// spread the projectiles out
angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
//dir = axis[ 0 ] + axis[ 2 ] * ( 0 * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir = axis[ 0 ] - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir.Normalize();
// launch the projectile
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, dir );
}
lastProjectile = projectile.GetEntity();
lastProjectile->Launch( muzzle, dir, vec3_origin );
projectile = NULL;
}
TriggerWeaponEffects( muzzle, axis );
lastAttackTime = gameLocal.time;
//HUMANHEAD mdc - added to support multiple projectiles
projectile = NULL;
SetCurrentProjectile( projectileDefaultDefIndex ); //set back to our default projectile to be on the safe side
//HUMANHEAD END
return lastProjectile;
}
void hhKeeperSimple::Event_GetTriggerEntity() {
idThread::ReturnEntity( triggerEntity.GetEntity() );
}
void hhKeeperSimple::Event_TriggerEntity( idEntity *ent ) {
if ( !ent ) {
return;
}
triggerEntity = ent;
const function_t *newstate = NULL;
newstate = GetScriptFunction( "state_TriggerEntity" );
if ( newstate ) {
SetState( newstate );
UpdateScript();
}
}
void hhKeeperSimple::Event_GetThrowEntity() {
idThread::ReturnEntity( throwEntity.GetEntity() );
}
void hhKeeperSimple::Event_ThrowEntity( idEntity *ent ) {
if ( !ent || !ent->IsType( idMoveable::Type ) ) {
return;
}
throwEntity = ent;
const function_t *newstate = NULL;
newstate = GetScriptFunction( "state_ThrowEntity" );
if ( newstate ) {
SetState( newstate );
UpdateScript();
}
}
void hhKeeperSimple::Hide() {
Event_DisableShield();
hhMonsterAI::Hide();
}
void hhKeeperSimple::Show() {
hhMonsterAI::Show();
if ( spawnArgs.GetInt( "always_shield", "0" ) ) {
Event_EnableShield();
}
}
void hhKeeperSimple::HideNoDormant() {
//overridden to hide shield fx
if ( shieldFx.IsValid() ) {
shieldFx->Hide();
}
idAI::Hide();
}
/*
=====================
hhKeeperSimple::Save
=====================
*/
void hhKeeperSimple::Save( idSaveGame *savefile ) const {
beamTelepathic.Save( savefile );
beamAttack.Save( savefile );
shieldFx.Save( savefile );
headFx.Save( savefile );
triggerEntity.Save( savefile );
throwEntity.Save( savefile );
savefile->WriteInt( nextShieldImpact );
savefile->WriteBool( bThrowing );
}
/*
=====================
hhKeeperSimple::Restore
=====================
*/
void hhKeeperSimple::Restore( idRestoreGame *savefile ) {
beamTelepathic.Restore( savefile );
beamAttack.Restore( savefile );
shieldFx.Restore( savefile );
headFx.Restore( savefile );
triggerEntity.Restore( savefile );
throwEntity.Restore( savefile );
savefile->ReadInt( nextShieldImpact );
savefile->ReadBool( bThrowing );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+98
View File
@@ -0,0 +1,98 @@
#ifndef __PREY_AI_KEEPER_SIMPLE_H__
#define __PREY_AI_KEEPER_SIMPLE_H__
class hhKeeperSimple : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhKeeperSimple);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_GetTriggerEntity() {};
void Event_TriggerEntity( idEntity *ent ) {};
void Event_GetThrowEntity() {};
void Event_ThrowEntity( idEntity *ent ) {};
void Event_StartBlast( idEntity *ent ) {};
void Event_EndBlast() {};
void Event_BeginTelepathicThrow(idEntity *throwMe) {};
void Event_UpdateTelepathicThrow() {};
void Event_TelepathicThrow() {};
void Event_StartTeleport() {};
void Event_EndTeleport() {};
void Event_TeleportExit() {};
void Event_TeleportEnter() {};
void Event_CreatePortal() {};
void Event_EnableShield() {};
void Event_DisableShield() {};
void Event_ForceDisableShield() {};
void Event_AssignShieldFx( hhEntityFx* fx ) {};
void Event_StartHeadFx() {};
void Event_EndHeadFx() {};
void Event_AssignHeadFx( hhEntityFx* fx ) {};
void Event_KeeperTrigger() {};
#else
hhKeeperSimple();
~hhKeeperSimple();
void Spawn( void );
virtual void Think();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void LinkScriptVariables();
virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
idProjectile* LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef );
void Hide();
void Show();
void HideNoDormant();
idScriptBool AI_LANDED;
idScriptBool AI_SHIELD;
protected:
void Event_GetTriggerEntity();
void Event_TriggerEntity( idEntity *ent );
void Event_GetThrowEntity();
void Event_ThrowEntity( idEntity *ent );
// Attack blast
void Event_StartBlast( idEntity *ent );
void Event_EndBlast();
// Telepathic Throwing
void Event_BeginTelepathicThrow(idEntity *throwMe);
void Event_UpdateTelepathicThrow();
void Event_TelepathicThrow();
// Teleporting
void Event_StartTeleport();
void Event_EndTeleport();
void Event_TeleportExit();
void Event_TeleportEnter();
void Event_CreatePortal();
// Shield
void Event_EnableShield();
void Event_DisableShield();
void Event_ForceDisableShield();
void Event_AssignShieldFx( hhEntityFx* fx );
void Event_StartHeadFx();
void Event_EndHeadFx();
void Event_AssignHeadFx( hhEntityFx* fx );
// Telepathic Triggering
void Event_KeeperTrigger();
float GetTeleportDestRating(const idVec3 &pos);
idEntityPtr<hhBeamSystem> beamTelepathic; // Beam used when we are telepathically controlling an object
idEntityPtr<hhBeamSystem> beamAttack;
idEntityPtr<hhEntityFx> shieldFx;
idEntityPtr<hhEntityFx> headFx;
idEntityPtr<idEntity> triggerEntity;
idEntityPtr<idEntity> throwEntity;
int nextShieldImpact;
float shieldAlpha;
bool bThrowing;
#endif
};
#endif
+63
View File
@@ -0,0 +1,63 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
CLASS_DECLARATION(hhMonsterAI, hhMutate)
EVENT( MA_OnProjectileLaunch, hhMutate::Event_OnProjectileLaunch )
END_CLASS
void hhMutate::Event_OnProjectileLaunch(hhProjectile *proj) {
const function_t *newstate = NULL;
if ( !enemy.IsValid() || !AI_COMBAT ) {
return;
}
float min = spawnArgs.GetFloat( "dda_dodge_min", "0.3" );
float max = spawnArgs.GetFloat( "dda_dodge_max", "0.8" );
float dodgeChance = 0.6f;
dodgeChance = (min + (max-min)*gameLocal.GetDDAValue() );
if ( ai_debugBrain.GetBool() ) {
gameLocal.Printf( "%s dodge chance %f\n", GetName(), dodgeChance );
}
if ( gameLocal.random.RandomFloat() > dodgeChance ) {
return;
}
//determine which side to dodge to
idVec3 povPos, targetPos;
povPos = enemy->GetPhysics()->GetOrigin();
targetPos = GetPhysics()->GetOrigin();
idVec3 povToTarget = targetPos - povPos;
povToTarget.z = 0.f;
povToTarget.Normalize();
idVec3 povLeft, povUp;
povToTarget.OrthogonalBasis(povLeft, povUp);
povLeft.Normalize();
idVec3 projVel = proj->GetPhysics()->GetLinearVelocity();
projVel.Normalize();
float dot = povLeft * projVel;
if ( dot < 0 ) {
newstate = GetScriptFunction( "state_DodgeBackRight" );
} else {
newstate = GetScriptFunction( "state_DodgeBackLeft" );
}
if ( newstate ) {
SetState( newstate );
UpdateScript();
}
}
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
void hhMutate::LinkScriptVariables(void) {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable( AI_COMBAT );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+15
View File
@@ -0,0 +1,15 @@
#ifndef __PREY_AI_MUTATE_H__
#define __PREY_AI_MUTATE_H__
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
class hhMutate : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhMutate);
protected:
void Event_OnProjectileLaunch(hhProjectile *proj);
void LinkScriptVariables();
idScriptBool AI_COMBAT;
};
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
#endif
+390
View File
@@ -0,0 +1,390 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef MH_AlertFriends("alertFriends", NULL, NULL);
const idEventDef MH_DropBinds("dropBinds");
const idEventDef MH_DropProjectiles("<dropProjectiles>" );
CLASS_DECLARATION(hhMonsterAI, hhMutilatedHuman)
EVENT( MH_AlertFriends, hhMutilatedHuman::Event_AlertFriends )
EVENT( MH_DropBinds, hhMutilatedHuman::Event_DropBinds )
EVENT( MH_DropProjectiles, hhMutilatedHuman::Event_DropProjectiles )
END_CLASS
void hhMutilatedHuman::Spawn() {
damageFlag = 0;
}
void hhMutilatedHuman::Event_DropBinds( ) {
idEntity *ent;
idEntity *next;
for( ent = teamChain; ent != NULL; ent = next ) {
next = ent->GetTeamChain();
if ( ent && !ent->IsType( hhProjectile::Type ) && !ent->IsType( idEntityFx::Type ) && ent->GetBindMaster() == this && ent != head.GetEntity() ) {
ent->Unbind();
next = teamChain;
}
}
}
void hhMutilatedHuman::Event_DropProjectiles() {
idEntity *ent;
idEntity *next;
for( ent = teamChain; ent != NULL; ent = next ) {
next = ent->GetTeamChain();
if ( ent && ent->IsType( hhProjectile::Type ) ) {
ent->Unbind();
ent->Hide();
ent->PostEventSec( &EV_Remove, 5 );
next = teamChain;
}
}
}
void hhMutilatedHuman::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
if (!fl.takedamage) {
return;
}
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
if ( AI_LIMB_FELL ) {
PostEventSec( &MH_DropProjectiles, 0.1f );
}
if ( AI_DEAD ) {
return;
}
idDict args;
idVec3 bonePos;
idMat3 boneAxis;
idStr debrisName;
idStr damageGroup = GetDamageGroup( location );
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
if ( damageDef && damageDef->GetBool( "ice" ) ) {
return;
}
if ( !( damageGroup == "head" && damageDef->GetInt( "damage" ) >= spawnArgs.GetFloat( "head_falloff_damage", "70" ) ) ) {
if ( gameLocal.random.RandomFloat() >= spawnArgs.GetFloat( "chanceLimbsWillFallOff", "0.1" ) ) { // CJR: Build in a chance that the limbs will fall off
return;
}
}
if ( damageGroup == "left_arm" && !(damageFlag & BIT(0)) ) {
damageFlag |= BIT(0);
debrisName = spawnArgs.GetString( "def_debris_arm" );
if ( !debrisName.IsEmpty() ) {
idEntity *debris = gameLocal.SpawnObject( debrisName, &args );
if ( debris ) {
AI_LIMB_FELL = true;
GetJointWorldTransform( spawnArgs.GetString( "bone_arm_left" ), bonePos, boneAxis );
debris->SetOrigin( bonePos );
debris->GetPhysics()->SetLinearVelocity( spawnArgs.GetVector( "debris_arm_velocity" ) * GetAxis() );
debris->GetPhysics()->SetAngularVelocity( 60 * hhUtils::RandomVector() );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_left_arm_blood"), spawnArgs.GetString("bone_arm_left") );
}
}
} else if ( damageGroup == "right_arm" && !(damageFlag & BIT(1)) ) {
damageFlag |= BIT(1);
debrisName = spawnArgs.GetString( "def_debris_arm" );
if ( !debrisName.IsEmpty() ) {
idEntity *debris = gameLocal.SpawnObject( debrisName, &args );
if ( debris ) {
AI_LIMB_FELL = true;
GetJointWorldTransform( spawnArgs.GetString( "bone_arm_right" ), bonePos, boneAxis );
debris->SetOrigin( bonePos );
debris->GetPhysics()->SetLinearVelocity( spawnArgs.GetVector( "debris_arm_velocity" ) * GetAxis() );
debris->GetPhysics()->SetAngularVelocity( 60 * hhUtils::RandomVector() );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_right_arm_blood"), spawnArgs.GetString("bone_arm_right") );
}
}
} else if ( damageGroup == "chest" && !(damageFlag & BIT(2)) ) {
damageFlag |= BIT(2);
damageFlag |= BIT(3);
debrisName = spawnArgs.GetString( "def_debris_chest" );
if ( !debrisName.IsEmpty() ) {
idEntity *debris = gameLocal.SpawnObject( debrisName, &args );
if ( debris ) {
AI_LIMB_FELL = true;
GetJointWorldTransform( spawnArgs.GetString( "bone_chest" ), bonePos, boneAxis );
debris->SetOrigin( bonePos );
debris->GetPhysics()->SetLinearVelocity( spawnArgs.GetVector( "debris_chest_velocity" ) * GetAxis() );
debris->GetPhysics()->SetAngularVelocity( 60 * hhUtils::RandomVector() );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_chest_blood"), spawnArgs.GetString("bone_chest") );
}
}
} else if ( damageGroup == "head" ) {
if ( head.IsValid() && !head->IsHidden() ) {
debrisName = spawnArgs.GetString( "def_debris_head" );
if ( !debrisName.IsEmpty() ) {
idEntity *debris = gameLocal.SpawnObject( debrisName, &args );
if ( debris ) {
AI_LIMB_FELL = true;
GetJointWorldTransform( spawnArgs.GetString( "bone_head" ), bonePos, boneAxis );
debris->SetOrigin( bonePos );
debris->GetPhysics()->SetLinearVelocity( spawnArgs.GetVector( "debris_head_velocity" ) * GetAxis() );
debris->GetPhysics()->SetAngularVelocity( 60 * hhUtils::RandomVector() );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_head_blood"), spawnArgs.GetString("bone_head") );
}
}
head->Hide();
}
}
idStr skinName = spawnArgs.GetString("damage_skin");
skinName += damageFlag;
if ( damageFlag > 0 ) {
SetSkin( declManager->FindSkin( skinName ) );
UpdateVisuals();
}
}
void hhMutilatedHuman::Event_AlertFriends() {
hhMonsterAI *check;
if ( !enemy.IsValid() ) {
return;
}
for( int i = 0; i < targets.Num(); i++ ) {
check = static_cast<hhMonsterAI *>(targets[ i ].GetEntity());
if ( !check || check->IsHidden() || !check->IsType( hhMutilatedHuman::Type ) ) {
continue;
}
check->SetEnemy( enemy.GetEntity() );
}
}
void hhMutilatedHuman::AnimMove( void ) {
//overridden to set enemy if blockedEnt can be an enemy
idVec3 goalPos;
idVec3 delta;
idVec3 goalDelta;
float goalDist;
monsterMoveResult_t moveResult;
idVec3 newDest;
idVec3 oldorigin = physicsObj.GetOrigin();
#ifdef HUMANHEAD //jsh wallwalk
idMat3 oldaxis = GetGravViewAxis();
#else
idMat3 oldaxis = viewAxis;
#endif
AI_BLOCKED = false;
if ( move.moveCommand < NUM_NONMOVING_COMMANDS ){
move.lastMoveOrigin.Zero();
move.lastMoveTime = gameLocal.time;
}
move.obstacle = NULL;
if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemy.GetEntity() ) {
TurnToward( lastVisibleEnemyPos );
goalPos = oldorigin;
} else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) {
TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() );
goalPos = oldorigin;
} else if ( GetMovePos( goalPos ) ) {
if ( move.moveCommand != MOVE_WANDER ) {
CheckObstacleAvoidance( goalPos, newDest );
TurnToward( newDest );
} else {
TurnToward( goalPos );
}
}
Turn();
if ( move.moveCommand == MOVE_SLIDE_TO_POSITION ) {
if ( gameLocal.time < move.startTime + move.duration ) {
goalPos = move.moveDest - move.moveDir * MS2SEC( move.startTime + move.duration - gameLocal.time );
delta = goalPos - oldorigin;
delta.z = 0.0f;
} else {
delta = move.moveDest - oldorigin;
delta.z = 0.0f;
StopMove( MOVE_STATUS_DONE );
}
} else if ( allowMove ) {
#ifdef HUMANHEAD //jsh wallwalk
GetMoveDelta( oldaxis, GetGravViewAxis(), delta );
#else
GetMoveDelta( oldaxis, viewAxis, delta );
#endif
} else {
delta.Zero();
}
if ( move.moveCommand == MOVE_TO_POSITION ) {
goalDelta = move.moveDest - oldorigin;
goalDist = goalDelta.LengthFast();
if ( goalDist < delta.LengthFast() ) {
delta = goalDelta;
}
}
physicsObj.SetDelta( delta );
physicsObj.ForceDeltaMove( disableGravity );
RunPhysics();
if ( ai_debugMove.GetBool() ) {
// HUMANHEAD JRM - so we can see if grav is on or off
if(disableGravity) {
gameRenderWorld->DebugLine( colorRed, oldorigin, physicsObj.GetOrigin(), 5000 );
} else {
gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 5000 );
}
}
moveResult = physicsObj.GetMoveResult();
if ( !af_push_moveables && attack.Length() && TestMelee() ) {
DirectDamage( attack, enemy.GetEntity() );
} else {
idEntity *blockEnt = physicsObj.GetSlideMoveEntity();
if ( blockEnt && blockEnt->IsType( idActor::Type ) && ReactionTo( blockEnt ) != ATTACK_IGNORE ) {
SetEnemy( static_cast<idActor*>(blockEnt) );
}
if ( blockEnt && blockEnt->IsType( hhPod::Type ) && blockEnt->GetPhysics()->IsPushable() ) {
KickObstacles( viewAxis[ 0 ], kickForce, blockEnt );
blockEnt->Damage( this, this, vec3_zero, spawnArgs.GetString( "kick_damage" ), 1.0f, INVALID_JOINT );
}
if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) {
KickObstacles( viewAxis[ 0 ], kickForce, blockEnt );
}
}
BlockedFailSafe();
AI_ONGROUND = physicsObj.OnGround();
idVec3 org = physicsObj.GetOrigin();
if ( oldorigin != org ) {
TouchTriggers();
}
if ( ai_debugMove.GetBool() ) {
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), org, gameLocal.msec );
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec );
gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true );
DrawRoute();
}
}
int hhMutilatedHuman::ReactionTo( const idEntity *ent ) {
const idActor *actor = static_cast<const idActor *>( ent );
if( actor && actor->IsType(hhDeathProxy::Type) ) {
return ATTACK_IGNORE;
}
if ( ent->health <= 0 ) {
return ATTACK_IGNORE;
}
if ( ent->fl.hidden ) {
// ignore hidden entities
return ATTACK_IGNORE;
}
if ( !ent->IsType( idActor::Type ) ) {
return ATTACK_IGNORE;
}
actor = static_cast<const idActor *>( ent );
if ( actor->IsType( idPlayer::Type ) && static_cast<const idPlayer *>(actor)->noclip ) {
// ignore players in noclip mode
return ATTACK_IGNORE;
}
//only attack spiritwalking players if they hurt me
if ( ent->IsType( hhPlayer::Type ) ) {
const hhPlayer *player = static_cast<const hhPlayer*>( ent );
if ( nextSpiritProxyCheck == 0 && player && player->IsSpiritWalking() ) {
nextSpiritProxyCheck = gameLocal.time + SEC2MS(2);
return ATTACK_ON_DAMAGE;
}
}
if ( ent->IsType( hhSpiritProxy::Type ) ) {
if ( gameLocal.time > nextSpiritProxyCheck ) {
nextSpiritProxyCheck = 0;
//attack spiritproxy on sight if we have no enemy or if its closer than our current enemy
if ( enemy.IsValid() && enemy->IsType( hhPlayer::Type ) ) {
float distToEnemy = (enemy->GetOrigin() - GetOrigin()).LengthSqr();
float distToProxy = (ent->GetOrigin() - GetOrigin()).LengthSqr();
if ( distToProxy < distToEnemy ) {
return ATTACK_ON_SIGHT;
}
} else {
return ATTACK_ON_SIGHT;
}
} else {
return ATTACK_IGNORE;
}
}
if ( ent && ent->spawnArgs.GetBool( "never_target" ) ) {
return ATTACK_IGNORE;
}
//if we're hurt, its probably because of the player, so keep him as an enemy
if ( actor->IsType( idPlayer::Type ) && health < spawnHealth ) {
return ATTACK_ON_DAMAGE | ATTACK_ON_ACTIVATE | ATTACK_ON_SIGHT;
}
// actors on different teams will always fight each other
if ( actor->team != team ) {
if ( actor->fl.notarget ) {
// don't attack on sight when attacker is notargeted
if ( actor->IsType( idPlayer::Type ) ) {
return ATTACK_ON_DAMAGE;
} else {
return ATTACK_ON_DAMAGE | ATTACK_ON_ACTIVATE;
}
}
//force players to only alert through damage
if ( actor->IsType( idPlayer::Type ) ) {
return ATTACK_ON_DAMAGE | ATTACK_ON_ACTIVATE;
} else if ( actor->IsType( idAI::Type ) ) {
//only allow ai actors to otherwise alert them
return ATTACK_ON_SIGHT | ATTACK_ON_DAMAGE | ATTACK_ON_ACTIVATE;
}
}
// monsters will fight when attacked by lower ranked monsters. rank 0 never fights back.
if ( rank && ( actor->rank < rank ) ) {
return ATTACK_ON_DAMAGE;
}
// don't fight back
return ATTACK_IGNORE;
}
/*
=====================
hhMutilatedHuman::Save
=====================
*/
void hhMutilatedHuman::Save( idSaveGame *savefile ) const {
savefile->WriteInt( damageFlag );
}
/*
=====================
hhMutilatedHuman::Restore
=====================
*/
void hhMutilatedHuman::Restore( idRestoreGame *savefile ) {
savefile->ReadInt( damageFlag );
}
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
void hhMutilatedHuman::LinkScriptVariables(void) {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable( AI_LIMB_FELL );
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef __PREY_AI_MUTILATEDHUMAN_H__
#define __PREY_AI_MUTILATEDHUMAN_H__
class hhMutilatedHuman : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhMutilatedHuman);
void Event_AlertFriends();
void Event_DropBinds();
void Event_DropProjectiles();
int ReactionTo( const idEntity *ent );
void Spawn();
void AnimMove();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
void LinkScriptVariables();
protected:
idScriptBool AI_LIMB_FELL;
int damageFlag;
};
#endif //__PREY_AI_MUTILATEDHUMAN_H__
+144
View File
@@ -0,0 +1,144 @@
//
// ai_passageway.cpp
//
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_EnablePassageway("enable", NULL);
const idEventDef EV_DisablePassageway("disable", NULL);
// hhAIPassageway
CLASS_DECLARATION(hhAnimated, hhAIPassageway)
EVENT(EV_AnimDone, hhAIPassageway::Event_AnimDone)
EVENT(EV_Activate, hhAIPassageway::Event_Trigger)
EVENT(EV_PostSpawn, hhAIPassageway::PostSpawn)
EVENT(EV_EnablePassageway, hhAIPassageway::Event_EnablePassageway)
EVENT(EV_DisablePassageway, hhAIPassageway::Event_DisablePassageway)
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
//
// Spawn()
//
void hhAIPassageway::Spawn() {
timeLastEntered = 0;
lastEntered = NULL;
enabled = TRUE;
hasEntered = FALSE;
GetPhysics()->SetContents(CONTENTS_SOLID);
PostEventMS( &EV_PostSpawn, 0 );
}
//
// PostSpawn()
//
void hhAIPassageway::PostSpawn() {
SetEnablePassageway(spawnArgs.GetBool("enabled", "1"));
}
//
// SetEnablePassageway()
//
void hhAIPassageway::SetEnablePassageway(bool tf) {
// Ignore if we're already in that state
if(enabled == tf)
return;
fl.refreshReactions = tf;
enabled = tf;
}
//
// Event_AnimDone()
//
void hhAIPassageway::Event_AnimDone( int animIndex ) {
//When we are done we want to pass ourselves as the activator
activator = this;
hhAnimated::Event_AnimDone( animIndex );
}
//
// Event_Trigger()
//
void hhAIPassageway::Event_Trigger( idEntity *activator ) {
if(!activator)
return;
// Ignore being activated by another passage node - they link to eachother,
// so they must be ignored otherwise it will continuously trigger
if( activator->IsType(hhAIPassageway::Type) ) {
return;
}
// Play our anim
hhAnimated::Event_Activate( activator );
HH_ASSERT(anim != NULL);
if( !activator->IsType(hhMonsterAI::Type) ) {
return;
}
hhMonsterAI *ai = static_cast<hhMonsterAI*>(activator);
// Can't enter if dead
if(ai->health <= 0)
return;
if(!ai->IsInsidePassageway())
{
//HUMANHEAD PCF mdl 04/29/06 - Added lastEntered check
if(hasEntered && lastEntered.GetEntity() == ai) {
ai->ProcessEvent(&MA_EnterPassageway, this);
hasEntered = FALSE;
} else {
lastEntered = ai;
timeLastEntered = gameLocal.GetTime();
hasEntered = TRUE;
}
}
else
{
ai->PostEventMS(&MA_ExitPassageway, 32, this);
hasEntered = FALSE;
}
}
//
// GetExitPos()
//
idVec3 hhAIPassageway::GetExitPos(void) {
idVec3 pos = GetOrigin();
idVec3 exitOffset;
spawnArgs.GetVector("exit_offset", "0 0 0", exitOffset);
exitOffset *= GetAxis();
pos += exitOffset;
pos.z += 0.2f;
return pos;
}
void hhAIPassageway::Save(idSaveGame *savefile) const {
savefile->WriteInt( timeLastEntered - gameLocal.time );
lastEntered.Save( savefile );
savefile->WriteBool( hasEntered );
savefile->WriteBool( enabled );
}
void hhAIPassageway::Restore(idRestoreGame *savefile) {
savefile->ReadInt( timeLastEntered );
timeLastEntered += gameLocal.time;
lastEntered.Restore( savefile );
savefile->ReadBool( hasEntered );
savefile->ReadBool( enabled );
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+49
View File
@@ -0,0 +1,49 @@
#ifndef __PREY_AI_PASSAGENODE_H__
#define __PREY_AI_PASSAGENODE_H__
//
// hhAIPassageway
//
class hhAIPassageway : public hhAnimated
{
public:
CLASS_PROTOTYPE(hhAIPassageway);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
virtual void PostSpawn() {};
void SetEnablePassageway(bool tf) {};
void Event_AnimDone( int animIndex ) {};
void Event_Trigger( idEntity *activator ) {};
void Event_EnablePassageway(void) {}
void Event_DisablePassageway(void) {}
#else
hhAIPassageway() {timeLastEntered = 0; lastEntered = NULL;}
virtual void Spawn();
virtual void PostSpawn();
void Save(idSaveGame *savefile) const;
void Restore(idRestoreGame *savefile);
idVec3 GetExitPos(void); // The point that a monster should be spawned upon exiting this passageway
void SetEnablePassageway(bool tf);
bool IsPassagewayEnabled(void) const {return enabled;}
int timeLastEntered; // The time someone last entered this passage node
idEntityPtr<idAI> lastEntered; // The ai that last entered this passage node
bool hasEntered; // FALSE if the AI has not fully entered yet - waiting for one more trigger
protected:
void Event_AnimDone( int animIndex );
void Event_Trigger( idEntity *activator );
void Event_EnablePassageway(void) {SetEnablePassageway(TRUE);}
void Event_DisablePassageway(void) {SetEnablePassageway(FALSE);}
bool enabled; // TRUE if we are a valid passagway
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif
+120
View File
@@ -0,0 +1,120 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
CLASS_DECLARATION( hhMonsterAI, hhPossessedTommy )
END_CLASS
// TODO: Set up a rhythmic damaging of this entity.
void hhPossessedTommy::Spawn() {
physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP | CONTENTS_RENDERMODEL );
nextDrop = 0;
}
void hhPossessedTommy::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
if ( attacker->IsType( hhPlayer::Type ) ) { // Being attacked by a player, must be a spiritwalking player
if ( possessedProxy.IsValid() ) {
hhSpiritProxy *proxy = possessedProxy.GetEntity();
Hide();
proxy->SetOrigin( GetOrigin() );
proxy->SetAxis( GetAxis() );
proxy->Show();
proxy->GetPhysics()->SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP | CONTENTS_RENDERMODEL );
if ( proxy->GetPlayer() ) {
proxy->GetPlayer()->Unpossess();
}
}
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
PostEventMS( &EV_Remove, 0 );
return;
}
// OTHERWISE, KILL THIS ENTITY AND KILL THE PLAYER -- create a death proxy here, etc
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
// Kill the player
if (possessedProxy.IsValid() ) {
if ( possessedProxy->GetPlayer() ) {
possessedProxy->GetPlayer()->PossessKilled();
}
}
}
void hhPossessedTommy::Event_Remove(void) {
if (!fl.hidden && possessedProxy.IsValid()) {
Hide();
hhSpiritProxy *proxy = possessedProxy.GetEntity();
proxy->SetOrigin( GetOrigin() );
proxy->SetAxis( GetAxis() );
proxy->Show();
proxy->GetPhysics()->SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP | CONTENTS_RENDERMODEL );
if ( proxy->GetPlayer() ) {
proxy->GetPlayer()->Unpossess();
}
}
hhMonsterAI::Event_Remove();
}
void hhPossessedTommy::Think(void) {
PROFILE_SCOPE("AI", PROFMASK_NORMAL|PROFMASK_AI);
if (ai_skipThink.GetBool()) {
return;
}
hhMonsterAI::Think();
if (possessedProxy.IsValid() && gameLocal.time > nextDrop) {
hhPlayer *player = possessedProxy->GetPlayer();
if (player) {
player->SetHealth(player->GetHealth() - 1);
if (player->GetHealth() <= 0) {
Hide();
possessedProxy->SetOrigin( GetOrigin() );
possessedProxy->SetAxis( GetAxis() );
possessedProxy->Show();
possessedProxy->GetPhysics()->SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP | CONTENTS_RENDERMODEL );
player->Unpossess();
player->Killed(this, this, 1, vec3_origin, INVALID_JOINT);
PostEventMS(&EV_Remove, 0);
}
}
float min = spawnArgs.GetFloat( "dda_drain_min" );
float max = spawnArgs.GetFloat( "dda_drain_max" );
nextDrop = gameLocal.time + min + (max - min) * (1.0f - gameLocal.GetDDAValue());
}
}
void hhPossessedTommy::Save( idSaveGame *savefile ) const {
possessedProxy.Save( savefile );
}
void hhPossessedTommy::Restore( idRestoreGame *savefile ) {
possessedProxy.Restore( savefile );
nextDrop = 0;
}
void hhPossessedTommy::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
// Turn to a different direction
float adjust = 45.0f + (gameLocal.random.RandomFloat() * 30.0f);
if (gameLocal.random.RandomInt(100) > 50) {
adjust = -adjust;
}
gameLocal.Printf("Adjusting by %f\n", adjust);
TurnToward(current_yaw + adjust);
move.nextWanderTime = 0;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef __PREY_AI_POSSESSED_TOMMY_H__
#define __PREY_AI_POSSESSED_TOMMY_H__
/***********************************************************************
hhPossessedTommy.
***********************************************************************/
class hhPossessedTommy : public hhMonsterAI {
public:
CLASS_PROTOTYPE( hhPossessedTommy );
public:
void Spawn();
virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
virtual void Think(void);
void SetPossessedProxy( hhSpiritProxy *newProxy ) { possessedProxy = newProxy; }
virtual void Event_Remove(void);
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
protected:
idEntityPtr<hhSpiritProxy> possessedProxy;
int nextDrop;
};
#endif //__PREY_AI_POSSESSED_TOMMY_H__
+639
View File
@@ -0,0 +1,639 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
///////////////////////////////////////////
//
// hhReactionDesc
//
///////////////////////////////////////////
//
// CausedToStr()
//
idStr hhReactionDesc::CauseToStr(Cause c) {
switch(c) {
case Cause_Damage:
return idStr("Damage");
case Cause_Touch:
return idStr("Touch");
case Cause_Use:
return idStr("Use");
case Cause_None:
return idStr("None");
case Cause_PlayAnim:
return idStr("PlayAnim");
case Cause_Telepathic_Trigger:
return idStr("TelepathicTrigger");
case Cause_Telepathic_Throw:
return idStr("TelepathicThrow");
}
return idStr("!!UNDEFINED!!");
}
//
// EffectToStr()
//
idStr hhReactionDesc::EffectToStr(Effect e) {
switch(e) {
case Effect_Damage:
return idStr("Damage");
case Effect_DamageEnemy:
return idStr("DamageEnemy");
case Effect_VehicleDock:
return idStr("VehicleDock");
case Effect_Vehicle:
return idStr("Vehicle");
case Effect_Heal:
return idStr("Heal");
case Effect_HaveFun:
return idStr("HaveFun");
case Effect_ProvideCover:
return idStr("ProvideCover");
case Effect_BroadcastTargetMsgs:
return idStr("BroadcastTargetMsgs");
case Effect_Climb:
return idStr("Climb");
case Effect_Passageway:
return idStr("Passageway");
case Effect_CallBackup:
return idStr("CallBackup");
}
return idStr("!!UNDEFINED!!");
}
//
// StrToCause()
//
hhReactionDesc::Cause hhReactionDesc::StrToCause(const char* str) {
for(int i=0;i<Cause_Total;i++) {
if(!CauseToStr((Cause)i).Icmp(str)) {
return (Cause)i;
}
}
return Cause_Invalid;
}
//
// StrToEffect()
//
hhReactionDesc::Effect hhReactionDesc::StrToEffect(const char* str) {
for(int i=0;i<Effect_Total;i++)
{
if(!EffectToStr((Effect)i).Icmp(str))
return (Effect)i;
}
return Effect_Invalid;
}
//
// Set()
//
void hhReactionDesc::Set(const idDict &keys) {
cause = StrToCause(keys.GetString("cause"));
effect = StrToEffect(keys.GetString("effect"));
flags = 0;
effectRadius = keys.GetFloat("effect_radius","-1.0f");
effectMinRadius = keys.GetFloat("effect_min_radius","0.0f");
if(keys.GetBool("snap_to_point")) {
flags |= flag_SnapToPoint;
}
if(keys.GetBool("effect_all_players")) {
flags |= flag_EffectAllPlayers;
}
if(keys.GetBool("effect_all_monsters")) {
flags |= flag_EffectAllMonsters;
}
if(keys.GetBool("req_novehicle")) {
flags |= flagReq_NoVehicle;
}
if(keys.GetBool("exclusive")) {
flags |= flag_Exclusive;
}
if(keys.GetBool("effect_listener")) {
flags |= flag_EffectListener;
}
if(keys.GetBool("anim_face_cause_dir")) {
flags |= flag_AnimFaceCauseDir;
}
if(keys.GetBool("anim_trigger_cause")) {
flags |= flag_AnimTriggerCause;
}
idStr keyString("");
if(keys.GetString("req_key", "", keyString)) {
if(keyString.Length() > 1) {
flags |= flagReq_KeyValue;
int firstSpace = keyString.Find(' ');
if( firstSpace >= 0 ) {
key = keyString.Left( firstSpace);
keyVal = keyString.Right( keyString.Length() - firstSpace -1);
}
}
else
gameLocal.Error("Invalide key for 'reaction_req_ley' value: %s", (const char*)keyString);
}
//MDC begin
keyString.Empty();
if( keys.GetString( "finish_key", "", keyString)) {
if( keyString.Length() > 1 ) {
int firstSpace = keyString.Find(' ');
if( firstSpace >= 0 ) {
finish_key = keyString.Left( firstSpace );
finish_val = keyString.Right( keyString.Length() - firstSpace - 1 );
}
}
}
//MDC end
idStr animString("");
if(keys.GetString("req_anim", "", animString)) {
flags |= flagReq_Anim;
anim = animString;
}
if(keys.GetBool("req_rangeattack")) {
flags |= flagReq_RangeAttack;
}
if(keys.GetBool("req_meleeattack")) {
flags |= flagReq_MeleeAttack;
}
if(keys.GetBool("req_can_see")) {
flags |= flagReq_CanSee;
}
if(keys.GetBool("req_telepathic") || cause == hhReactionDesc::Cause_Telepathic_Throw || cause == hhReactionDesc::Cause_Telepathic_Trigger) {
flags |= flagReq_Telepathic;
}
// Effect volumes
effectVolumes.Clear();
const idKeyValue *kv = keys.MatchPrefix("effect_volume", NULL);
while(kv) {
idStr effectVolName = kv->GetValue();
if(effectVolName.Length() > 0) {
idEntity *e = gameLocal.FindEntity(effectVolName.c_str());
if(!e) {
gameLocal.Error("Failed to find effect_volume named %s", effectVolName.c_str());
}
if(!e->IsType(hhReactionVolume::Type)) {
gameLocal.Error("effect_volume named %s was of incorrect spawn type. Must be hhReactionVolume", effectVolName.c_str());
}
effectVolumes.AddUnique(static_cast<hhReactionVolume*>(e));
}
// Move to next volume
kv = keys.MatchPrefix("effect_volume", kv);
}
listenerRadius = keys.GetFloat("listener_radius", "-1.0f");
listenerMinRadius = keys.GetFloat("listener_min_radius", "-1.0f");
// Store listener volumes
listenerVolumes.Clear();
kv = keys.MatchPrefix("listener_volume", NULL);
while(kv) {
idStr listenVolName = kv->GetValue();
if(listenVolName.Length() > 0) {
idEntity *e = gameLocal.FindEntity(listenVolName.c_str());
if(!e) {
gameLocal.Error("Failed to find listener_volume named %s", listenVolName.c_str());
}
if(!e->IsType(hhReactionVolume::Type)) {
gameLocal.Error("listener_volume named %s was of incorrect spawn type. Must be hhReactionVolume", listenVolName.c_str());
}
listenerVolumes.AddUnique(static_cast<hhReactionVolume*>(e));
}
// Move to next volume
kv = keys.MatchPrefix("listener_volume", kv);
}
// Store touchdir
touchDir = keys.GetString("touchdir","");
// Extract out touch offsets
kv = keys.MatchPrefix("touchoffset_", NULL);
touchOffsets.SetGranularity(1);
touchOffsets.Clear();
idStr tmpStr;
idStr keyName;
int usIndex;
while(kv) {
tmpStr = kv->GetKey();
usIndex = tmpStr.FindChar("touchoffset_", '_');
keyName = tmpStr.Mid(usIndex+1, strlen(kv->GetKey())-usIndex-1);
touchOffsets.Set(keyName, kv->GetValue());
// Move to the next
kv = keys.MatchPrefix("touchoffset_", kv);
}
// Extract out touch bounds
kv = keys.MatchPrefix("safebound_", NULL );
while(kv) {
tmpStr = kv->GetKey();
usIndex = tmpStr.FindChar("safebound_", '_');
keyName = tmpStr.Mid(usIndex+1, strlen(kv->GetKey())-usIndex-1);
touchOffsets.Set(keyName, kv->GetValue());
kv = keys.MatchPrefix("safebound_", kv);
}
}
/*
================
hhReactionDesc::Save
================
*/
void hhReactionDesc::Save(idSaveGame *savefile) const {
savefile->WriteString(name);
savefile->WriteInt(effect);
savefile->WriteInt(cause);
savefile->WriteInt(flags);
savefile->WriteFloat(effectRadius);
savefile->WriteFloat(effectMinRadius);
int num = effectVolumes.Num();
savefile->WriteInt(num);
for(int i = 0; i < num; i++) {
savefile->WriteObject( effectVolumes[i] );
}
savefile->WriteString(key);
savefile->WriteString(keyVal);
savefile->WriteString(anim);
savefile->WriteFloat(listenerRadius);
savefile->WriteFloat(listenerMinRadius);
num = listenerVolumes.Num();
savefile->WriteInt(num);
for(int i = 0; i < num; i++) {
savefile->WriteObject(listenerVolumes[i]);
}
savefile->WriteDict(&touchOffsets);
savefile->WriteString(touchDir);
savefile->WriteString(finish_key);
savefile->WriteString(finish_val);
}
/*
================
hhReactionDesc::Restore
================
*/
void hhReactionDesc::Restore( idRestoreGame *savefile ) {
savefile->ReadString(name);
savefile->ReadInt(reinterpret_cast<int &> (effect));
savefile->ReadInt(reinterpret_cast<int &> (cause));
savefile->ReadInt(reinterpret_cast<int &> (flags));
savefile->ReadFloat(effectRadius);
savefile->ReadFloat(effectMinRadius);
int num;
savefile->ReadInt(num);
effectVolumes.SetNum(num);
for(int i = 0; i < num; i++) {
savefile->ReadObject(reinterpret_cast<idClass *&> (effectVolumes[i]));
}
savefile->ReadString(key);
savefile->ReadString(keyVal);
savefile->ReadString(anim);
savefile->ReadFloat(listenerRadius);
savefile->ReadFloat(listenerMinRadius);
savefile->ReadInt(num);
listenerVolumes.SetNum(num);
for(int i = 0; i < num; i++) {
savefile->ReadObject(reinterpret_cast<idClass *&> (listenerVolumes[i]));
}
savefile->ReadDict(&touchOffsets);
savefile->ReadString(touchDir);
savefile->ReadString(finish_key);
savefile->ReadString(finish_val);
}
///////////////////////////////////////////
//
// hhReactionVolume
//
///////////////////////////////////////////
CLASS_DECLARATION(idEntity, hhReactionVolume)
END_CLASS
//
// Spawn()
//
void hhReactionVolume::Spawn() {
flags = 0;
if(spawnArgs.GetBool("players", "1")) {
flags |= flagPlayers;
}
if(spawnArgs.GetBool("monsters", "1")) {
flags |= flagMonsters;
}
if(flags == 0) {
gameLocal.Error("Reaction volume %s is not targetting players or monsters - Why even have this volume?", (const char*)name);
}
}
bool hhReactionVolume::IsValidEntity( idEntity *ent ) {
assert(GetPhysics() != NULL);
assert(flags != 0); // have to be looking for something - else whats the point?
if ( !ent || ent->IsHidden() ) {
return false;
}
if(flags & flagMonsters && !ent->IsType(idAI::Type)) {
if(flags & flagPlayers && !ent->IsType(hhPlayer::Type)) {
return false;
}
}
idEntity * entityList[ MAX_GENTITIES ];
int numEnts = gameLocal.clip.EntitiesTouchingBounds(GetPhysics()->GetAbsBounds(), CONTENTS_BODY, entityList, MAX_GENTITIES);
for(int i=0;i<numEnts;i++) {
if ( entityList[i] == ent ) {
return true;
}
}
return false;
}
//
// GetValidEntitiesInside()
//
void hhReactionVolume::GetValidEntitiesInside(idList<idEntity*> &outValidEnts) {
assert(GetPhysics() != NULL);
assert(flags != 0); // have to be looking for something - else whats the point?
idEntity * entityList[ MAX_GENTITIES ];
int numEnts = gameLocal.clip.EntitiesTouchingBounds(GetPhysics()->GetAbsBounds(), CONTENTS_BODY, entityList, MAX_GENTITIES);
for(int i=0;i<numEnts;i++) {
if(!entityList[i] || entityList[i]->IsHidden())
continue;
if(flags & flagPlayers && entityList[i]->IsType(hhPlayer::Type)) {
outValidEnts.Append(entityList[i]);
if(ai_debugBrain.GetInteger()) {
gameRenderWorld->DebugArrow(colorMagenta, GetOrigin(), entityList[i]->GetOrigin(), 10, 1000);
}
continue;
}
}
if(ai_debugBrain.GetInteger()) {
gameRenderWorld->DebugBounds(colorWhite, GetPhysics()->GetBounds(), GetOrigin(), 1000);
}
}
/*
================
hhReactionVolume::Save
================
*/
void hhReactionVolume::Save(idSaveGame *savefile) const {
savefile->WriteInt(flags);
}
/*
================
hhReactionVolume::Restore
================
*/
void hhReactionVolume::Restore(idRestoreGame *savefile) {
savefile->ReadInt(flags);
}
///////////////////////////////////////////
//
// hhReactionHandler
//
///////////////////////////////////////////
//
// construction
//
hhReactionHandler::hhReactionHandler() {
}
//
// destruction
//
hhReactionHandler::~hhReactionHandler() {
reactionDescs.DeleteContents(TRUE);
}
//
// LoadReactionDesc()
//
const hhReactionDesc* hhReactionHandler::LoadReactionDesc(const char* defName, const idDict *uniqueDescKeys) {
// Ignore null reactions
if ( !defName || !defName[0] ) {
return NULL;
}
const hhReactionDesc *ret = NULL;
// If we do not have unqiue keys, we can just use a cached version
if(!uniqueDescKeys) {
ret = FindReactionDesc(defName);
if(ret) {
return ret;
}
}
// Get the def dict
const idDict *reactDefDict = gameLocal.FindEntityDefDict(defName);
if(!reactDefDict) {
gameLocal.Error("Failed to find reaction dict named %s", defName);
}
// Build the keys that will be passed onto the creation
idDict finalDict;
finalDict.Copy(*reactDefDict);
StripReactionPrefix(finalDict);
if(uniqueDescKeys) {
idDict uniqueCopy(*uniqueDescKeys);
StripReactionPrefix(uniqueCopy);
finalDict.Copy(uniqueCopy);
}
hhReactionDesc* react = CreateReactionDesc(defName, finalDict);
return react;
}
//
// createReactionDesc()
//
hhReactionDesc* hhReactionHandler::CreateReactionDesc(const char *desiredName, const idDict &keys) {
idStr finalName = GetUniqueReactionDescName(desiredName);
hhReactionDesc *desc = new hhReactionDesc();
desc->name = finalName;
desc->Set(keys);
reactionDescs.Append(desc);
return desc;
}
//
// getUniqueReactionDescName()
//
idStr hhReactionHandler::GetUniqueReactionDescName(const char *name) {
int count = 0;
idStr finalName(name);
while(1) {
if(count > 0) {
finalName = idStr(name) + idStr("_") + idStr(count);
}
// Did we find a name that was not taken?
if(FindReactionDesc(finalName.c_str()) == NULL) {
return finalName;
}
#ifdef _DEBUG
if(count > 128) {
assert(FALSE); // How the hell did we get so many copies?
}
#endif
count++;
}
}
//
// findReactionDesc()
//
const hhReactionDesc* hhReactionHandler::FindReactionDesc(const char *name) {
for(int i=0;i<reactionDescs.Num();i++) {
if(strcmp(reactionDescs[i]->name.c_str(), name) == 0) {
return reactionDescs[i];
}
}
return NULL;
}
//
// stripReactionPrefix()
//
void hhReactionHandler::StripReactionPrefix(idDict &dict) {
const idKeyValue *kv = NULL;//dict.MatchPrefix("reaction");
idDict newDict;
for(int i=0;i<dict.GetNumKeyVals();i++) {
kv = dict.GetKeyVal(i);
idStr key;
key = kv->GetKey();
// Do we have a reaction token to strip out?
if(idStr::FindText(key.c_str(), "reaction") != -1) {
int endPrefix = idStr::FindChar(key.c_str(), '_');
if(endPrefix == -1) {
gameLocal.Error("reactionX_ prefix not found.");
}
idStr realKey(key);
realKey = key.Mid(endPrefix+1, key.Length() - endPrefix - 1);
key = realKey;
}
//dict.Delete(kv->GetKey().c_str());
newDict.Set(key.c_str(), kv->GetValue());
kv = dict.MatchPrefix("reaction", kv);
}
dict.Clear();
dict.Copy(newDict);
}
void hhReactionHandler::Save(idSaveGame *savefile) const {
savefile->WriteInt(reactionDescs.Num());
for (int i = 0; i < reactionDescs.Num(); i++) {
reactionDescs[i]->Save(savefile);
}
}
void hhReactionHandler::Restore( idRestoreGame *savefile ) {
reactionDescs.DeleteContents(true);
int num;
savefile->ReadInt(num);
reactionDescs.SetNum(num);
for (int i = 0; i < num; i++) {
reactionDescs[i] = new hhReactionDesc();
reactionDescs[i]->Restore(savefile);
}
}
void hhReaction::Save(idSaveGame *savefile) const {
savefile->WriteBool(active);
exclusiveOwner.Save(savefile);
savefile->WriteInt(exclusiveUntil);
if (desc) {
savefile->WriteString(desc->name);
} else {
savefile->WriteString("");
}
causeEntity.Save(savefile);
int num = effectEntity.Num();
savefile->WriteInt(num);
for(int i = 0; i < num; i++) {
effectEntity[i].ent.Save(savefile);
savefile->WriteFloat(effectEntity[i].weight);
}
}
void hhReaction::Restore(idRestoreGame *savefile) {
savefile->ReadBool(active);
exclusiveOwner.Restore(savefile);
savefile->ReadInt(exclusiveUntil);
idStr name;
savefile->ReadString(name);
desc = gameLocal.GetReactionHandler()->FindReactionDesc(name);
causeEntity.Restore(savefile);
int num;
savefile->ReadInt(num);
hhReactionTarget ent;
for(int i = 0; i < num; i++) {
ent.ent.Restore(savefile);
savefile->ReadFloat(ent.weight);
effectEntity.Append(ent);
}
}
+261
View File
@@ -0,0 +1,261 @@
#ifndef __HH_REACTION_H
#define __HH_REACTION_H
//
// hhReactionTarget
//
class hhReactionTarget
{
public:
hhReactionTarget() {
weight = 1.0f;
ent = NULL;
}
hhReactionTarget(idEntity *e, float w = 1.0f) {
ent = e;
weight = w;
}
idEntityPtr<idEntity> ent; // The entity that is effected
float weight; // The degree ent is effected
};
//
// hhReactionVolume
//
class hhReactionVolume : public idEntity {
public:
CLASS_PROTOTYPE( hhReactionVolume );
enum {
flagPlayers = (1<<0),
flagMonsters = (1<<1),
flagActors = (flagPlayers|flagMonsters),
};
void Spawn(void);
// Gets all of the entities (filtered by validFlags) that are inside this volume
void GetValidEntitiesInside(idList<idEntity*> &outValidEnts);
bool IsValidEntity( idEntity *ent );
void Save(idSaveGame *savefile) const;
void Restore(idRestoreGame *savefile);
protected:
int flags; // Flags for this volume
};
//
// hhReactionDesc
//
// Holds the unchanging properties of a reaction
//
class hhReactionDesc
{
public:
friend class hhReactionHandler;
hhReactionDesc() {
name = idStr("<undefined>");
effect = Effect_Invalid;
cause = Cause_Invalid;
flags = 0;
effectRadius = -1.0f;
effectMinRadius = -1.0f;
effectVolumes.SetGranularity(1);
key = idStr("");
keyVal = idStr("");
anim = idStr("");
listenerRadius = -1.0f;
listenerMinRadius = -1.0f;
listenerVolumes.SetGranularity(1);
}
enum Cause {
Cause_Invalid = -1,
Cause_Damage, // AI can damage this to get reaction
Cause_Touch, // AI can touch this to get reaction
Cause_Use, // AI can 'use' this to get reaction
Cause_None, // AI does nothing, and the effect is always felt
Cause_PlayAnim, // AI must play an anim to get the desired effect
Cause_Telepathic_Trigger, // AI must use their telepathy to trigger this entity
Cause_Telepathic_Throw, // AI must use their telepathy to physically throw this entity
Cause_Total
};
enum Effect {
Effect_Invalid = -1,
Effect_Damage, // Causes damage (reduces health)
Effect_DamageEnemy, // Causes damage (reduces health)
Effect_VehicleDock, // Causes damage (reduces health)
Effect_Vehicle, // Causes damage (reduces health)
Effect_Heal, // Heals entity (increases health)
Effect_HaveFun, // Something 'fun' for this entity to do
Effect_ProvideCover, // Indicates this entity can possibily provide 'cover' for a monster
Effect_BroadcastTargetMsgs, // This entity will have its target's msg's sent
Effect_Climb, // This entity will let the monster climb it.
Effect_Passageway, // This entity is a harvester passageway
Effect_CallBackup, // Calls for help
Effect_Total
};
enum {
flag_EffectAllPlayers = (1<<0), // This entity automatically targets ALL entities of type hhPlayer
flag_EffectAllMonsters = (1<<1), // This entity automatically targets ALL entities of typehhAI
flag_Exclusive = (1<<2), // This msg is exclusive, and once a monster has committed to it - NO one else should listen to it
flag_EffectListener = (1<<3), // The effect of this reaction is applied to the listener
flag_AnimFaceCauseDir = (1<<4), // When playing an anim for this reaction, face the direction of our cause
flag_AnimTriggerCause = (1<<5), // When playing an anim for this reaction, trigger the cause entity
flag_SnapToPoint = (1<<6), // This msg is only for monsters that are telepathic
flagReq_MeleeAttack = (1<<8), // This msg is for monsters that can melee attack
flagReq_RangeAttack = (1<<9), // This msg is for monsters that can range attack
flagReq_Anim = (1<<10), // This msg is for monsters that have a given anim (anim)
flagReq_KeyValue = (1<<11), // This msg is for monsters that have a given key set (key, keyVal)
flagReq_NoVehicle = (1<<12), // This msg is for monsters that are NOT in vehicles
flagReq_CanSee = (1<<13), // This msg is only for monsters that can see the cause entity
flagReq_Telepathic = (1<<14), // This msg is only for monsters that are telepathic
};
static idStr CauseToStr(Cause c); // Converts activate enum into readable form
static idStr EffectToStr(Effect e); // Converts reaction enum to readable form
static Cause StrToCause(const char* str); // Converts string to caused by enum or Caused_Invalid if not found
static Effect StrToEffect(const char* str); // Converts string to effect enum or Effect_Invalid if not found
void Set(const idDict &keys); // Sets this description to the given key values
bool CauseRequiresPathfinding(void) const {return cause == Cause_Touch || cause == Cause_Use || cause == Cause_PlayAnim;}
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
idStr name; // unique name for each reaction desc
Effect effect; // pdm: for reaction system
Cause cause; // pdm: for reaction system
unsigned int flags; // jrm: reaction flags for reaction system
float effectRadius; // jrm: If > 0.0f then ONLY target entities that are at most this far away
float effectMinRadius; // jrm: if > 0.0f then ONLY target entities that are at least this far away
idList<hhReactionVolume*> effectVolumes; // jrm: if valid, then only entities that are inside one of these volumes are valid 'effect' entities
idStr key; // jrm: the key required for a monster to be eligable for this reaction msg (ReactionFlag_KeyReq must be set)
idStr keyVal; // jrm: the value of the reaction key required
idStr anim; // jrm: the value of the reaction key required
float listenerRadius; // jrm: listeners farther away than this distance will not receive this reaction
float listenerMinRadius; // jrm: listeners closer than this dist will not receive this reaction
idList<hhReactionVolume*> listenerVolumes; // jrm: only listeners that are inside one of these volumes will receive this reaction
idDict touchOffsets; // Example: Use "monster_hunter" as key to get touchOffset values
idStr touchDir; // Indicates how a monster should approach the cause entity
idStr finish_key; // mdc: used to set a key on monster after finishing a reaction
idStr finish_val; // mdc: used to set a key on monster after finishing a reaction
};
//
// hhReaction
//
// Describes a reaction ready to be processed by the AI. Holds a description of the reaction, as well as the cause/effect entities.
// Do the cause describe by <desc> to <causeEntity> to get the effect in <desc> applied to <effectEntity>
//
class hhReaction
{
public:
hhReaction()
{
desc = NULL;
causeEntity = NULL;
active = TRUE;
exclusiveOwner = NULL;
exclusiveUntil = -1;
effectEntity.Clear();
};
hhReaction(const hhReactionDesc *reactDesc, idEntity *cause, const hhReactionTarget &effect)
{
active = TRUE;
desc = reactDesc;
causeEntity = cause;
exclusiveUntil = -1;
exclusiveOwner = NULL;
effectEntity.Append(effect);
}
bool IsActive() const {return active;}
bool IsActiveForListener(idEntity *listener) const {
if(!active) {
return FALSE;
}
// If someone has claimed this, and their claim is still valid... Only active for that particular AI
if(exclusiveOwner.GetEntity() && gameLocal.GetTime() < exclusiveUntil) {
return exclusiveOwner.GetEntity() == listener;
}
// No one has claimed us, or time has expired, so anyone can claim us now
return TRUE;
};
bool ClaimExclusivity(idEntity *claimer, int ms=1000) {
// Cannot claim, someone else already has it
if(exclusiveOwner.GetEntity() && gameLocal.GetTime() < exclusiveUntil) {
return FALSE;
}
// They claimed it now....
exclusiveOwner = claimer;
exclusiveUntil = gameLocal.GetTime() + ms;
return TRUE;
}
void Save(idSaveGame *savefile) const;
void Restore(idRestoreGame *savefile);
bool active; // TRUE to be considered for sending
idEntityPtr<idEntity> exclusiveOwner; // The AI that has 'claimed' this reaction
int exclusiveUntil; // Until gameLocal.time has reached this value, this reaction does not send msgs (except for exclusive reactions)
const hhReactionDesc* desc; // Info about the kind of reaction this is
idEntityPtr<idEntity> causeEntity; // The entity to apply the cause to
idList<hhReactionTarget> effectEntity; // The effect of doing the cause is felt by these entities
};
//
// hhReactionHandler
//
// Manages all of the reaction descs currently loaded
//
class hhReactionHandler
{
public:
hhReactionHandler();
virtual ~hhReactionHandler();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// Loads the given reaction def name. If uniqueDescKeys are specified, a unique hhReactionDesc* is guarenteed to be returned.
// Otherwise, if no override keys are specified and a reaction of the given name is found, it is returned without creating a new one
// The returned desc is ONLY a desc, it is not meant to be modified in any way
const hhReactionDesc* LoadReactionDesc(const char* defName, const idDict &uniqueDescKeys) {
if(uniqueDescKeys.GetNumKeyVals() <= 0) {
return LoadReactionDesc(defName, NULL);
} else {
return LoadReactionDesc(defName, &uniqueDescKeys);
}
}
const hhReactionDesc* LoadReactionDesc(const char* defName) {return LoadReactionDesc(defName, NULL);}
protected:
friend class hhReaction;
// Creates a new reaction desc with the given name and keys to describe the reaction
hhReactionDesc* CreateReactionDesc(const char *name, const idDict &keys);
idStr GetUniqueReactionDescName(const char *name);
const hhReactionDesc* FindReactionDesc(const char *name);
void StripReactionPrefix(idDict &dict); // Removes any "reaction_" or "reaction1_" prefix from the given dict
const hhReactionDesc* LoadReactionDesc(const char* defName, const idDict *uniqueDescKeys);
idList<hhReactionDesc*> reactionDescs;
};
#endif
+227
View File
@@ -0,0 +1,227 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
//
// hhAISpawnCase
//
const idEventDef EV_CreateAI( "<createAI>", NULL);
const idEventDef EV_AutoTrigger( "<autotrigger>", NULL);
CLASS_DECLARATION( hhAnimated, hhAISpawnCase )
EVENT( EV_Activate, hhAISpawnCase::Event_Trigger )
EVENT( EV_CreateAI, hhAISpawnCase::Event_CreateAI )
EVENT( EV_AutoTrigger, hhAISpawnCase::Event_AutoTrigger )
END_CLASS
//
// Spawn()
//
void hhAISpawnCase::Spawn( void ) {
triggerToggle = FALSE;
aiSpawnCount = 0;
waitingForAutoTrigger = FALSE;
triggerQueue = 0;
CreateEntSpawnArgs();
GetPhysics()->SetContents(CONTENTS_SHOOTABLE|CONTENTS_PLAYERCLIP|CONTENTS_MOVEABLECLIP|CONTENTS_IKCLIP|CONTENTS_SHOOTABLEBYARROW);
// Next frame, create the AI to attach to this case - Wait a frame so that we can copy targets
PostEventMS(&EV_CreateAI, 0);
}
//
// Event_CreateAI()
//
void hhAISpawnCase::Event_CreateAI( void ) {
// Spawn the monster
const char *monsterName = spawnArgs.GetString("def_monster", NULL);
int i;
if ( aiSpawnCount < spawnArgs.GetInt("max_monsters", "1") && monsterName && monsterName[0]) {
idDict args = entSpawnArgs;
idVec3 offset = spawnArgs.GetVector("monster_offset", "0 0 0");
offset *= GetPhysics()->GetAxis();
args.SetVector( "origin", GetPhysics()->GetOrigin() + offset);
args.SetBool("encased", TRUE);
args.Set("encased_idle", spawnArgs.GetString("anim_encased_monster_idle", "encased_idle"));
args.Set("encased_exit", spawnArgs.GetString("anim_encased_monster_exit", "encased_exit"));
args.Set( "encased_exit_offset", spawnArgs.GetString( "encased_exit_offset", "0 0 0" ) );
args.SetMatrix("rotation", GetAxis());
encasedAI = static_cast<idAI*>(gameLocal.SpawnObject(monsterName, &args));
if(!encasedAI.GetEntity()) {
//gameLocal.Warning("No monster specified for case");
return;
}
// Copy the targets that our case has to our newly spawned monster
for( i = 0; i < targets.Num(); i++ ) {
encasedAI->targets.AddUnique(targets[i]);
}
if ( spawnArgs.GetBool( "rotated" ) ) {
encasedAI->SetAxis( GetAxis() );
encasedAI->GetPhysics()->SetAxis( GetAxis() );
encasedAI->GetRenderEntity()->axis = GetAxis();
encasedAI->viewAxis = GetAxis();
encasedAI->Bind(this, true);
} else {
encasedAI->viewAxis = GetAxis();
encasedAI->Bind(this, FALSE);
}
aiSpawnCount++;
if(spawnArgs.GetBool("monster_hide", "0")) {
encasedAI->ProcessEvent(&EV_Hide);
}
}
}
//
// Event_Trigger()
//
void hhAISpawnCase::Event_Trigger( idEntity *activator ) {
bool triggeredAI = false;
bool showedAI = false;
// We are waiting for an auto-trigger, so don't fire now - but remember that we need to later
if(waitingForAutoTrigger) {
triggerQueue++;
//gameLocal.Printf("\nQUEUED TRIGGERS: %i", triggerQueue);
return;
}
//gameLocal.Printf("\n * TRIGGERED *");
if(encasedAI.GetEntity()) {
if(encasedAI->IsHidden()) {
encasedAI->ProcessEvent(&EV_Show);
showedAI = true;
}
//if triggered_spawn is set, spawn the encasedAI on the first trigger,
//and but don't activate it until a second trigger
if ( !showedAI || !spawnArgs.GetBool( "triggered_spawn", "0" ) ) {
encasedAI->Unbind();
// removed since monster_offset should take care of this
//encasedAI->SetOrigin(encasedAI->GetOrigin() + encasedAI->viewAxis[0] * 64);
encasedAI.GetEntity()->ProcessEvent(&EV_Activate, activator);
triggeredAI = true;
}
}
// Start the anim playing
hhAnimated::Event_Activate(activator);
if ( spawnArgs.GetInt( "no_anim", "0" ) ) {
ProcessEvent(&EV_CreateAI);
//if triggered_spawn is set, dont show the next AI until the next trigger
if ( encasedAI.IsValid() && triggeredAI && spawnArgs.GetBool( "triggered_spawn", "0" ) ) {
encasedAI->ProcessEvent(&EV_Hide);
}
}
triggerToggle = !triggerToggle;
}
//
// Event_AutoTrigger()
//
void hhAISpawnCase::Event_AutoTrigger( void ) {
waitingForAutoTrigger = FALSE;
ProcessEvent(&EV_Activate, this);
}
//
// Event_AnimDone()
//
void hhAISpawnCase::Event_AnimDone( int animIndex ) {
// Call back first
hhAnimated::Event_AnimDone(animIndex);
const char *n = NULL;
// Door is OPEN, now we queue up the CLOSE anim
if(triggerToggle) {
n = spawnArgs.GetString("anim_retrigger");
// Should we automatically retrigger? (ie. close the door after it was opened?)
if(spawnArgs.GetFloat("auto_retrigger_delay", "-1") >= 0.0f ) {
int delay = SEC2MS(spawnArgs.GetFloat("auto_retrigger_delay", "-1"));
waitingForAutoTrigger = TRUE;
PostEventMS(&EV_AutoTrigger, delay);
}
}
// Door is CLOSED, now we queue up the OPEN anim
else {
// If we have queued triggers saved up - then lets fire one now since we are now closed
if(triggerQueue > 0) {
triggerQueue--;
PostEventMS(&EV_Activate, 0, this);
//gameLocal.Printf("\nQUEUED TRIGGERS: %i", triggerQueue);
}
n = spawnArgs.GetString("anim");
int maxMonsters = spawnArgs.GetInt("max_monsters", "1");
if(maxMonsters < 0 || aiSpawnCount < maxMonsters) {
Event_CreateAI();
} else {
//gameLocal.Printf("\nMax monsters reached.");
}
}
anim = GetAnimator()->GetAnim( n );
HH_ASSERT( anim );
}
/*
================
hhAISpawnCase::Save
================
*/
void hhAISpawnCase::Save( idSaveGame *savefile ) const {
encasedAI.Save( savefile );
savefile->WriteBool( triggerToggle );
savefile->WriteInt( aiSpawnCount );
savefile->WriteBool( waitingForAutoTrigger );
savefile->WriteInt( triggerQueue );
}
/*
================
hhAISpawnCase::Restore
================
*/
void hhAISpawnCase::Restore( idRestoreGame *savefile ) {
encasedAI.Restore( savefile );
savefile->ReadBool( triggerToggle );
savefile->ReadInt( aiSpawnCount );
savefile->ReadBool( waitingForAutoTrigger );
savefile->ReadInt( triggerQueue );
CreateEntSpawnArgs();
}
/*
================
hhAISpawnCase::CreateEntSpawnArgs
================
*/
void hhAISpawnCase::CreateEntSpawnArgs( void ) {
// Create list of spawn args, copied to encasedAI in Event_CreateAI
entSpawnArgs.Clear();
idStr tmpStr, realKeyName;
const idKeyValue *kv = spawnArgs.MatchPrefix("ent_", NULL);
while(kv) {
tmpStr = kv->GetKey();
int usIndex = tmpStr.FindChar("ent_", '_');
realKeyName = tmpStr.Mid(usIndex+1, strlen( kv->GetKey())-usIndex-1);
entSpawnArgs.Set(realKeyName, kv->GetValue());
kv = spawnArgs.MatchPrefix("ent_", kv);
}
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef ai_spawncase_H
#define ai_spawncase_H
//
// hhAISpawnCase
//
// Spawns a specific monster, attaches to model - waits for trigger before releasing monster
//
class hhAISpawnCase : public hhAnimated {
public:
CLASS_PROTOTYPE(hhAISpawnCase);
void Spawn( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
virtual void Event_Trigger( idEntity *activator );
virtual void Event_AnimDone( int animIndex );
protected:
void Event_CreateAI( void );
void Event_AutoTrigger( void );
void CreateEntSpawnArgs( void );
idEntityPtr<idAI> encasedAI; // The AI that is currently encased and waiting to come out
bool triggerToggle; // Toggles back and forth to indicated which anim to play (open or close)
int aiSpawnCount; // Current number of monsters spawned
bool waitingForAutoTrigger; // True if we are waiting for an auto-trigger msg to come in (from auto_retrigger_delay setting)
int triggerQueue; // Number of triggers that have occurred during the delay period that must be re-sent
idDict entSpawnArgs; // Spawn args to copy to spawned entities
};
#endif
+403
View File
@@ -0,0 +1,403 @@
//
// ai_speech.cpp
//
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
extern idCVar ai_skipSpeech;
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
//////////////////////////////////////////////////////////////////////
//
// hhAISpeech
//
//////////////////////////////////////////////////////////////////////
// jrm: none yet
//////////////////////////////////////////////////////////////////////
//
// hhAISpeechHandler
//
//////////////////////////////////////////////////////////////////////
float hhAISpeechHandler::TokenMatchWeight[] = {3.0f, 2.0f, 1.0f};
float hhAISpeechHandler::TokenWildcardMatchWeight[] = {1.5f, 1.0f, 0.5f};
#define TokenWildCard "*"
#define SpeechShaderPrefix "snd_speech_" // IF THIS CHANGES YOU MUST CHANGE THE LENGTH DEFINE!
#define SpeechShaderPrefixLen 11
#define FreqToken ':'
#define FreqTokenStr ":"
//
// Construction
//
hhAISpeechHandler::hhAISpeechHandler()
{
firstSpeech = NULL;
lastSpeech = NULL;
nextSpeechTime = 0;
};
//
// Update()
//
void hhAISpeechHandler::Update()
{
hhAISpeech *currSpeech = firstSpeech;
hhAISpeech *nextSpeech = NULL;
if(ai_skipSpeech.GetBool())
return;
//for( currSpeech = speechQueue.Next(); currSpeech != NULL; currSpeech = nextSpeech )
while(currSpeech != NULL)
{
// We can't play any more speech yet!
if(gameLocal.GetTime() < nextSpeechTime)
return;
nextSpeech = currSpeech->next;
// Has this speech expired?
if(gameLocal.GetTime() > currSpeech->expireTime)
{
RemoveSpeechFromQueue(currSpeech);
currSpeech = nextSpeech;
continue;
}
// Play the speech!
currSpeech->speaker->StartSound(currSpeech->snd, SND_CHANNEL_VOICE, 0, true, NULL);
// Debug Start
/*
idStr speechStr;
sprintf(speechStr, "\"%s\"", (const char*)currSpeech->snd);
speechStr.ToLower();
gameRenderWorld->DrawText(speechStr, currSpeech->speaker->GetOrigin() + idVec3(0.0f, 0.0f, 12.0f), 0.5f, colorYellow, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(),1,1000);
gameLocal.Printf("\n%.01f, %s says %s", (float)MS2SEC(gameLocal.GetTime()), (const char*)currSpeech->speaker->name, (const char*)speechStr);
*/
// Debug End
RemoveSpeechFromQueue(currSpeech);
nextSpeechTime = gameLocal.GetTime() + MinSpeechWaitTime;
currSpeech = nextSpeech;
}
};
//
// PlaySpeech()
//
bool hhAISpeechHandler::PlaySpeech(idAI *source, idStr sndShd, int expireDelay, bool allowQueue)
{
if(ai_skipSpeech.GetBool())
return FALSE;
if(!allowQueue) {
// just play it and return
HH_ASSERT(FALSE); // Code not done yet!
return TRUE;
}
// Do we have more slots availble?
hhAISpeech *freeSpeech = GetFreeSpeech();
if(!freeSpeech)
return FALSE;
// Setup the new speech
freeSpeech->speaker = source;
freeSpeech->expireTime = gameLocal.GetTime() + expireDelay;
freeSpeech->snd = sndShd;
AddSpeechToQueue(freeSpeech);
return TRUE;
};
//
// ClearSpeech()
//
void hhAISpeechHandler::ClearSpeech()
{
firstSpeech = NULL;
lastSpeech = NULL;
for(int i=0;i<SpeechPoolSize;i++) {
speechPool[i].Clear();
}
};
//
// getFreeSpeech()
//
hhAISpeech* hhAISpeechHandler::GetFreeSpeech()
{
for(int i=0;i<SpeechPoolSize;i++) {
if(speechPool[i].IsCleared())
return &speechPool[i];
}
return NULL;
};
//
// AddSpeechToQueue()
//
void hhAISpeechHandler::AddSpeechToQueue(hhAISpeech *speech)
{
// First entry?
if(!firstSpeech || !lastSpeech)
{
// this means empty list, so they both better be empty
HH_ASSERT(lastSpeech == NULL);
HH_ASSERT(firstSpeech == NULL);
speech->next = NULL;
speech->prev = NULL;
firstSpeech = speech;
lastSpeech = speech;
return;
}
// Add it to the end of the list
HH_ASSERT(lastSpeech && lastSpeech->next == NULL);
lastSpeech->next = speech;
speech->prev = lastSpeech;
speech->next = NULL;
lastSpeech = speech;
}
//
// RemoveSpeechFromQueue()
//
void hhAISpeechHandler::RemoveSpeechFromQueue(hhAISpeech *speech)
{
speech->Clear();
// Remove from one of the ends?
if(speech == firstSpeech || speech == lastSpeech) {
if(speech == firstSpeech) {
firstSpeech = firstSpeech->next;
if(firstSpeech)
firstSpeech->prev = NULL;
}
if(speech == lastSpeech) {
lastSpeech = lastSpeech->prev;
if(lastSpeech)
lastSpeech->next = NULL;
}
return;
}
// Middle?
if(speech->next)
speech->next->prev = speech->prev;
if(speech->prev)
speech->prev->next = speech->next;
}
//
// GetSpeechFrequency()
//
float hhAISpeechHandler::GetSpeechFrequency(idStr sndShader)
{
if(ai_skipSpeech.GetBool())
return 0.0f;
int firstBreak = sndShader.Find(FreqToken);
if(firstBreak == -1)
return 1.0f;
int secondBreak = sndShader.Find(FreqTokenStr, true, firstBreak);
if(secondBreak == -1)
secondBreak = sndShader.Length();
idStr freqStr = sndShader.Mid(firstBreak, secondBreak - firstBreak);
int f = atoi((const char*)freqStr);
return idMath::ClampFloat(0.0f, 1.0f, (float(f) * 0.01f));
};
//
// GetSpeechResponseDelay()
//
int hhAISpeechHandler::GetSpeechResponseDelay(idStr sndShader)
{
// TODO: Fill this code in when we actually need it. Does 1 second work all the time?
return 500;
};
//
// GetSpeechSoundShader()
//
bool hhAISpeechHandler::GetSpeechSoundShader(idAI *source, idStr speechDesc, idStr &outClosestSndShd)
{
HH_ASSERT(source != NULL);
const idKeyValue *kv = NULL;
if(ai_skipSpeech.GetBool())
return FALSE;
// Quick out - do we have this EXACT snd shader?
idStr sndShader = SpeechShaderPrefix + speechDesc;
kv = source->spawnArgs.MatchPrefix(sndShader);
if(kv) {
outClosestSndShd = kv->GetKey();
return TRUE;
}
// Extrace the tokens for our 'desired' speech pattern
SpeechTokens desired;
if(!ExtractSpeechTokens(speechDesc, desired))
return FALSE;
// Find our best potential speech pattern match
float bestRating = 0.0f;
float currRating = -1.0f;
const idKeyValue *bestKey = NULL;
SpeechTokens currPotential;
kv = source->spawnArgs.MatchPrefix(SpeechShaderPrefix);
while(kv)
{
idStr speechStr;
speechStr = kv->GetKey().Mid(SpeechShaderPrefixLen, kv->GetKey().Length() - SpeechShaderPrefixLen);
if(!ExtractSpeechTokens(speechStr, currPotential))
currRating = -1.0f;
else
currRating = GetMatchRating(desired, currPotential);
if(currRating > bestRating)
{
bestRating = currRating;
bestKey = kv;
}
kv = source->spawnArgs.MatchPrefix(SpeechShaderPrefix,kv);
}
// We've found a match to some degree
if(bestKey && bestRating > 0.0f)
{
outClosestSndShd = bestKey->GetKey();
return TRUE;
}
return FALSE;
};
//
// GetMatchRating()
//
float hhAISpeechHandler::GetMatchRating(SpeechTokens &desired, SpeechTokens &potential)
{
float rating = 0.0f;
for(int i=0;i<TT_Total;i++)
{
if(potential.tokens[i] == desired.tokens[i])
rating += TokenMatchWeight[i];
else if(potential.tokens[i] == TokenWildCard)
rating += TokenWildcardMatchWeight[i];
}
return rating;
};
//
// ExtractSpeechTokens()
//
bool hhAISpeechHandler::ExtractSpeechTokens(idStr speechDesc, SpeechTokens &outTokens)
{
int firstBreak = speechDesc.Find('_');
if(firstBreak < 0)
return FALSE;
int lastBreak = speechDesc.Find("_", true, firstBreak+1);
if(lastBreak < 0)
return FALSE;
outTokens.tokens[TT_Desire] = speechDesc.Mid(0, firstBreak-1);
outTokens.tokens[TT_How] = speechDesc.Mid(firstBreak, lastBreak-(firstBreak));
outTokens.tokens[TT_What] = speechDesc.Mid(lastBreak+1, (speechDesc.Length()-1) - lastBreak);
int findFreqBreak = outTokens.tokens[TT_What].Find(FreqToken);
if(findFreqBreak >= 0)
outTokens.tokens[TT_What] = outTokens.tokens[TT_What].Mid(0, outTokens.tokens[TT_What].Length() - (findFreqBreak+1));
return true;
};
/*
================
hhAISpeechHandler::Save
================
*/
void hhAISpeechHandler::Save(idSaveGame *savefile) const {
for (int i = 0; i < SpeechPoolSize; i++) {
savefile->WriteObject(speechPool[i].speaker);
savefile->WriteString(speechPool[i].snd);
savefile->WriteInt(speechPool[i].expireTime);
savefile->WriteInt(GetPoolIndex(speechPool[i].next));
savefile->WriteInt(GetPoolIndex(speechPool[i].prev));
}
savefile->WriteInt(GetPoolIndex(firstSpeech));
savefile->WriteInt(GetPoolIndex(lastSpeech));
savefile->WriteInt(nextSpeechTime);
}
/*
================
hhAISpeechHandler::Restore
================
*/
void hhAISpeechHandler::Restore(idRestoreGame *savefile) {
int tmp;
for (int i = 0; i < SpeechPoolSize; i++) {
savefile->ReadObject(reinterpret_cast<idClass *&> (speechPool[i].speaker));
savefile->ReadString(speechPool[i].snd);
savefile->ReadInt(speechPool[i].expireTime);
savefile->ReadInt(tmp);
speechPool[i].next = (tmp == -1 ? NULL : &speechPool[tmp]);
savefile->ReadInt(tmp);
speechPool[i].prev = (tmp == -1 ? NULL : &speechPool[tmp]);
}
savefile->ReadInt(tmp);
firstSpeech = (tmp == -1 ? NULL : &speechPool[tmp]);
savefile->ReadInt(tmp);
lastSpeech = (tmp == -1 ? NULL : &speechPool[tmp]);
savefile->ReadInt(nextSpeechTime);
}
int hhAISpeechHandler::GetPoolIndex(hhAISpeech *obj) const {
if (!obj) {
return -1;
}
for (int i = 0; i < SpeechPoolSize; i++) {
if (obj == &speechPool[i]) {
return i;
}
}
HH_ASSERT(!"Couldn't find pool index!");
return -1;
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+102
View File
@@ -0,0 +1,102 @@
#ifndef __HH_AISPEECH_H
#define __HH_AISPEECH_H
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
//
// hhAISpeech
//
class hhAISpeech
{
public:
hhAISpeech() {Clear(); next = NULL; prev = NULL; }
void Clear(void) {speaker = NULL; expireTime = -1;}
bool IsCleared(void) {return speaker == NULL;} // Assumes speech will NEVER come from a 'null' speaker, NULL = empty
idAI* speaker;
idStr snd;
int expireTime;
hhAISpeech *next;
hhAISpeech *prev;
};
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
//
// hhAISpeechHandler
//
class hhAISpeechHandler
{
public:
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
enum
{
SpeechPoolSize = 8,
MinSpeechWaitTime = 2000, // We have to wait at LEAST this long before we can play ANY more speech
};
hhAISpeechHandler();
virtual ~hhAISpeechHandler() { }
virtual void Update(); // note: not named Think() on purpose, because we are NOT an entity
// Play speech from a given AI - returns true if speech was queued - DOES NOT mean it is guarenteed to play
bool PlaySpeech(idAI *source, idStr sndShader, int expireDelay = 1000, bool allowQueue = true);
// Finds the matching snd shader to the speechDesc given, as well as 0->1 of the frequency for this speech
// Returns FALSE if no possible match could be found.
bool GetSpeechSoundShader(idAI *source, idStr speechDesc, idStr &outClosestSndShd);
// From a sound shader name, return the frequency from 0->1
float GetSpeechFrequency(idStr sndShader);
// From a sound shader name, return the delay in MS of how long it takes to 'comprehend' the given shader.
// Example: Someone says "Take the shuttle!" and we want the person taking the shuttle to wait at least 1 second before they do it
// so it looks like they comprehended the command
int GetSpeechResponseDelay(idStr sndShader);
// Remove all queued speech
void ClearSpeech();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
protected:
hhAISpeech speechPool[SpeechPoolSize]; // Pool of all possible speech slots
hhAISpeech* GetFreeSpeech(); // Returns the first empty speech obj available in the pool
int ClearExpiredSpeech(); // Clears out any expired speech in the pool
enum TokenType
{
TT_Desire = 0, // The desire we are going to satisfy
TT_How, // How we are going to satisfy it
TT_What, // What entity we will use to satisfy it
TT_Total,
};
struct SpeechTokens
{
idStr tokens[TT_Total];
};
static float TokenMatchWeight[TT_Total];
static float TokenWildcardMatchWeight[TT_Total];
// Returns a 0+ rating of 'how' close the potential speech matches the desired speech
float GetMatchRating(SpeechTokens &desired, SpeechTokens &potential);
bool ExtractSpeechTokens(idStr speechDesc, SpeechTokens &outTokens);
// because I hate id's linked list
hhAISpeech *firstSpeech;
hhAISpeech *lastSpeech;
void AddSpeechToQueue(hhAISpeech *speech);
void RemoveSpeechFromQueue(hhAISpeech *speech);
int GetPoolIndex(hhAISpeech *obj) const;
int nextSpeechTime; // The time we are next allowed to play speech
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif
+533
View File
@@ -0,0 +1,533 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_UpdateTarget( "<updateTarget>" );
const idEventDef EV_DirectMoveToPosition("directMoveToPosition", "v" );
const idEventDef MA_GetCircleNode("getCircleNode", NULL, 'e' );
const idEventDef MA_SpinClouds("spinClouds", "f" );
const idEventDef MA_SetSeekScale("setSeekScale", "f" );
CLASS_DECLARATION(hhMonsterAI, hhSphereBoss)
EVENT( EV_UpdateTarget, hhSphereBoss::Event_UpdateTarget )
EVENT( EV_DirectMoveToPosition, hhSphereBoss::Event_DirectMoveToPosition )
EVENT( MA_GetCircleNode, hhSphereBoss::Event_GetCircleNode )
EVENT( MA_SpinClouds, hhSphereBoss::Event_SpinClouds )
EVENT( MA_SetSeekScale, hhSphereBoss::Event_SetSeekScale )
END_CLASS
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void hhSphereBoss::Spawn() {
for ( int i=0;i<10;i++ ) {
lastTargetPos.Append( vec3_zero );
}
nextShieldImpact = 0;
lastNodeIndex = -1;
PostEventSec( &EV_UpdateTarget, spawnArgs.GetFloat( "target_period", "0.1" ) );
}
void hhSphereBoss::Event_UpdateTarget() {
for ( int i=0;i<10;i++ ) {
if ( i == 9 ) {
if ( enemy.IsValid() ) {
lastTargetPos[i] = enemy->GetOrigin();
} else {
lastTargetPos[i] = lastTargetPos[i - 1];
}
} else {
lastTargetPos[i] = lastTargetPos[i + 1];
}
}
PostEventSec( &EV_UpdateTarget, spawnArgs.GetFloat( "target_period", "0.1" ) );
}
//overridden to allow custom accuracy/numbers per projectile def
idProjectile *hhSphereBoss::LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef ) {
idVec3 muzzle;
idVec3 dir;
idVec3 start;
trace_t tr;
idBounds projBounds;
float distance;
const idClipModel *projClip;
float attack_accuracy;
float attack_cone;
float projectile_spread;
float diff;
float angle;
float spin;
idAngles ang;
int num_projectiles;
int i;
idMat3 axis;
idVec3 tmp;
idProjectile *lastProjectile;
//HUMANHEAD mdc - added to support multiple projectiles
if( desiredProjectileDef ) { //try to set our projectile to the desiredProjectile
int projIndex = FindProjectileInfo( desiredProjectileDef );
if( projIndex >= 0 ) {
SetCurrentProjectile( projIndex );
}
}
//HUMANHEAD END
if ( !projectileDef ) {
gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
return NULL;
}
if ( projectileDef->GetFloat( "attack_accuracy" ) ) {
attack_accuracy = projectileDef->GetFloat( "attack_accuracy", "7" );
} else {
attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" );
}
attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
if ( projectileDef->GetFloat( "projectile_spread" ) ) {
projectile_spread = projectileDef->GetFloat( "projectile_spread", "0" );
} else {
projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" );
}
if ( projectileDef->GetFloat( "num_projectiles" ) ) {
num_projectiles = projectileDef->GetFloat( "num_projectiles", "1" );
} else {
num_projectiles = spawnArgs.GetFloat( "num_projectiles", "1" );
}
GetMuzzle( jointname, muzzle, axis );
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, axis[ 0 ] );
}
lastProjectile = projectile.GetEntity();
if ( target != NULL ) {
tmp = target->GetPhysics()->GetAbsBounds().GetCenter() - muzzle;
tmp.Normalize();
axis = tmp.ToMat3();
} else {
axis = viewAxis;
}
// rotate it because the cone points up by default
tmp = axis[2];
axis[2] = axis[0];
axis[0] = -tmp;
// make sure the projectile starts inside the monster bounding box
const idBounds &ownerBounds = physicsObj.GetAbsBounds();
projClip = lastProjectile->GetPhysics()->GetClipModel();
projBounds = projClip->GetBounds().Rotate( axis );
// check if the owner bounds is bigger than the projectile bounds
if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
start = muzzle + distance * viewAxis[ 0 ];
} else {
start = ownerBounds.GetCenter();
}
} else {
// projectile bounds bigger than the owner bounds, so just start it from the center
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this );
muzzle = tr.endpos;
// set aiming direction
if ( spawnArgs.GetBool( "lag_target", "0" ) ) {
dir = (lastTargetPos[0] - muzzle).ToNormal();
} else {
GetAimDir( muzzle, target, this, dir );
}
ang = dir.ToAngles();
// adjust his aim so it's not perfect. uses sine based movement so the tracers appear less random in their spread.
float t = MS2SEC( gameLocal.time + entityNumber * 497 );
ang.pitch += idMath::Sin16( t * 5.1 ) * attack_accuracy;
ang.yaw += idMath::Sin16( t * 6.7 ) * attack_accuracy;
if ( clampToAttackCone ) {
// clamp the attack direction to be within monster's attack cone so he doesn't do
// things like throw the missile backwards if you're behind him
diff = idMath::AngleDelta( ang.yaw, current_yaw );
if ( diff > attack_cone ) {
ang.yaw = current_yaw + attack_cone;
} else if ( diff < -attack_cone ) {
ang.yaw = current_yaw - attack_cone;
}
}
axis = ang.ToMat3();
float spreadRad = DEG2RAD( projectile_spread );
for( i = 0; i < num_projectiles; i++ ) {
// spread the projectiles out
angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
dir = axis[ 0 ] + axis[ 2 ] * ( angle * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) );
dir.Normalize();
// launch the projectile
if ( !projectile.GetEntity() ) {
CreateProjectile( muzzle, dir );
}
lastProjectile = projectile.GetEntity();
lastProjectile->Launch( muzzle, dir, vec3_origin );
projectile = NULL;
}
TriggerWeaponEffects( muzzle,axis );
lastAttackTime = gameLocal.time;
//HUMANHEAD mdc - added to support multiple projectiles
projectile = NULL;
SetCurrentProjectile( projectileDefaultDefIndex ); //set back to our default projectile to be on the safe side
//HUMANHEAD END
return lastProjectile;
}
void hhSphereBoss::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
HandleNoGore();
if ( !AI_DEAD ) {
AI_DEAD = true;
state = GetScriptFunction( "state_SphereDeath" );
SetState( state );
SetWaitState( "" );
}
}
void hhSphereBoss::FlyTurn( void ) {
if ( AI_FACE_ENEMY ) {
TurnToward( enemy->GetOrigin() );
} else {
if ( move.moveCommand == MOVE_FACE_ENEMY ) {
TurnToward( lastVisibleEnemyPos );
} else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) {
TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() );
} else if ( move.speed > 0.0f ) {
const idVec3 &vel = physicsObj.GetLinearVelocity();
if ( vel.ToVec2().LengthSqr() > 0.1f ) {
TurnToward( vel.ToYaw() );
}
}
}
Turn();
}
void hhSphereBoss::Event_SetSeekScale( float new_scale ) {
fly_seek_scale = new_scale;
}
void hhSphereBoss::Event_GetCircleNode() {
if ( !enemy.IsValid() ) {
idThread::ReturnEntity( NULL );
return;
}
idEntity *ent = NULL;
idEntity *bestEnt = NULL;
lastNodeIndex++;
for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
if ( !ent || !ent->IsType( hhAINode::Type ) ) {
continue;
}
if ( !ent->spawnArgs.GetBool( "circle_node" ) ) {
continue;
}
if ( lastNodeIndex == ent->spawnArgs.GetInt( "circle_node_index" ) ) {
bestEnt = ent;
break;
}
}
if ( !bestEnt ) {
lastNodeIndex = 0;
for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
if ( !ent || !ent->IsType( hhAINode::Type ) ) {
continue;
}
if ( !ent->spawnArgs.GetBool( "circle_node" ) ) {
continue;
}
if ( lastNodeIndex == ent->spawnArgs.GetInt( "circle_node_index" ) ) {
bestEnt = ent;
break;
}
}
}
if ( bestEnt ) {
idThread::ReturnEntity( bestEnt );
} else {
idThread::ReturnEntity( NULL );
}
}
void hhSphereBoss::Event_GetCombatNode() {
idEntity *ent = NULL;
float bestDist = 0.0f;
float dist;
idEntity *bestEnt = NULL;
idList<idEntity*> list;
for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
if ( !ent || !ent->spawnArgs.GetBool( "ainode" ) ) {
continue;
}
dist = (ent->GetOrigin() - GetOrigin()).Length();
if ( dist < spawnArgs.GetFloat( "node_dist", "400" ) ) {
continue;
}
list.Append( ent );
}
if ( list.Num() > 0 ) {
idThread::ReturnEntity( list[gameLocal.random.RandomInt(list.Num())] );
} else {
idThread::ReturnEntity( NULL );
}
}
void hhSphereBoss::Event_DirectMoveToPosition(const idVec3 &pos) {
StopMove(MOVE_STATUS_DONE);
DirectMoveToPosition(pos);
}
void hhSphereBoss::FlyMove( void ) {
idVec3 goalPos;
idVec3 oldorigin;
idVec3 newDest;
AI_BLOCKED = false;
if ( ( move.moveCommand != MOVE_NONE ) && ReachedPos( move.moveDest, move.moveCommand ) ) {
if ( AI_FACE_ENEMY ) {
StopMove( MOVE_STATUS_DONE );
} else {
AI_MOVE_DONE = true;
}
}
idVec3 vel = physicsObj.GetLinearVelocity();
goalPos = move.moveDest;
if ( ReachedPos( move.moveDest, move.moveCommand ) ) {
StopMove( MOVE_STATUS_DONE );
}
if ( move.speed ) {
FlySeekGoal( vel, goalPos );
}
AddFlyBob( vel );
AdjustFlySpeed( vel );
physicsObj.SetLinearVelocity( vel );
// turn
FlyTurn();
// run the physics for this frame
oldorigin = physicsObj.GetOrigin();
physicsObj.UseFlyMove( true );
physicsObj.UseVelocityMove( false );
physicsObj.SetDelta( vec3_zero );
physicsObj.ForceDeltaMove( disableGravity );
RunPhysics();
monsterMoveResult_t moveResult = physicsObj.GetMoveResult();
if ( !af_push_moveables && attack.Length() && TestMelee() ) {
DirectDamage( attack, enemy.GetEntity() );
} else {
idEntity *blockEnt = physicsObj.GetSlideMoveEntity();
if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) {
KickObstacles( viewAxis[ 0 ], kickForce, blockEnt );
} else if ( moveResult == MM_BLOCKED ) {
move.blockTime = gameLocal.time + 500;
AI_BLOCKED = true;
}
}
idVec3 org = physicsObj.GetOrigin();
if ( oldorigin != org ) {
TouchTriggers();
}
if ( ai_debugMove.GetBool() ) {
gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 4000 );
gameRenderWorld->DebugBounds( colorOrange, physicsObj.GetBounds(), org, gameLocal.msec );
gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec );
gameRenderWorld->DebugLine( colorRed, org, org + physicsObj.GetLinearVelocity(), gameLocal.msec, true );
gameRenderWorld->DebugLine( colorBlue, org, goalPos, gameLocal.msec, true );
gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true );
DrawRoute();
}
}
void hhSphereBoss::AdjustFlySpeed( idVec3 &vel ) {
float speed;
// apply dampening
float damp = spawnArgs.GetFloat( "fly_dampening", "0.01" );
vel -= vel * damp * MS2SEC( gameLocal.msec );
// gradually speed up/slow down to desired speed
speed = vel.Normalize();
speed += ( move.speed - speed ) * MS2SEC( gameLocal.msec );
if ( speed < 0.0f ) {
speed = 0.0f;
} else if ( move.speed && ( speed > move.speed ) ) {
speed = move.speed;
}
vel *= speed;
}
bool hhSphereBoss::ReachedPos( const idVec3 &pos, const moveCommand_t moveCommand ) const {
if ( move.moveType == MOVETYPE_SLIDE ) {
idBounds bnds( idVec3( -4, -4.0f, -8.0f ), idVec3( 4.0f, 4.0f, 64.0f ) );
bnds.TranslateSelf( physicsObj.GetOrigin() );
if ( bnds.ContainsPoint( pos ) ) {
return true;
}
} else {
if ( ( moveCommand == MOVE_TO_ENEMY ) || ( moveCommand == MOVE_TO_ENTITY ) ) {
if ( physicsObj.GetAbsBounds().IntersectsBounds( idBounds( pos ).Expand( 8.0f ) ) ) {
return true;
}
} else {
idBounds bnds( idVec3( -64.0, -64.0f, -64.0f ), idVec3( 64.0, 64.0f, 64.0f ) );
bnds.TranslateSelf( physicsObj.GetOrigin() );
if ( bnds.ContainsPoint( pos ) ) {
return true;
}
}
}
return false;
}
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
void hhSphereBoss::LinkScriptVariables() {
hhMonsterAI::LinkScriptVariables();
LinkScriptVariable( AI_FACE_ENEMY );
LinkScriptVariable( AI_CAN_DAMAGE );
}
void hhSphereBoss::Event_SpinClouds( float shouldSpin ) {
if ( shouldSpin == 0.0f ) {
const idKeyValue *kv = spawnArgs.MatchPrefix( "cloud" );
while( kv ) {
idEntity *ent = gameLocal.FindEntity( kv->GetValue() );
if ( ent ) {
ent->SetShaderParm( spawnArgs.GetInt( "spin_parm", "4" ), ent->spawnArgs.GetFloat( "shaderparm4", "0" ) );
}
kv = spawnArgs.MatchPrefix( "cloud", kv );
}
} else {
const idKeyValue *kv = spawnArgs.MatchPrefix( "cloud" );
while( kv ) {
idEntity *ent = gameLocal.FindEntity( kv->GetValue() );
if ( ent ) {
ent->SetShaderParm( spawnArgs.GetInt( "spin_parm", "4" ), spawnArgs.GetFloat( "spin_value", "0.5" ) );
}
kv = spawnArgs.MatchPrefix( "cloud", kv );
}
}
}
void hhSphereBoss::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
//overridden to allow custom wound code
if ( !AI_CAN_DAMAGE && inflictor && spawnArgs.MatchPrefix("mineDamage") ) {
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone( true );
if ( gameLocal.time >= nextShieldImpact ) {
nextShieldImpact = gameLocal.time + int(spawnArgs.GetFloat( "shield_impact_freq", "0.4" ) * 1000);
idVec3 offset;
if ( attacker && inflictor ) {
offset = (attacker->GetOrigin() - inflictor->GetOrigin()).ToNormal() * spawnArgs.GetFloat( "shield_impact_offset", "150" );
const char *defName = spawnArgs.GetString( "fx_shield_impact" );
idEntityFx *impactFx = SpawnFxLocal( defName, inflictor->GetOrigin() + offset, mat3_identity, &fxInfo, gameLocal.isClient );
if ( impactFx ) {
impactFx->Bind( this, true );
}
}
}
StartSound( "snd_shield_impact", SND_CHANNEL_BODY );
if ( inflictor && inflictor->IsType( idProjectile::Type ) ) {
inflictor->PostEventMS( &EV_Remove, 0 );
}
} else {
hhFxInfo fxInfo;
fxInfo.RemoveWhenDone( true );
if ( gameLocal.time >= nextShieldImpact ) {
nextShieldImpact = gameLocal.time + int(spawnArgs.GetFloat( "shield_impact_freq", "0.4" ) * 1000);
idVec3 offset;
if ( attacker && inflictor ) {
offset = (attacker->GetOrigin() - inflictor->GetOrigin()).ToNormal() * spawnArgs.GetFloat( "shield_impact_offset", "150" );
BroadcastFxInfoPrefixed( "fx_pain_impact", inflictor->GetOrigin() + offset, mat3_identity, &fxInfo );
}
}
}
bool mine_damage = false;
if ( !AI_CAN_DAMAGE && spawnArgs.MatchPrefix("mineDamage") != NULL ) {
const idKeyValue *kv = spawnArgs.MatchPrefix("mineDamage");
while( kv && kv->GetValue().Length() ) {
if ( !kv->GetValue().Icmp(damageDefName) ) {
mine_damage = true;
break;
}
kv = spawnArgs.MatchPrefix("mineDamage", kv);
}
if (!mine_damage) {
return;
}
}
if ( !mine_damage ) {
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
}
if ( !AI_CAN_DAMAGE && health > 0 ) {
SetState( GetScriptFunction( "state_Pain" ) );
SetWaitState( "" );
}
}
/*
=====================
hhSphereBoss::Save
=====================
*/
void hhSphereBoss::Save( idSaveGame *savefile ) const {
savefile->WriteInt( lastTargetPos.Num() );
savefile->WriteInt( nextShieldImpact );
for ( int i=0;i<lastTargetPos.Num(); i++) {
savefile->WriteVec3( lastTargetPos[i] );
}
}
/*
=====================
hhSphereBoss::Restore
=====================
*/
void hhSphereBoss::Restore( idRestoreGame *savefile ) {
int num = 0;
savefile->ReadInt( num );
savefile->ReadInt( nextShieldImpact );
lastTargetPos.SetNum( num );
for ( int i=0;i<num; i++) {
savefile->ReadVec3( lastTargetPos[i] );
}
}
void hhSphereBoss::AddLocalMatterWound( jointHandle_t jointNum, const idVec3 &localOrigin, const idVec3 &localNormal, const idVec3 &localDir, int damageDefIndex, const idMaterial *collisionMaterial ) {
//overridden to remove woundmanager hook and use custom wound code is Damage()
if ( AI_CAN_DAMAGE ) {
return hhMonsterAI::AddLocalMatterWound( jointNum, localOrigin, localNormal, localDir, damageDefIndex, collisionMaterial );
}
}
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
+45
View File
@@ -0,0 +1,45 @@
#ifndef __PREY_AI_SPHEREBOSS_H__
#define __PREY_AI_SPHEREBOSS_H__
class hhSphereBoss : public hhMonsterAI {
public:
CLASS_PROTOTYPE(hhSphereBoss);
#ifdef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
void Event_UpdateTarget() {};
void Event_GetCombatNode() {};
void Event_GetCircleNode() {};
void Event_DirectMoveToPosition(const idVec3 &pos) {};
void Event_SpinClouds( float shouldSpin ) {};
void Event_SetSeekScale( float new_scale ) {};
#else
void Spawn();
void FlyTurn();
void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
idProjectile *LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone, const idDict* desiredProjectileDef );
void AdjustFlySpeed( idVec3 &vel );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void FlyMove( void );
bool ReachedPos( const idVec3 &pos, const moveCommand_t moveCommand ) const;
void LinkScriptVariables();
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
void AddLocalMatterWound( jointHandle_t jointNum, const idVec3 &localOrigin, const idVec3 &localNormal, const idVec3 &localDir, int damageDefIndex, const idMaterial *collisionMaterial );
void Event_UpdateTarget();
void Event_GetCombatNode();
void Event_GetCircleNode();
void Event_DirectMoveToPosition(const idVec3 &pos);
void Event_SpinClouds( float shouldSpin );
void Event_SetSeekScale( float new_scale );
protected:
idScriptBool AI_FACE_ENEMY;
idScriptBool AI_CAN_DAMAGE;
idList<idVec3> lastTargetPos;
int lastNodeIndex;
int nextShieldImpact;
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
};
#endif
+104
View File
@@ -0,0 +1,104 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
#include "../../renderer/Model_local.h" // Hackish. Needed to access certain classes. Imitates game/anim/Blend.cpp
/*
===============
hhMD5Anim::hhMD5Anim
===============
*/
hhMD5Anim::hhMD5Anim(void) {
start = 0.0f;
end = 1.0f;
}
/*
==============================
hhMD5Anim::setLimits
Set the limits of the animation to play.
start and end should vary from 0 to 1
==============================
*/
void hhMD5Anim::SetLimits(float start, float end) const {
if (start <= end) {
this->start = start;
this->end = end;
}
else {
this->start = end;
this->end = start;
}
}
/*
==============================
hhMD5Anim::ConvertTimeToFrame
==============================
*/
void hhMD5Anim::ConvertTimeToFrame( int time, int cycleCount,
frameBlend_t &frame ) const {
float newTime;
float timeOffset;
timeOffset = animLength * start;
if (time < 0) {
newTime = timeOffset;
}
else {
newTime = time + timeOffset;
}
idMD5Anim::ConvertTimeToFrame(newTime, cycleCount, frame);
}
/*
==============================
hhMD5Anim::Length
==============================
*/
int hhMD5Anim::Length(void) const {
int intLength;
intLength = animLength * (end - start);
if ( ( intLength == 0 ) && ( end != start ) ) {
intLength = 1;
}
return( intLength );
}
/*
================
hhMD5Anim::Save
================
*/
void hhMD5Anim::Save( idSaveGame *savefile ) const {
savefile->WriteFloat( start );
savefile->WriteFloat( end );
}
/*
================
hhMD5Anim::Restore
================
*/
void hhMD5Anim::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat( start );
savefile->ReadFloat( end );
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef __PREY_ANIM_MD5ANIM_H__
#define __PREY_ANIM_MD5ANIM_H__
// Forward declar
class idMD5Bone;
class hhMD5Anim : public idMD5Anim {
public:
hhMD5Anim(void);
void SetLimits(float start, float end) const;
virtual void ConvertTimeToFrame( int time, int cycleCount, frameBlend_t &frame ) const;
virtual int Length( void ) const;
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
protected:
mutable float start;
mutable float end;
};
#endif /* __PREY_ANIM_MD5ANIM_H__ */
+173
View File
@@ -0,0 +1,173 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
CLASS_DECLARATION( idForce, hhForce_Converge )
END_CLASS
hhForce_Converge::hhForce_Converge( void ) {
restoreFactor = 1.0f;
restoreForceSlack = 1.0f;
restoreTime = 0.1f;
ent = NULL;
physics = NULL;
axisEnt = NULL;
bShuttle = false;
}
hhForce_Converge::~hhForce_Converge( void ) {
}
void hhForce_Converge::Save(idSaveGame *savefile) const {
ent.Save(savefile);
axisEnt.Save(savefile);
savefile->WriteVec3( target );
savefile->WriteVec3( offset );
savefile->WriteInt( bodyID );
savefile->WriteFloat( restoreTime );
savefile->WriteFloat( restoreFactor );
savefile->WriteFloat( restoreForceSlack );
savefile->WriteBool( bShuttle );
}
void hhForce_Converge::Restore( idRestoreGame *savefile ) {
ent.Restore(savefile);
axisEnt.Restore(savefile);
savefile->ReadVec3( target );
savefile->ReadVec3( offset );
savefile->ReadInt( bodyID );
savefile->ReadFloat( restoreTime );
savefile->ReadFloat( restoreFactor );
savefile->ReadFloat( restoreForceSlack );
savefile->ReadBool( bShuttle );
physics = NULL; // HUMANHEAD mdl: Updated each frame
}
void hhForce_Converge::Evaluate( int time ) {
// Get the physics of ent each frame, in case their physics object was changed.
physics = ent.IsValid() ? ent->GetPhysics() : NULL;
// Apply convergent force
if (physics) {
idVec3 p = physics->GetOrigin( bodyID ) + offset * physics->GetAxis( bodyID );
idVec3 x = p - target;
if (axisEnt.IsValid()) {
idBounds bounds = ent->GetPhysics()->GetBounds();
idVec3 rightPt = ent->GetOrigin() + (ent->GetAxis()[0] * bounds[0].x);
idVec3 axisRightPt = axisEnt->GetOrigin() + (axisEnt->GetAxis()[1] * bounds[1].x);
idVec3 leftPt = ent->GetOrigin() + (ent->GetAxis()[0] * bounds[1].x);
idVec3 axisLeftPt = axisEnt->GetOrigin() + (axisEnt->GetAxis()[1] * bounds[0].x);
//gameRenderWorld->DebugLine(idVec4(1, 0, 0, 1), rightPt, axisRightPt, 100);
p = rightPt;
x = p - axisRightPt;
x *= restoreForceSlack; //allow a linear buildup based on the distance of the target point
idVec3 v = physics->GetLinearVelocity();
float m = physics->GetMass();
float b = idMath::Sqrt(4*restoreFactor*m);
idVec3 force = -restoreFactor*x - b*v; // use with addforce, k=200000
physics->AddForce(bodyID, p, force * 0.5f ); // Great to show mass variations
//gameRenderWorld->DebugLine(idVec4(1, 0, 0, 1), leftPt, axisLeftPt, 100);
p = leftPt;
x = p - axisLeftPt;
x *= restoreForceSlack; //allow a linear buildup based on the distance of the target point
force = axisLeftPt - leftPt;
force *= m * 4;
physics->AddForce(bodyID, p, force ); // Great to show mass variations
return;
}
x *= restoreForceSlack; //allow a linear buildup based on the distance of the target point
if (ent->IsType(idAFEntity_Base::Type)) { // Actors use velocity method since their masses are unrealistic, ragdolls need it too
if (!ent->fl.tooHeavyForTractor) {
// Velocity method: cover distance in fixed time
idVec3 velocity = -x / restoreTime; // Use with SetLinearVelocity()
if (ent->IsType(idActor::Type)) { //if a player is affected by this force..
//..do not allow him to build up velocity into his ground plane
if (ent->GetPhysics()->IsType(idPhysics_Player::Type) && ent->GetPhysics()->HasGroundContacts()) {
velocity.x *= -ent->GetPhysics()->GetGravityNormal().x;
velocity.y *= -ent->GetPhysics()->GetGravityNormal().y;
velocity.z *= -ent->GetPhysics()->GetGravityNormal().z;
}
}
physics->SetLinearVelocity(velocity, bodyID);
}
else {
// Entities that are too heavy get no force, just give feedback force
}
} else {
float m = physics->GetMass();
if (bShuttle && m < 1500.0f) { // Different equation for picking up low mass objects with the shuttle
idVec3 v = physics->GetLinearVelocity();
float springFactor = restoreFactor*0.0002f;
float dampFactor = idMath::Sqrt(springFactor);
idVec3 force = (-x * springFactor * m) - (v * dampFactor * m);
physics->AddForce(bodyID, p, force );
} else { // Critically Damped spring: m*a = -k*x - b*v ; b = 2 * sqrt(m*k)
idVec3 v = physics->GetLinearVelocity();
float m = physics->GetMass();
float b = idMath::Sqrt(4.0f*restoreFactor*m);
idVec3 force = -restoreFactor*x - b*v; // use with addforce, k=200000
physics->AddForce(bodyID, p, force ); // Great to show mass variations
}
}
/* else { // Impulse method
idVec3 v = physics->GetLinearVelocity();
float b = idMath::Sqrt(4*restoreFactor);
impulse = -restoreFactor*x - b*v; // Use with applyimpulse, k=50000
physics->ApplyImpulse(bodyID, p, impulse ); // Worked for all but some moveables (k=50000)
}
else { // Mass scaled force method, applies varying force to keep constant velocity
idVec3 v = physics->GetLinearVelocity();
float m = physics->GetMass();
float b = idMath::Sqrt(4*restoreFactor);
impulse = (-restoreFactor*x - b*v) * m; // use with addforce, k=500
physics->AddForce(bodyID, p, impulse ); // Works for all but ragdolls (k=500)
}
}*/
}
}
void hhForce_Converge::RemovePhysics( const idPhysics *phys ) {
// physics of ent is stored each evaluate so we can compare pointers directly, rather than querying
// ent about it's physics. This is done because typically, physics objects are reported as removed
// during deconstruction of the entities.
if (ent.IsValid() && phys == physics) {
SetEntity(NULL);
}
}
void hhForce_Converge::SetRestoreTime( float time ) {
restoreTime = idMath::ClampFloat(0.02f, time, time);
}
void hhForce_Converge::SetTarget(idVec3 &newTarget) {
target = newTarget;
}
void hhForce_Converge::SetEntity(idEntity *entity, int id, const idVec3 &point) {
ent = entity;
bodyID = id;
offset = point;
physics = NULL;
}
void hhForce_Converge::SetAxisEntity(idEntity *entity) {
axisEnt = entity;
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef __FORCE_CONVERGE_H__
#define __FORCE_CONVERGE_H__
//===============================================================================
//
// Convergent force
//
//===============================================================================
class hhForce_Converge : public idForce {
CLASS_PROTOTYPE( hhForce_Converge );
public:
hhForce_Converge( void );
virtual ~hhForce_Converge( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void SetTarget(idVec3 &newTarget);
void SetEntity(idEntity *entity, int id=0, const idVec3 &point=vec3_origin);
idEntity * GetEntity() const { return ent.GetEntity(); }
void SetRestoreTime( float time );
void SetRestoreFactor( float factor ){ restoreFactor = factor; }
void SetRestoreSlack(float slack) { restoreForceSlack = slack; }
public: // common force interface
virtual void Evaluate( int time );
virtual void RemovePhysics( const idPhysics *phys );
void SetAxisEntity(idEntity *entity);
void SetShuttle(bool shuttle) { bShuttle = shuttle; }
private:
idEntityPtr<idEntity> ent; // Entity to apply forces to
idEntityPtr<idEntity> axisEnt;
idPhysics * physics; // physics object of entity during last evaluate
idVec3 target; // Point of convergence
idVec3 offset; // Entity local offset for force application
int bodyID; // Body ID for force application
float restoreTime; // Ideal convergence time
float restoreFactor; // Spring constant for restorative force
float restoreForceSlack; //rww - allow a linear buildup based on the distance of the target point
bool bShuttle; //mdl: Use an alternate spring equation for shuttle tractor beam
};
#endif
+100
View File
@@ -0,0 +1,100 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
/***********************************************************************
hhAFEntity
***********************************************************************/
// nla - Added to allow the mappers to do huge translations w/out too much bouncing
const idEventDef EV_EnableRagdoll( "enableRagdoll", "" );
const idEventDef EV_DisableRagdoll( "disableRagdoll", "" );
CLASS_DECLARATION( idAFEntity_Generic, hhAFEntity )
EVENT( EV_EnableRagdoll, hhAFEntity::Event_EnableRagdoll )
EVENT( EV_DisableRagdoll, hhAFEntity::Event_DisableRagdoll )
END_CLASS
void hhAFEntity::Spawn( void ) {
fl.takedamage = !spawnArgs.GetBool("noDamage");
if (spawnArgs.FindKey("gravity")) {
PostEventMS(&EV_ResetGravity, 100); // Post after first think, when gravity is reset by UpdateGravity()
}
}
void hhAFEntity::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
if ( CheckRagdollDamage( inflictor, attacker, dir, damageDefName, location ) ) {
return;
}
idAFEntity_Generic::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
}
//This is so ragdolls shutdown when attached to movers that are outside of the pvs.
void hhAFEntity::DormantBegin() {
idEntity::DormantBegin();
Event_DisableRagdoll();
}
void hhAFEntity::DormantEnd() {
idEntity::DormantEnd();
Event_EnableRagdoll();
}
void hhAFEntity::Event_EnableRagdoll() {
af.GetPhysics()->Thaw();
}
void hhAFEntity::Event_DisableRagdoll() {
af.GetPhysics()->Freeze();
}
/***********************************************************************
hhAFEntity_WithAttachedHead
***********************************************************************/
CLASS_DECLARATION( idAFEntity_WithAttachedHead, hhAFEntity_WithAttachedHead )
EVENT( EV_EnableRagdoll, hhAFEntity_WithAttachedHead::Event_EnableRagdoll )
EVENT( EV_DisableRagdoll, hhAFEntity_WithAttachedHead::Event_DisableRagdoll )
END_CLASS
void hhAFEntity_WithAttachedHead::Spawn( void ) {
fl.takedamage = !spawnArgs.GetBool("noDamage");
if (spawnArgs.FindKey("gravity")) {
PostEventMS(&EV_ResetGravity, 100); // Post after first think, when gravity is reset by UpdateGravity()
}
}
void hhAFEntity_WithAttachedHead::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
if ( CheckRagdollDamage( inflictor, attacker, dir, damageDefName, location ) ) {
return;
}
idAFEntity_WithAttachedHead::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
}
//This is so ragdolls shutdown when attached to movers that are outside of the pvs.
void hhAFEntity_WithAttachedHead::DormantBegin() {
idEntity::DormantBegin();
Event_DisableRagdoll();
}
void hhAFEntity_WithAttachedHead::DormantEnd() {
idEntity::DormantEnd();
Event_EnableRagdoll();
}
void hhAFEntity_WithAttachedHead::Event_EnableRagdoll() {
af.GetPhysics()->Thaw();
}
void hhAFEntity_WithAttachedHead::Event_DisableRagdoll() {
af.GetPhysics()->Freeze();
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef __GAME_AFS_H__
#define __GAME_AFS_H__
extern const idEventDef EV_CursorDrop;
extern const idEventDef EV_CursorDone;
/***********************************************************************
hhAFEntity
***********************************************************************/
class hhAFEntity : public idAFEntity_Generic {
public:
CLASS_PROTOTYPE( hhAFEntity );
void Spawn();
virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
virtual void DormantBegin();
virtual void DormantEnd();
void Event_EnableRagdoll( void );
void Event_DisableRagdoll( void );
};
/***********************************************************************
hhAFEntity_WithAttachedHead
***********************************************************************/
class hhAFEntity_WithAttachedHead : public idAFEntity_WithAttachedHead {
public:
CLASS_PROTOTYPE( hhAFEntity_WithAttachedHead );
void Spawn();
virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location );
virtual void DormantBegin();
virtual void DormantEnd();
void Event_EnableRagdoll();
void Event_DisableRagdoll();
};
#endif // __GAME_AFS_H__
+76
View File
@@ -0,0 +1,76 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
//==========================================================================
//
// hhAlarmLight
//
//==========================================================================
CLASS_DECLARATION(idLight, hhAlarmLight)
EVENT(EV_Activate, hhAlarmLight::Event_Activate)
END_CLASS
void hhAlarmLight::Spawn() {
bAlarmOn = false;
fl.takedamage = false; // Never take damage
/* Shader parms set up like this (so the editor shows the light being on):
parm6 parm7
editor(on): 0 0
spawn(off): 1 0
trigger(on): 1 1
broken(off): 1 0
*/
SetParmState(1.0f, 0.0f);
// setup the clipModel
GetPhysics()->SetContents( CONTENTS_SOLID );
}
void hhAlarmLight::Save(idSaveGame *savefile) const {
savefile->WriteBool( bAlarmOn );
}
void hhAlarmLight::Restore( idRestoreGame *savefile ) {
savefile->ReadBool( bAlarmOn );
}
void hhAlarmLight::TurnOn() {
if (!bAlarmOn) {
bAlarmOn = true;
StartSound("snd_alarm", SND_CHANNEL_BODY2, 0, true, NULL);
SetParmState(1.0f, 1.0f);
}
}
void hhAlarmLight::TurnOff() {
if (bAlarmOn) {
bAlarmOn = false;
StopSound(SND_CHANNEL_BODY2, true);
SetParmState(0.0f, 1.0f);
}
}
void hhAlarmLight::SetParmState(float value6, float value7) {
SetShaderParm(6, value6);
SetShaderParm(7, value7);
SetLightParm(6, value6);
SetLightParm(7, value7);
}
void hhAlarmLight::Event_Activate(idEntity *activator) {
if (bAlarmOn) {
if (activator && activator->IsType(hhPlayer::Type)) {
TurnOff();
}
}
else {
TurnOn();
}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef __GAME_ALARMLIGHT_H__
#define __GAME_ALARMLIGHT_H__
class hhAlarmLight : public idLight {
CLASS_PROTOTYPE( hhAlarmLight );
public:
void Spawn();
void TurnOn();
void TurnOff();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
protected:
void SetParmState(float value6, float value7);
void Event_Activate(idEntity *activator);
bool bAlarmOn;
};
#endif
+244
View File
@@ -0,0 +1,244 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
/*
============
hhAnim::AddFrameCommandExtra
============
*/
bool hhAnim::AddFrameCommandExtra( idToken &token, frameCommand_t &fc, idLexer &src, idStr &errorText ) {
errorText = "";
if ( token == "stopSnd" ) {
fc.type = FC_STOPSND;
return( true );
} else if ( token == "stopSnd_voice" ) {
fc.type = FC_STOPSND_VOICE;
return( true );
} else if ( token == "stopSnd_voice2" ) {
fc.type = FC_STOPSND_VOICE2;
return( true );
} else if ( token == "stopSnd_body" ) {
fc.type = FC_STOPSND_BODY;
return( true );
} else if ( token == "stopSnd_body2" ) {
fc.type = FC_STOPSND_BODY2;
return( true );
} else if ( token == "stopSnd_body3" ) {
fc.type = FC_STOPSND_BODY3;
return( true );
} else if ( token == "stopSnd_weapon" ) {
fc.type = FC_STOPSND_WEAPON;
return( true );
} else if ( token == "stopSnd_item" ) {
fc.type = FC_STOPSND_ITEM;
return( true );
} else if ( token == "event_args" ) {
fc.type = FC_EVENT_ARGS;
src.ParseRestOfLine( token );
idStr error = InitFrameCommandEvent( fc, token );
if( error.Length() ) {
errorText = error.c_str();
return( false );
}
return( true );
} else if ( token == "launch_missile" ) {
/* HUMANHEAD JRM - Because we parse out the joint when launched
if ( !modelDef->FindJoint( cmd ) ) {
return va( "Joint '%s' not found", cmd.c_str() );
}
*/
src.ParseRestOfLine( token );
/* HUMANHEAD JRM - need the rest of the line not just one token
if( !src.ReadTokenOnLine( &token ) ) {
errorText = va( "Unexpected end of line" );
return( true );
}
*/
fc.type = FC_LAUNCHMISSILE;
fc.string = new idStr( token );
return( true );
} else if( token == "launch_altMissile" ) {
if( !src.ReadTokenOnLine( &token ) ) {
errorText = va( "Unexpected end of line" );
return( true );
}
fc.type = FC_LAUNCHALTMISSILE;
fc.string = new idStr( token );
return( true );
} else if ( token == "launch_missile_bonedir" ) {
/* HUMANHEAD JRM - we want the whole token
if( !src.ReadTokenOnLine( &token ) ) {
errorText = va( "Unexpected end of line" );
return( true );
}
*/
src.ParseRestOfLine( token );
fc.type = FC_LAUNCHMISSILE_BONEDIR;
fc.string = new idStr( token );
return( true );
} else if ( token == "leftfootprint" ) {
fc.type = FC_LEFTFOOTPRINT;
return( true );
} else if ( token == "rightfootprint" ) {
fc.type = FC_RIGHTFOOTPRINT;
return( true );
} else if ( token == "mood" ) {
fc.type = FC_MOOD;
if( !src.ReadTokenOnLine( &token ) ) {
fc.string = new idStr( "" );
return( true );
}
fc.string = new idStr( token );
return( true );
} else if ( token == "kick_obstacle" ) {
if( !src.ReadTokenOnLine( &token ) ) {
errorText = va( "Unexpected end of line" );
return( true );
}
fc.type = FC_KICK_OBSTACLE;
fc.string = new idStr( token );
return( true );
} else if ( token == "trigger_anim_ent" ) {
/*
if( !src.ReadTokenOnLine( &token ) ) {
errorText = va( "Unexpected end of line" );
return( true );
}
*/
fc.type = FC_TRIGGER_ANIM_ENT;
return( true );
} else if ( token == "set_key" ) {
fc.type = FC_SETKEY;
if( !src.ParseRestOfLine( token ) ) {
errorText = va( "Unexpected end of line" );
return ( true );
}
if( !fc.parmList ) {
fc.parmList = new idList<idStr>;
}
hhUtils::SplitString( token, *fc.parmList, ' ' );
if( fc.parmList->Num() != 2 ) {
errorText = va( "Invalid number of arguments for setkey frame-command" );
return ( true );
}
return ( true );
}
return( false );
}
/*
============
hhAnim::CallFrameCommandsExtra
============
*/
bool hhAnim::CallFrameCommandsExtra( const frameCommand_t &command, idEntity *ent ) const {
switch( command.type ) {
case FC_EVENT_ARGS: {
if ( command.function && command.parmList && command.function->eventdef ) {
ent->ProcessEvent( command.function->eventdef, (int)command.parmList );
}
return( true );
}
case FC_LAUNCHALTMISSILE: {
//ent->ProcessEvent( &AI_AttackAltMissile, command.string->c_str(), NULL );
return( true );
}
case FC_STOPSND:
case FC_STOPSND_VOICE:
case FC_STOPSND_VOICE2:
case FC_STOPSND_BODY:
case FC_STOPSND_BODY2:
case FC_STOPSND_BODY3:
case FC_STOPSND_WEAPON:
case FC_STOPSND_ITEM: {
ent->StopSound( s_channelType(command.type - FC_STOPSND), false ); //rww - do not broadcast
return( true );
}
case FC_HIDE: {
ent->ProcessEvent( &EV_Hide );
return( true );
}
case FC_MOOD: {
if(command.string) {
ent->ProcessEvent( &AI_SetAnimPrefix, command.string->c_str());
} else {
ent->ProcessEvent( &AI_SetAnimPrefix, " ");
}
return( true );
}
case FC_LEFTFOOTPRINT: {
ent->ProcessEvent( &EV_FootprintLeft );
return( true );
}
case FC_RIGHTFOOTPRINT: {
ent->ProcessEvent( &EV_FootprintRight );
return( true );
}
case FC_LAUNCHMISSILE: { // JRM: changed to AttackMissileEx (so we can pass in projectile)
ent->ProcessEvent( &MA_AttackMissileEx, command.string->c_str(),0 );
return( true );
}
case FC_LAUNCHMISSILE_BONEDIR: { // JRM: need so we can launch missiles
ent->ProcessEvent( &MA_AttackMissileEx, command.string->c_str(),1 );
return( true );
}
case FC_SETKEY: {//mdc: added to be able to set keys from frame commands
if( command.parmList && command.parmList->Num() == 2 ) {
ent->spawnArgs.Set( (*command.parmList)[0].c_str(), (*command.parmList)[1].c_str() );
}
return ( true );
}
}
return( false );
}
/*
=====================
hhAnim::InitFrameCommandEvent
=====================
*/
idStr hhAnim::InitFrameCommandEvent( frameCommand_t &command, const idStr& cmdStr ) const {
idStr error;
if( !command.parmList ) {
command.parmList = new idList<idStr>;
}
hhUtils::SplitString( cmdStr, *command.parmList, ' ' );
// Find the function
command.function = gameLocal.program.FindFunction( (*command.parmList)[0].c_str(), gameLocal.program.FindType((*command.parmList)[0].c_str()) );
if( !command.function || !command.function->eventdef || command.function->eventdef->GetNumArgs() != 1 ) {
error = va("Invalid event('%s') for frameCommands event or event_args\n", (*command.parmList)[0].c_str() );
}
//Remove function name from the list
command.parmList->RemoveIndex( 0 );
//If no parms are needed, no need to waste memory
if( command.parmList->Num() <= 0 ) {
SAFE_DELETE_PTR( command.parmList );
}
return error;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef __PREY_GAME_ANIM_H__
#define __PREY_GAME_ANIM_H__
class hhAnim : public idAnim {
public:
hhAnim() : idAnim() { exactMatch = false; }
hhAnim( const idDeclModelDef *modelDef, const idAnim *anim ) : idAnim( modelDef, anim ) { }
virtual bool AddFrameCommandExtra( idToken &token, frameCommand_t &fc, idLexer &src, idStr &errorText );
virtual bool CallFrameCommandsExtra( const frameCommand_t &command, idEntity *ent ) const;
bool exactMatch;
protected:
virtual idStr InitFrameCommandEvent( frameCommand_t &command, const idStr& cmdStr ) const;
};
#endif /* __PREY_GAME_ANIM_H__ */
+276
View File
@@ -0,0 +1,276 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
/*
============
hhAnimBlend::hhAnimBlend
============
*/
hhAnimBlend::hhAnimBlend() {
frozen = false;
freezeStart = -1;
freezeEnd = -1;
freezeCurrent = -1;
rotateTime = -1;
rotateEvent = NULL;
}
/*
=====================
hhAnimBlend::FrameHasChanged
=====================
*/
bool hhAnimBlend::FrameHasChanged( int currentTime ) const {
UpdateFreezeTime( currentTime );
if ( frozen ) {
return false;
}
return( idAnimBlend::FrameHasChanged( currentTime ) );
}
/*
=====================
hhAnimBlend::AnimTime
=====================
*/
int hhAnimBlend::AnimTime( int currentTime ) const {
if ( animNum ) {
UpdateFreezeTime( currentTime );
}
return( idAnimBlend::AnimTime( currentTime ) );
}
/*
=====================
hhAnimBlend::GetFrameNumber
=====================
*/
int hhAnimBlend::GetFrameNumber( int currentTime ) const {
//gameLocal.Printf( "In FRAME NUM\n" );
UpdateFreezeTime( currentTime );
return( idAnimBlend::GetFrameNumber( currentTime ) );
}
/*
=====================
hhAnimBlend::CallFrameCommands
=====================
*/
void hhAnimBlend::CallFrameCommands( idEntity *ent, int fromtime, int totime ) const {
if ( frozen ) {
return;
}
idAnimBlend::CallFrameCommands( ent, fromtime, totime );
}
/*
=====================
hhAnimBlend::BlendAnim
=====================
*/
bool hhAnimBlend::BlendAnim( int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOriginOffset, bool overrideBlend, bool printInfo ) const {
UpdateFreezeTime( currentTime );
return( idAnimBlend::BlendAnim( currentTime, channel, numJoints, blendFrame, blendWeight, removeOriginOffset, overrideBlend, printInfo ) );
}
/*
=====================
hhAnimBlend::BlendOrigin
=====================
*/
void hhAnimBlend::BlendOrigin( int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset ) const {
//gameLocal.Printf( "BLEND ORIGIN\n" );
UpdateFreezeTime( currentTime );
if ( frozen ) {
return;
}
idAnimBlend::BlendOrigin( currentTime, blendPos, blendWeight, removeOriginOffset );
}
/*
=====================
hhAnimBlend::BlendDelta
=====================
*/
void hhAnimBlend::BlendDelta( int fromtime, int totime, idVec3 &blendDelta, float &blendWeight ) const {
if ( frozen ) {
return;
}
idAnimBlend::BlendDelta( fromtime, totime, blendDelta, blendWeight );
}
/*
=====================
hhAnimBlend::AddBounds
=====================
*/
bool hhAnimBlend::AddBounds( int currentTime, idBounds &bounds, bool removeOriginOffset ) const {
UpdateFreezeTime( currentTime );
if ( frozen ) {
return false;
}
return( idAnimBlend::AddBounds( currentTime, bounds, removeOriginOffset ) );
}
/*
===============
hhAnimBlend::UpdateFreezeTime
===============
*/
void hhAnimBlend::UpdateFreezeTime( int currentTime ) const {
if ( !frozen ) {
return;
}
if ( currentTime > freezeCurrent ) {
starttime += currentTime - freezeCurrent;
endtime += currentTime - freezeCurrent;
freezeCurrent = currentTime;
}
}
extern const idEventDef EV_CheckThaw;
/*
================
hhAnimBlend::Freeze
Freeze the animation
Inputs: currentTime - The current time of freeze
freezeEnd - Delta time to end the freeze. Set to -1 if will thaw manually
Outputs: true if frozen successfully, false otherwise
HUMANHEAD nla
================
*/
bool hhAnimBlend::Freeze( int currentTime, idEntity *owner, int aFreezeEnd ) {
if ( frozen ) {
return( false );
}
frozen = true;
freezeStart = currentTime;
freezeCurrent = currentTime;
freezeEnd = currentTime + aFreezeEnd;
// Post the thaw event if time is known
if ( owner ) {
owner->PostEventMS( &EV_CheckThaw, aFreezeEnd );
}
else {
gameLocal.Warning( "Freeze called on an animator with no owner!" );
}
return( true );
}
/*
===============
hhAnimBlend::Freeze
HUMANHEAD nla
===============
*/
bool hhAnimBlend::Freeze( int currentTime, idEntity *owner ) {
return( Freeze( currentTime, owner, -1 ) );
}
/*
===============
hhAnimBlend::Thaw
HUMANHEAD nla
===============
*/
bool hhAnimBlend::Thaw( int currentTime ) {
if ( !frozen ) {
return( false );
}
UpdateFreezeTime( currentTime );
frozen = false;
return( true );
}
/*
===============
hhAnimBlend::ThawIfTime
HUMANHEAD nla
===============
*/
bool hhAnimBlend::ThawIfTime( int currentTime ) {
if ( !frozen ) {
return( false );
}
if ( freezeEnd < 0 ) {
return( false );
}
if ( currentTime >= freezeEnd ) {
return( Thaw( currentTime ) );
}
return( false );
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef __PREY_GAME_ANIMBLEND_H__
#define __PREY_GAME_ANIMBLEND_H__
#endif /* __PREY_GAME_ANIMBLEND_H__ */
+287
View File
@@ -0,0 +1,287 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_PlayCycle( "<playCycle>", "ds" );
CLASS_DECLARATION( hhAnimatedEntity, hhAnimDriven )
EVENT( EV_PlayCycle, hhAnimDriven::Event_PlayCycle )
END_CLASS
//==============
// hhAnimDriven::Spawn
//==============
void hhAnimDriven::Spawn() {
passenger = NULL;
hadPassenger = false;
spawnTime = gameLocal.time;
// We are gonna move the guy manually, turn off having the anim move him
GetAnimator()->RemoveOriginOffset( true );
// How do we deal with our owner?
physicsAnim.SetSelf( this );
if( spawnArgs.GetBool( "solid", "0" ) ) {
fl.takedamage = true;
physicsAnim.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
GetPhysics()->SetContents( CONTENTS_SOLID );
} else {
fl.takedamage = false;
GetPhysics()->SetContents( 0 );
physicsAnim.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
GetPhysics()->UnlinkClip();
}
// move up to make sure the monster is at least an epsilon above the floor
physicsAnim.SetOrigin( GetOrigin() + idVec3( 0, 0, CM_CLIP_EPSILON ) );
SetPhysics( &physicsAnim );
//? Have this start at a set time afterwards?
int animLength = PlayAnim( ANIMCHANNEL_ALL, "initial" );
PostEventMS( &EV_PlayCycle, animLength, ANIMCHANNEL_ALL, "move" );
float delta_min = spawnArgs.GetFloat( "delta_scale_min", "1.0" );
float delta_max = spawnArgs.GetFloat( "delta_scale_max", "1.0" );
if ( delta_min != 1.0f || delta_max != 1.0f ) {
deltaScale.x = idMath::ClampFloat( delta_min, delta_max, gameLocal.random.RandomFloat() );
deltaScale.y = idMath::ClampFloat( delta_min, delta_max, gameLocal.random.RandomFloat() );
deltaScale.z = idMath::ClampFloat( delta_min, delta_max, gameLocal.random.RandomFloat() );
} else {
deltaScale = idVec3( 1.0f, 1.0f, 1.0f );
}
BecomeActive( TH_TICKER );
}
void hhAnimDriven::Save(idSaveGame *savefile) const {
savefile->WriteStaticObject( physicsAnim );
passenger.Save(savefile);
savefile->WriteInt( spawnTime );
savefile->WriteBool( hadPassenger );
}
void hhAnimDriven::Restore( idRestoreGame *savefile ) {
savefile->ReadStaticObject( physicsAnim );
passenger.Restore(savefile);
savefile->ReadInt( spawnTime );
savefile->ReadBool( hadPassenger );
}
//=============
// hhAnimDriven::SetPassenger
//=============
void hhAnimDriven::SetPassenger( idEntity *newPassenger, bool orientFromPassenger ) {
idVec3 origin;
idMat3 axis;
//?! Right now handle only 1 passenger. If we have one, warn and exit.
if ( passenger.IsValid() ) {
const char *oldName = passenger->GetName();
const char *newName = "NULL";
if ( newPassenger ) {
newName = newPassenger->GetName();
}
gameLocal.Warning( "Error: hhAnimDriven::SetPassenger tried to add passenger %s but already had %s\n",
newName, oldName );
return;
}
passenger = newPassenger;
hadPassenger = true;
fl.takedamage = true;
if ( orientFromPassenger ) {
origin = passenger->GetOrigin();
axis = passenger->GetAxis();
}
GetPhysics()->SetClipModel( new idClipModel( passenger->GetPhysics()->GetClipModel() ), 1.0f );
GetPhysics()->SetContents( passenger->GetPhysics()->GetContents() );
GetPhysics()->SetClipMask( passenger->GetPhysics()->GetClipMask() );
if ( orientFromPassenger ) {
SetOrigin( origin );
SetAxis( axis );
}
passenger->Bind( this, true );
}
//==============
// hhAnimDriven::Think
//==============
void hhAnimDriven::Think() {
idVec3 delta;
// Done move unless we have a passenger. (Give us like 10 secs to get one)
if ( !passenger.IsValid() ) {
// If we had a passenger, they removed themselves, and so should we :)
if ( hadPassenger ) {
PostEventMS( &EV_Remove, 0 );
}
// If never had a passenger for a second, remove ourselves
else if ( gameLocal.time - spawnTime > 1000 ) {
PostEventMS( &EV_Remove, 0 );
gameLocal.Warning( "hhAnimDriven %s existed for a second w/out a passenger. Removing.", GetName() );
}
return;
}
// Move them based on their anim
GetAnimator()->GetDelta( gameLocal.time - gameLocal.msec, gameLocal.time, delta );
delta *= GetAxis();
delta.x *= deltaScale.x;
delta.y *= deltaScale.y;
delta.z *= deltaScale.z;
physicsAnim.SetDelta( delta );
// gameLocal.Printf( "%d Doing %s\n", gameLocal.GetTime(), delta.ToString() );
hhAnimatedEntity::Think();
}
//============
//
//============
int hhAnimDriven::PlayAnim( int channel, const char *animName ) {
int animIndex;
int length;
animIndex = GetAnimator()->GetAnim( animName );
if ( !animIndex ) {
return( 0 );
}
//gameLocal.Printf( "Playing Anim %s\n", animName );
GetAnimator()->PlayAnim( channel, animIndex, gameLocal.GetTime(), 0 );
length = GetAnimator()->CurrentAnim( channel )->GetEndTime() - gameLocal.GetTime();
return( length );
}
//============
// hhAnimDrive::Event_PlayCycle()
//============
void hhAnimDriven::Event_PlayCycle( int channel, const char *animName ) {
PlayCycle( channel, animName );
}
//============
//
//============
bool hhAnimDriven::PlayCycle( int channel, const char *animName ) {
int animIndex;
animIndex = GetAnimator()->GetAnim( animName );
if ( !animIndex ) {
return( false );
}
//gameLocal.Printf( "Cycling Anim %s\n", animName );
GetAnimator()->CycleAnim( channel, animIndex, gameLocal.GetTime(), 0 );
return( true );
}
/*
================
hhAnimDriven::ClearAllAnims
================
*/
void hhAnimDriven::ClearAllAnims() {
GetAnimator()->ClearAllAnims( gameLocal.GetTime(), 0 );
}
//===========
//
//============
bool hhAnimDriven::Collide( const trace_t &collision, const idVec3 &velocity ) {
// If we hit something, and have a passenger, pass along the message
if( passenger.IsValid() ) {
if( !passenger->Collide(collision, velocity) ) {
return( false );
}
passenger->Unbind();
} //. We have a valid passenger
// If we made it this far, assume the collision is for real, and
// remove ourselves from interacting with the world
fl.takedamage = false;
GetPhysics()->SetContents( 0 );
GetPhysics()->UnlinkClip();
ClearAllAnims();
PostEventMS( &EV_Remove, 0 );
return( true );
}
bool hhAnimDriven::AllowCollision( const trace_t& collision ) {
if ( !spawnArgs.GetBool( "projectile_collision", "1" ) ) {
idEntity* ent = gameLocal.entities[ collision.c.entityNum ];
if ( !ent || ent->IsType( idProjectile::Type ) ) {
return false;
}
}
return true;
}
void hhAnimDriven::UpdateAnimation( void ) {
PROFILE_SCOPE("Animation", PROFMASK_NORMAL); // HUMANHEAD pdm
// don't do animations if they're not enabled
if ( !( thinkFlags & TH_ANIMATE ) ) {
return;
}
// is the model an MD5?
if ( !animator.ModelHandle() ) {
// no, so nothing to do
return;
}
// call any frame commands that have happened in the past frame
if ( !fl.hidden ) {
animator.ServiceAnims( gameLocal.previousTime, gameLocal.time );
}
// if the model is animating then we have to update it
if ( !animator.FrameHasChanged( gameLocal.time ) ) {
// still fine the way it was
return;
}
// update the renderEntity
UpdateVisuals();
// the animation is updated
animator.ClearForceUpdate();
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef __PREY_GAME_ANIMDRIVEN_H__
#define __PREY_GAME_ANIMDRIVEN_H__
// Class name by Jimmy! :)
class hhAnimDriven : public hhAnimatedEntity {
public:
CLASS_PROTOTYPE( hhAnimDriven );
void Spawn();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
virtual void Think();
void SetPassenger( idEntity *newPassenger, bool orientFromPassenger = true );
// Events
void Event_PlayCycle( int channel, const char *animName );
bool Collide( const trace_t &collision, const idVec3 &velocity );
int PlayAnim( int channel, const char *animName );
bool PlayCycle( int channel, const char *animName );
void ClearAllAnims();
void UpdateAnimation();
bool AllowCollision( const trace_t& collision );
protected:
hhPhysics_Delta physicsAnim;
idEntityPtr<idEntity> passenger;
int spawnTime;
bool hadPassenger;
idVec3 deltaScale; //scale anim delta movement by this
};
#endif /* __PREY_GAME_ANIMDRIVEN_H__ */
+424
View File
@@ -0,0 +1,424 @@
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_CheckCycleRotate( "<checkCycleRotate>" );
const idEventDef EV_CheckThaw( "<checkThaw>" );
const idEventDef EV_SpawnFxAlongBone( "spawnFXAlongBone", "d" );
const idEventDef EV_Silent( "<silent>", NULL );
CLASS_DECLARATION( idAnimatedEntity, hhAnimatedEntity )
EVENT( EV_CheckCycleRotate, hhAnimatedEntity::Event_CheckAnimatorCycleRotate )
EVENT( EV_CheckThaw, hhAnimatedEntity::Event_CheckAnimatorThaw )
EVENT( EV_SpawnFxAlongBone, hhAnimatedEntity::Event_SpawnFXAlongBone )
EVENT( EV_Thread_SetSilenceCallback,hhAnimatedEntity::Event_SetSilenceCallback )
EVENT( EV_Silent, hhAnimatedEntity::Event_Silent )
END_CLASS
/*
==============
hhAnimatedEntity::Spawn
==============
*/
void hhAnimatedEntity::Spawn( void ) {
hasFlapInfo = false;
// nla - Added to allow for 1 frame anims to play/proper bone initialization
if ( GetAnimator() ) {
int anim = GetAnimator()->GetAnim("init");
if ( anim ) {
GetAnimator()->PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, 0);
GetAnimator()->ForceUpdate();
UpdateModel();
}
}
}
void hhAnimatedEntity::Save(idSaveGame *savefile) const {
savefile->WriteInt( waitingThread );
savefile->WriteInt( silentTimeOffset );
savefile->WriteInt( nextSilentTime );
savefile->WriteFloat( lastAmplitude );
}
void hhAnimatedEntity::Restore( idRestoreGame *savefile ) {
savefile->ReadInt( waitingThread );
savefile->ReadInt( silentTimeOffset );
savefile->ReadInt( nextSilentTime );
savefile->ReadFloat( lastAmplitude );
hasFlapInfo = false;
}
/*
==============
hhAnimatedEntity::hhAnimatedEntity
==============
*/
hhAnimatedEntity::hhAnimatedEntity() {
// WaitForSilence support
waitingThread = 0;
silentTimeOffset = 0;
nextSilentTime = 0;
lastAmplitude = 0.0f;
hasFlapInfo = false;
}
/*
==============
hhAnimatedEntity::~hhAnimatedEntity
==============
*/
hhAnimatedEntity::~hhAnimatedEntity() {
Event_Silent();
}
/*
==============
hhAnimatedEntity::FillDebugVars
==============
*/
void hhAnimatedEntity::FillDebugVars(idDict *args, int page) {
switch(page) {
case 1:
args->SetInt("anims", GetAnimator()->NumAnims());
break;
}
idAnimatedEntity::FillDebugVars(args, page);
}
/*
==============
hhAnimatedEntity::Think
==============
*/
void hhAnimatedEntity::Think() {
idAnimatedEntity::Think();
//HUMANHEAD: aob - moved from idActor
UpdateWounds();
//HUMANHEAD END
}
/*
=====================
hhAnimatedEntity::GetAnimator
=====================
*/
hhAnimator *hhAnimatedEntity::GetAnimator( void ) {
return &animator;
}
/*
=====================
hhAnimatedEntity::GetAnimator
=====================
*/
const hhAnimator *hhAnimatedEntity::GetAnimator( void ) const {
return &animator;
}
/*
=====================
hhAnimatedEntity::GetJointWorldTransform
=====================
*/
bool hhAnimatedEntity::GetJointWorldTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
return idAnimatedEntity::GetJointWorldTransform( jointHandle, currentTime, offset, axis );
}
/*
=====================
hhAnimatedEntity::GetJointWorldTransform
=====================
*/
bool hhAnimatedEntity::GetJointWorldTransform( const char* jointName, idVec3 &offset, idMat3 &axis ) {
return GetJointWorldTransform( GetAnimator()->GetJointHandle(jointName), gameLocal.GetTime(), offset, axis );
}
/*
=====================
hhAnimatedEntity::GetJointWorldTransform
=====================
*/
bool hhAnimatedEntity::GetJointWorldTransform( jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis ) {
return GetJointWorldTransform( jointHandle, gameLocal.GetTime(), offset, axis );
}
/*
==============
hhAnimatedEntity::UpdateWounds
==============
*/
void hhAnimatedEntity::UpdateWounds( void ) {
}
/*
==================
idEntity::SpawnFXAlongBonePrefixLocal
==================
*/
void hhAnimatedEntity::SpawnFxAlongBonePrefixLocal( const idDict* dict, const char* fxKeyPrefix, const char* bonePrefix, const hhFxInfo* const fxInfo, const idEventDef* eventDef ) {
idVec3 bonePos;
idMat3 boneAxis;
for( const idKeyValue* kv = dict->MatchPrefix(bonePrefix); kv; kv = dict->MatchPrefix(bonePrefix, kv) ) {
if( !kv->GetValue().Length() ) {
continue;
}
GetJointWorldTransform( kv->GetValue().c_str(), bonePos, boneAxis );
SpawnFXPrefixLocal( dict, fxKeyPrefix, bonePos, boneAxis, fxInfo, eventDef );
}
}
/*
=================
hhAnimatedEntity::SpawnFXAlongBone
=================
*/
void hhAnimatedEntity::BroadcastFxInfoAlongBonePrefix( const idDict* args, const char* fxKey, const char* bonePrefix, const hhFxInfo* const fxInfo, const idEventDef* eventDef, bool broadcast ) {
if( !fxKey || !fxKey[0] || !bonePrefix || !bonePrefix[0] ) {
return;
}
idVec3 bonePos;
idMat3 boneAxis;
hhFxInfo localFxInfo( fxInfo );
localFxInfo.SetEntity( this );
localFxInfo.RemoveWhenDone( true );
const idKeyValue* keyValue = args->MatchPrefix( bonePrefix );
while( keyValue && keyValue->GetValue().Length() ) {
if( GetJointWorldTransform( keyValue->GetValue().c_str(), bonePos, boneAxis ) ) {
//AOB: HACK - crashed in idBitMsg::DirToBits because we didn't appear to be normalized
localFxInfo.SetNormal( boneAxis[0].ToNormal() );
localFxInfo.SetBindBone( keyValue->GetValue().c_str() );
BroadcastFxInfoPrefixed( fxKey, bonePos, boneAxis, &localFxInfo, eventDef, broadcast );
}
keyValue = args->MatchPrefix( bonePrefix, keyValue );
}
}
/*
=================
hhAnimatedEntity::SpawnFXAlongBone
mdl
=================
*/
void hhAnimatedEntity::BroadcastFxInfoAlongBonePrefixUnique( const idDict* args, const char* fxKey, const char* bonePrefix, const hhFxInfo* const fxInfo, const idEventDef* eventDef, bool broadcast ) {
if( !fxKey || !fxKey[0] || !bonePrefix || !bonePrefix[0] ) {
return;
}
idVec3 bonePos;
idMat3 boneAxis;
hhFxInfo localFxInfo( fxInfo );
localFxInfo.SetEntity( this );
localFxInfo.RemoveWhenDone( true );
const idKeyValue* keyValue = args->MatchPrefix( bonePrefix );
idStr postfix;
int prefixLen = strlen( bonePrefix );
while( keyValue && keyValue->GetValue().Length() ) {
postfix = keyValue->GetKey().Right( keyValue->GetKey().Length() - prefixLen );
if( GetJointWorldTransform( keyValue->GetValue().c_str(), bonePos, boneAxis ) ) {
//AOB: HACK - crashed in idBitMsg::DirToBits because we didn't appear to be normalized
localFxInfo.SetNormal( boneAxis[0].ToNormal() );
localFxInfo.SetBindBone( keyValue->GetValue().c_str() );
// Changed this because it was causing every fx listed to be bound to every bone listed. -mdl
BroadcastFxInfo( spawnArgs.GetString( fxKey + postfix ), bonePos, boneAxis, &localFxInfo, eventDef, broadcast );
//BroadcastFxInfoPrefixed( fxKey, bonePos, boneAxis, &localFxInfo, eventDef );
}
keyValue = args->MatchPrefix( bonePrefix, keyValue );
}
}
/*
================
hhAnimatedEntity::SpawnFxAlongBone
================
*/
void hhAnimatedEntity::BroadcastFxInfoAlongBone( const char* fxName, const char* boneName, const hhFxInfo* const fxInfo, const idEventDef* eventDef, bool broadcast ) {
//mdc: pass through to our newer version of the function (this is mainly done for backwards compatibility)
BroadcastFxInfoAlongBone( false, fxName, boneName, fxInfo, eventDef, broadcast );
}
void hhAnimatedEntity::BroadcastFxInfoAlongBone( bool bNoRemoveWhenUnbound, const char* fxName, const char* boneName, const hhFxInfo* const fxInfo, const idEventDef* eventDef, bool broadcast ) {
if( !fxName || !fxName[0] || !boneName || !boneName[0] ) {
return;
}
idVec3 bonePos;
idMat3 boneAxis;
hhFxInfo localFxInfo( fxInfo );
GetJointWorldTransform( boneName, bonePos, boneAxis );
localFxInfo.SetNormal( boneAxis[0] );
localFxInfo.SetEntity( this );
localFxInfo.NoRemoveWhenUnbound( bNoRemoveWhenUnbound ); //mdc: added
localFxInfo.SetBindBone( boneName );
BroadcastFxInfo( fxName, bonePos, boneAxis, &localFxInfo, eventDef, broadcast );
}
/*
================
hhAnimatedEntity::Event_SpawnFXAlongBone
================
*/
void hhAnimatedEntity::Event_SpawnFXAlongBone( idList<idStr>* fxParms ) {
if ( !fxParms ) {
return;
}
bool bNoRemoveWhenUnbound = false; //default to false (we normally want to delete fx when the bound-entity is deleted)
HH_ASSERT( fxParms->Num() >= 2 && fxParms->Num() <= 3 ); //allow 2-3 parameters
if( fxParms->Num() == 3 ) {
//make sure the 3rd paramater is our special noRemoveWhenUnbound flag
if( !idStr::Icmp((*fxParms)[2].c_str(), "noremovewhenunbound") ) {
bNoRemoveWhenUnbound = true;
}
else {
gameLocal.Warning( "unrecognized 3rd paramater on frame command for SpawnFXAlongBone on entity '%s'", this->GetName() );
}
}
BroadcastFxInfoAlongBone(bNoRemoveWhenUnbound, spawnArgs.GetString((*fxParms)[0].c_str()), (*fxParms)[1].c_str() );
}
// HUMANHEAD pdm: Jaw flapping support
// This provides generalized support for any animated entity to translate voice channel sound to bone movements
void hhAnimatedEntity::JawFlap(hhAnimator *theAnimator) {
PROFILE_SCOPE("Jaw Flap", PROFMASK_NORMAL);
float amplitude = 0.0f;
if (fl.noJawFlap || !g_jawflap.GetBool()) {
return;
}
// Get amplitude from head or body
idEntity *headEntity = NULL;
if (IsType(idActor::Type)) {
headEntity = static_cast<idActor*>(this)->GetHead();
if (headEntity && headEntity->GetSoundEmitter()) {
amplitude = headEntity->GetSoundEmitter()->CurrentVoiceAmplitude( SND_CHANNEL_VOICE );
}
}
if( amplitude == 0.0f && GetSoundEmitter() ) {
amplitude = GetSoundEmitter()->CurrentVoiceAmplitude( SND_CHANNEL_VOICE );
}
if (amplitude != 0.0f || lastAmplitude != 0.0f) {
//HUMANHEAD rww - only get the joint handles and info for jaw flapping once
//we have to do this here, since the head is not valid at hhAnimatedEntity::Spawn
if (!hasFlapInfo) {
jawFlapList.Clear();
const char *prefix = "jawbone_";
const idKeyValue *kv = spawnArgs.MatchPrefix(prefix);
while( kv && kv->GetValue().Length() ) {
jointHandle_t bone = theAnimator->GetJointHandle( kv->GetValue() );
if (bone != INVALID_JOINT) {
jawFlapInfo_t flapInfo;
idStr xformName = kv->GetKey();
xformName.Strip(prefix);
flapInfo.bone = bone;
flapInfo.rMagnitude = spawnArgs.GetVector( va("jawflapR_%s", xformName.c_str()) );
flapInfo.tMagnitude = spawnArgs.GetVector( va("jawflapT_%s", xformName.c_str()) );
flapInfo.rMinThreshold = spawnArgs.GetFloat( va("jawflapRMin_%s", xformName.c_str()) );
flapInfo.tMinThreshold = spawnArgs.GetFloat( va("jawflapTMin_%s", xformName.c_str()) );
jawFlapList.Append(flapInfo);
}
kv = spawnArgs.MatchPrefix(prefix, kv);
}
hasFlapInfo = true;
}
lastAmplitude = amplitude;
//HUMANHEAD rww - changed to use a list and not do constant runtime joint lookups
for (int i = 0; i < jawFlapList.Num(); i++) {
jawFlapInfo_t &flapInfo = jawFlapList[i];
// Handle Rotation
idAngles angles = ang_zero;
if (amplitude > flapInfo.rMinThreshold) {
float factor = amplitude - flapInfo.rMinThreshold;
angles = idAngles(factor*flapInfo.rMagnitude[0], factor*flapInfo.rMagnitude[1], factor*flapInfo.rMagnitude[2]);
}
theAnimator->SetJointAxis( flapInfo.bone, JOINTMOD_WORLD, angles.ToMat3() );
// Handle translation
idVec3 translate = vec3_origin;
if (amplitude > flapInfo.tMinThreshold) {
float factor = amplitude - flapInfo.tMinThreshold;
translate = idVec3(factor*flapInfo.tMagnitude[0], factor*flapInfo.tMagnitude[1], factor*flapInfo.tMagnitude[2]);
}
theAnimator->SetJointPos( flapInfo.bone, JOINTMOD_WORLD, translate );
}
}
}
// WaitForSilence support: Tracks the next time the voice channel will be silent, and if any threads are doing a waitForSilence() block, calls them back.
// If a waitForSilence() call is issued while no sound is playing on the voice channel, it will wait until there is something and then wait for silence.
bool hhAnimatedEntity::StartSoundShader( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) {
int localLength = 0;
bool retVal = idAnimatedEntity::StartSoundShader(shader, channel, soundShaderFlags, broadcast, &localLength);
// need to track 'nextSilentTime' locally also, so if a tiny sound is played after a longer sound, it doesn't think silence will follow short sound
if (channel == SND_CHANNEL_VOICE && (localLength > 0) && (gameLocal.time + localLength > nextSilentTime)) {
nextSilentTime = gameLocal.time + localLength;
// If there's already a thread waiting for silence and this sound pushes silence out further, repost an event for it
if (waitingThread) {
CancelEvents(&EV_Silent);
int time = localLength+silentTimeOffset;
time = idMath::ClampInt(1, time, time); // Keep positive and wait at least 1ms
PostEventMS(&EV_Silent, time);
}
}
if (length) {
*length = localLength;
}
return retVal;
}
void hhAnimatedEntity::Event_Silent() {
if (waitingThread) {
idThread::ObjectMoveDone( waitingThread, this );
waitingThread = 0;
}
}
void hhAnimatedEntity::Event_SetSilenceCallback(float plusOrMinusSeconds) {
if (!waitingThread) {
waitingThread = idThread::CurrentThreadNum();
silentTimeOffset = SEC2MS(plusOrMinusSeconds);
if (nextSilentTime > gameLocal.time) {
// If sound already playing
int time = (nextSilentTime - gameLocal.time) + silentTimeOffset;
time = idMath::ClampInt(1, time, time); // Keep positive and wait at least 1ms
CancelEvents(&EV_Silent);
PostEventMS(&EV_Silent, time);
}
else {
// No sound playing, wait for sound to play first
}
idThread::ReturnInt( true );
}
else {
idThread::ReturnInt( false );
}
}

Some files were not shown because too many files have changed in this diff Show More