commit 684d1bcb3b0e12adee29cd3c83f99aca49cd201e Author: James Monroe Date: Thu Apr 4 17:35:38 2013 -0500 Jedi Academy Release diff --git a/code/0_compiled_first/0_SH_Leak.cpp b/code/0_compiled_first/0_SH_Leak.cpp new file mode 100644 index 0000000..adfd5a5 --- /dev/null +++ b/code/0_compiled_first/0_SH_Leak.cpp @@ -0,0 +1,774 @@ +// leave this as first line for PCH reasons... +// +#pragma warning( disable : 4786) +#pragma warning( disable : 4100) +#pragma warning( disable : 4663) +#include + +#include "..\smartheap\smrtheap.h" +#include "../game/q_shared.h" +#include "..\qcommon\qcommon.h" + +#include +#include + +using namespace std; + +#if MEM_DEBUG +#include "..\smartheap\heapagnt.h" + +static const int maxStack=2048; +static int TotalMem; +static int TotalBlocks; +static int nStack; +static char StackNames[maxStack][256]; +static int StackSize[maxStack]; +static int StackCount[maxStack]; +static int StackCache[48]; +static int StackCacheAt=0; +static int CheckpointSize[3000]; +static int CheckpointCount[3000]; + +//#define _FASTRPT_ + + +#ifdef _FASTRPT_ +class CMyStrComparator +{ +public: + bool operator()(const char *s1, const char *s2) const { return(strcmp(s1, s2) < 0); } +}; + +hmap Lookup; +#endif + +cvar_t *mem_leakfile; +cvar_t *mem_leakreport; + +MEM_BOOL MEM_CALLBACK MyMemReporter2(MEM_ERROR_INFO *info) +{ + static char buffer[10000]; + if (!info->objectCreationInfo) + return 1; + info=info->objectCreationInfo; + int idx=info->checkpoint; + if (idx<0||idx>=1000) + { + idx=0; + } + CheckpointCount[idx]++; + CheckpointSize[idx]+=info->argSize; + dbgMemFormatCall(info,buffer,9999); + if (strstr(buffer,"ntdll")) + return 1; + if (strstr(buffer,"CLBCATQ")) + return 1; + int i; + TotalBlocks++; + if (TotalBlocks%1000==0) + { + char mess[1000]; + sprintf(mess,"%d blocks processed\n",TotalBlocks); + OutputDebugString(mess); + } + for (i=strlen(buffer);i>0;i--) + { + if (buffer[i]=='\n') + break; + } + if (!i) + return 1; + buffer[i]=0; + char *buf=buffer; + while (*buf) + { + if (*buf=='\n') + { + buf++; + break; + } + buf++; + } + char *start=0; + char *altName=0; + while (*buf) + { + while (*buf==' ') + buf++; + start=buf; + while (*buf!=0&&*buf!='\n') + buf++; + if (*start) + { + if (*buf) + { + *buf=0; + buf++; + } + if (strlen(start)>255) + start[255]=0; + if (strstr(start,"std::")) + { + altName="std::??"; +// start=0; + continue; + } + if (strstr(start,"Malloc")) + { + altName="Malloc??"; + start=0; + continue; + } + if (strstr(start,"G_Alloc")) + { + altName="G_Alloc"; + start=0; + continue; + } + if (strstr(start,"Hunk_Alloc")) + { + altName="Hunk_Alloc"; + start=0; + continue; + } + if (strstr(start,"FS_LoadFile")) + { + altName="FS_LoadFile"; + start=0; + continue; + } + if (strstr(start,"CopyString")) + { + altName="CopyString"; + start=0; + continue; + } + break; + } + } + if (!start||!*start) + { + start=altName; + if (!start||!*start) + { + start="UNKNOWN"; + } + } +#ifdef _FASTRPT_ + hmap::iterator f=Lookup.find(start); + if(f==Lookup.end()) + { + strcpy(StackNames[nStack++],start); + Lookup[(const char *)&StackNames[nStack-1]]=nStack-1; + StackSize[nStack-1]=info->argSize; + StackCount[nStack-1]=1; + } + else + { + StackSize[(*f).second]+=info->argSize; + StackCount[(*f).second]++; + } +#else + for (i=0;i<48;i++) + { + if (StackCache[i]<0||StackCache[i]>=nStack) + continue; + if (!strcmpi(start,StackNames[StackCache[i]])) + break; + } + if (i<48) + { + StackSize[StackCache[i]]+=info->argSize; + StackCount[StackCache[i]]++; + } + else + { + for (i=0;iargSize; + StackCount[i]++; + StackCache[StackCacheAt]=i; + StackCacheAt++; + if (StackCacheAt>=48) + StackCacheAt=0; + } + else if (iargSize; + StackCount[i]=1; + nStack++; + } + else if (nStackargSize; + StackCount[maxStack-1]=1; + } + else + { + StackSize[maxStack-1]+=info->argSize; + StackCount[maxStack-1]++; + } + } +#endif + TotalMem+=info->argSize; + return 1; +} + +MEM_BOOL MEM_CALLBACK MyMemReporter3(MEM_ERROR_INFO *info) +{ + static char buffer[10000]; + if (!info->objectCreationInfo) + return 1; + info=info->objectCreationInfo; + int idx=info->checkpoint; + if (idx<0||idx>=3000) + { + idx=0; + } + CheckpointCount[idx]++; + CheckpointSize[idx]+=info->argSize; + dbgMemFormatCall(info,buffer,9999); + int i; + TotalBlocks++; +// if (TotalBlocks%1000==0) +// { +// char mess[1000]; +// sprintf(mess,"%d blocks processed\n",TotalBlocks); +// OutputDebugString(mess); +// } + for (i=strlen(buffer);i>0;i--) + { + if (buffer[i]=='\n') + break; + } + if (!i) + return 1; + buffer[i]=0; + char *buf=buffer; + while (*buf) + { + if (*buf=='\n') + { + buf++; + break; + } + buf++; + } + char *start=0; + char *altName=0; + while (*buf) + { + while (*buf==' ') + buf++; + start=buf; + while (*buf!=0&&*buf!='\n') + buf++; + if (*start) + { + if (*buf) + { + *buf=0; + buf++; + } + if (strlen(start)>255) + start[255]=0; + if (strstr(start,"SV_AreaEntities")) + { + altName="SV_AreaEntities??"; + start=0; + continue; + } + if (strstr(start,"SV_Trace")) + { + altName="SV_Trace??"; + start=0; + continue; + } + if (strstr(start,"SV_PointContents")) + { + altName="SV_PointContents??"; + start=0; + continue; + } + if (strstr(start,"CG_Trace")) + { + altName="??"; + start=0; + continue; + } + if (strstr(start,"CG_PointContents")) + { + altName="??"; + start=0; + continue; + } +/* + if (strstr(start,"")) + { + altName="??"; + start=0; + continue; + } + if (strstr(start,"")) + { + altName="??"; + start=0; + continue; + } +*/ + break; + } + } + if (!start||!*start) + { + start=altName; + if (!start||!*start) + { + start="UNKNOWN"; + } + } +#ifdef _FASTRPT_ + hmap::iterator f=Lookup.find(start); + if(f==Lookup.end()) + { + strcpy(StackNames[nStack++],start); + Lookup[(const char *)&StackNames[nStack-1]]=nStack-1; + StackSize[nStack-1]=info->argSize; + StackCount[nStack-1]=1; + } + else + { + StackSize[(*f).second]+=info->argSize; + StackCount[(*f).second]++; + } +#else + for (i=0;i<48;i++) + { + if (StackCache[i]<0||StackCache[i]>=nStack) + continue; + if (!strcmpi(start,StackNames[StackCache[i]])) + break; + } + if (i<48) + { + StackSize[StackCache[i]]+=info->argSize; + StackCount[StackCache[i]]++; + } + else + { + for (i=0;iargSize; + StackCount[i]++; + StackCache[StackCacheAt]=i; + StackCacheAt++; + if (StackCacheAt>=48) + StackCacheAt=0; + } + else if (iargSize; + StackCount[i]=1; + nStack++; + } + else if (nStackargSize; + StackCount[maxStack-1]=1; + } + else + { + StackSize[maxStack-1]+=info->argSize; + StackCount[maxStack-1]++; + } + } +#endif + TotalMem+=info->argSize; + return 1; +} + +void SH_Checking_f(void); +#endif + +class Leakage +{ + MEM_POOL MyPool; + +public: + Leakage() + { + MyPool = MemInitDefaultPool(); +// MemPoolSetSmallBlockSize(MyPool, 16); + MemPoolSetSmallBlockAllocator(MyPool,MEM_SMALL_BLOCK_SH3); +#if MEM_DEBUG + dbgMemSetGuardSize(2); + EnableChecking(100000); +#endif + } + + void LeakReport(void) + { +#if MEM_DEBUG + + // This just makes sure we have map nodes available without allocation + // during the heap walk (which could be bad). + int i; +#ifdef _FASTRPT_ + hlist makeSureWeHaveNodes; + for(i=0;i<5000;i++) + { + makeSureWeHaveNodes.push_back(0); + } + makeSureWeHaveNodes.clear(); + Lookup.clear(); +#endif + char mess[1000]; + int blocks=dbgMemTotalCount(); + int mem=dbgMemTotalSize()/1024; + sprintf(mess,"Final Memory Summary %d blocks %d K\n",blocks,mem); + OutputDebugString(mess); + + for (i=0;i<3000;i++) + { + CheckpointSize[i]=0; + CheckpointCount[i]=0; + } + + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter2); + dbgMemReportLeakage(NULL,1,1000); + MemSetErrorHandler(MemDefaultErrorHandler); + multimap > sortit; + multimap >::iterator j; + if (TotalBlocks) + { + // Sort by size. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("**********Memory Leak Report**********\n"); + OutputDebugString("*************** By Size **************\n"); + OutputDebugString("**************************************\n"); + sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024); + OutputDebugString(mess); + sortit.clear(); + for (i=0;i >(-StackSize[i],pair(StackCount[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%5d KB %6d cnt %s\n",-(*j).first/1024,(*j).second.first,(*j).second.second); + // if (!(-(*j).first/1024)) + // break; + Sleep(5); + OutputDebugString(mess); + } + + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("**********Memory Leak Report**********\n"); + OutputDebugString("************** By Count **************\n"); + OutputDebugString("**************************************\n"); + sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024); + OutputDebugString(mess); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%5d KB %6d cnt %s\n",(*j).second.first/1024,-(*j).first,(*j).second.second); + // if (!(-(*j).first/1024)) + // break; + Sleep(5); + OutputDebugString(mess); + } + } + else + { + OutputDebugString("No Memory Leaks\n"); + } + + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter3); + dbgMemReportLeakage(NULL,2001,2001); + MemSetErrorHandler(MemDefaultErrorHandler); + if (TotalBlocks) + { + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("SV_PointContents "); + sprintf(mess,"%d Calls.\n",TotalBlocks); + OutputDebugString(mess); + OutputDebugString("**************************************\n"); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second); + Sleep(5); + OutputDebugString(mess); + } + } + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter3); + dbgMemReportLeakage(NULL,2002,2002); + MemSetErrorHandler(MemDefaultErrorHandler); + if (TotalBlocks) + { + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("SV_Trace "); + sprintf(mess,"%d Calls.\n",TotalBlocks); + OutputDebugString(mess); + OutputDebugString("**************************************\n"); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second); + Sleep(5); + OutputDebugString(mess); + } + } + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter3); + dbgMemReportLeakage(NULL,2003,2003); + MemSetErrorHandler(MemDefaultErrorHandler); + if (TotalBlocks) + { + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("SV_AreaEntities "); + sprintf(mess,"%d Calls.\n",TotalBlocks); + OutputDebugString(mess); + OutputDebugString("**************************************\n"); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second); + Sleep(5); + OutputDebugString(mess); + } + } + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter3); + dbgMemReportLeakage(NULL,2004,2004); + MemSetErrorHandler(MemDefaultErrorHandler); + if (TotalBlocks) + { + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("CG_Trace "); + sprintf(mess,"%d Calls.\n",TotalBlocks); + OutputDebugString(mess); + OutputDebugString("**************************************\n"); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second); + Sleep(5); + OutputDebugString(mess); + } + } + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter3); + dbgMemReportLeakage(NULL,2005,2005); + MemSetErrorHandler(MemDefaultErrorHandler); + if (TotalBlocks) + { + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("CG_PointContents "); + sprintf(mess,"%d Calls.\n",TotalBlocks); + OutputDebugString(mess); + OutputDebugString("**************************************\n"); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second); + Sleep(5); + OutputDebugString(mess); + } + } +#if 0 //sw doesn't have the tag stuff + // Sort by size. + Sleep(5); + OutputDebugString("***************************************\n"); + OutputDebugString("By Tag, sort: size ********************\n"); + OutputDebugString("size(K) count name \n"); + OutputDebugString("-----------------------\n"); + Sleep(5); + multimap sorted; + for (i=0;i<1000;i++) + { + if (CheckpointCount[i]) + { + sorted.insert(pair(-CheckpointSize[i],i)); + } + } + multimap::iterator k; + for (k=sorted.begin();k!=sorted.end();k++) + { + sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown"); + Sleep(5); + OutputDebugString(mess); + } + + // Sort by count. + Sleep(5); + OutputDebugString("By Tag, sort: count *******************\n"); + OutputDebugString("size(K) count name \n"); + OutputDebugString("-----------------------\n"); + Sleep(5); + sorted.clear(); + for (i=0;i<1000;i++) + { + if (CheckpointCount[i]) + { + sorted.insert(pair(-CheckpointCount[i],i)); + } + } + for (k=sorted.begin();k!=sorted.end();k++) + { + sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown"); + Sleep(5); + OutputDebugString(mess); + } +#endif +#endif + } + + ~Leakage() + { +#if MEM_DEBUG + if (mem_leakfile && mem_leakfile->integer) + { + dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_FILE,"leakage.out"); + dbgMemReportLeakage(NULL,1,1); + dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT,NULL); + } + if (mem_leakreport && mem_leakreport->integer) + { + LeakReport(); + } +#endif + } +#if MEM_DEBUG + + void EnableChecking(int x) + { + if (x) + { + dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG); + dbgMemPoolSetCheckFrequency(MyPool, x); + dbgMemSetCheckFrequency(x); + dbgMemDeferFreeing(TRUE); + dbgMemSetDeferQueueLen(50000); + } + else + { + dbgMemSetSafetyLevel(MEM_SAFETY_SOME); + dbgMemDeferFreeing(FALSE); + } + + } +#endif + +}; + +static Leakage TheLeakage; + +#if MEM_DEBUG + +void MEM_Checking_f(void) +{ + if (Cmd_Argc() != 2) + { + Com_Printf ("mem_checking \n"); + return; + } + + if (atol(Cmd_Argv(1)) > 0 && atol(Cmd_Argv(1)) < 100) + { + Com_Printf ("mem_checking frequency is too low ( < 100 )\n"); + return; + } + + TheLeakage.EnableChecking(atol(Cmd_Argv(1))); +} + +void MEM_Report_f(void) +{ + if (0) + { + dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_FILE,"leakage.out"); + dbgMemReportLeakage(NULL,1,1); + dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT,NULL); + } + TheLeakage.LeakReport(); +} + +/* +void myexit(void) +{ + TheLeakage.LeakReport(); +} +*/ +void SH_Register(void) +{ + Cmd_AddCommand ("mem_checking", MEM_Checking_f); + Cmd_AddCommand ("mem_report", MEM_Report_f); + + mem_leakfile = Cvar_Get( "mem_leakfile", "0", 0 ); + mem_leakreport = Cvar_Get( "mem_leakreport", "1", 0 ); +// atexit(myexit); +} + +#endif diff --git a/code/0_compiled_first/vssver.scc b/code/0_compiled_first/vssver.scc new file mode 100644 index 0000000..bbe8e58 Binary files /dev/null and b/code/0_compiled_first/vssver.scc differ diff --git a/code/ALut.lib b/code/ALut.lib new file mode 100644 index 0000000..67cde9f Binary files /dev/null and b/code/ALut.lib differ diff --git a/code/EaxMan.dll b/code/EaxMan.dll new file mode 100644 index 0000000..651cbfe Binary files /dev/null and b/code/EaxMan.dll differ diff --git a/code/IFC22.dll b/code/IFC22.dll new file mode 100644 index 0000000..44331c8 Binary files /dev/null and b/code/IFC22.dll differ diff --git a/code/JediAcademy.sln b/code/JediAcademy.sln new file mode 100644 index 0000000..7caf775 --- /dev/null +++ b/code/JediAcademy.sln @@ -0,0 +1,88 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "game", "game\game.vcproj", "{52D48192-6C71-4D4A-BE26-D05C0E02939C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exe", "starwars.vcproj", "{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_game", "x_game\x_game.vcproj", "{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_exe", "x_exe\x_exe.vcproj", "{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "goblib", "goblib\goblib.vcproj", "{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}" +EndProject +Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 2 + SccProjectUniqueName0 = game\\game.vcproj + SccProjectName0 = \u0022$/jedi/code\u0022,\u0020ROBAAAAA + SccLocalPath0 = . + SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe + SccProjectFilePathRelativizedFromConnection0 = game\\ + SccProjectUniqueName1 = starwars.vcproj + SccProjectName1 = \u0022$/jedi/code\u0022,\u0020ROBAAAAA + SccLocalPath1 = . + SccProvider1 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe + EndGlobalSection + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = FinalBuild + ConfigName.2 = Release + ConfigName.3 = SHDebug + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.0 = {52D48192-6C71-4D4A-BE26-D05C0E02939C} + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.0 = {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA} + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.1 = {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.Debug.ActiveCfg = Debug|Win32 + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.Debug.Build.0 = Debug|Win32 + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.FinalBuild.ActiveCfg = FinalBuild|Win32 + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.FinalBuild.Build.0 = FinalBuild|Win32 + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.Release.ActiveCfg = Release|Win32 + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.Release.Build.0 = Release|Win32 + {52D48192-6C71-4D4A-BE26-D05C0E02939C}.SHDebug.ActiveCfg = SHDebug|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Debug.ActiveCfg = Debug|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Debug.Build.0 = Debug|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.FinalBuild.ActiveCfg = FinalBuild|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.FinalBuild.Build.0 = FinalBuild|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Release.ActiveCfg = Release|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Release.Build.0 = Release|Win32 + {1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.SHDebug.ActiveCfg = SHDebug|Win32 + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.ActiveCfg = Debug|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.Build.0 = Debug|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.FinalBuild.ActiveCfg = FinalBuild|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.FinalBuild.Build.0 = FinalBuild|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Release.ActiveCfg = Release|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Release.Build.0 = Release|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.SHDebug.ActiveCfg = Debug|Xbox + {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.SHDebug.Build.0 = Debug|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.ActiveCfg = Debug|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.Build.0 = Debug|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.FinalBuild.ActiveCfg = FinalBuild|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.FinalBuild.Build.0 = FinalBuild|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Release.ActiveCfg = Release|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Release.Build.0 = Release|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.SHDebug.ActiveCfg = Debug|Xbox + {FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.SHDebug.Build.0 = Debug|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Debug.ActiveCfg = Debug|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Debug.Build.0 = Debug|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.FinalBuild.ActiveCfg = FinalBuild|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.FinalBuild.Build.0 = FinalBuild|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Release.ActiveCfg = Release|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Release.Build.0 = Release|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.SHDebug.ActiveCfg = Debug|Xbox + {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.SHDebug.Build.0 = Debug|Xbox + EndGlobalSection + GlobalSection(SolutionItems) = postSolution + Item:1 = tonet.bat + Item:2 = VU.bat + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection + GlobalSection(DevPartner) = postSolution + EndGlobalSection + GlobalSection(DevPartner) = postSolution + EndGlobalSection +EndGlobal diff --git a/code/JediAcademy.vssscc b/code/JediAcademy.vssscc new file mode 100644 index 0000000..794f014 --- /dev/null +++ b/code/JediAcademy.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/code/OpenAL32.dll b/code/OpenAL32.dll new file mode 100644 index 0000000..1b2c553 Binary files /dev/null and b/code/OpenAL32.dll differ diff --git a/code/OpenAL32.lib b/code/OpenAL32.lib new file mode 100644 index 0000000..86de420 Binary files /dev/null and b/code/OpenAL32.lib differ diff --git a/code/RMG/RM_Area.cpp b/code/RMG/RM_Area.cpp new file mode 100644 index 0000000..c4eca5e --- /dev/null +++ b/code/RMG/RM_Area.cpp @@ -0,0 +1,480 @@ +/************************************************************************************************ + * + * Copyright (C) 2001-2002 Raven Software + * + * RM_Area.cpp + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" + +#ifdef _WIN32 +#pragma optimize("p", on) +#endif + +/************************************************************************************************ + * CRMArea::CRMArea + * constructor + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMArea::CRMArea ( + float spacingRadius, + float paddingSize, + float confineRadius, + vec3_t confineOrigin, + vec3_t lookAtOrigin, + bool flatten, + int symmetric + ) +{ + mMoveCount = 0; + mAngle = 0; + mCollision = true; + mConfineRadius = confineRadius; + mPaddingSize = paddingSize; + mSpacingRadius = spacingRadius; + mFlatten = flatten; + mLookAt = true; + mLockOrigin = false; + mSymmetric = symmetric; + mRadius = spacingRadius; + + VectorCopy ( confineOrigin, mConfineOrigin ); + VectorCopy ( lookAtOrigin, mLookAtOrigin ); +} + +/************************************************************************************************ + * CRMArea::LookAt + * Angle the area towards the given point + * + * inputs: + * lookat - the origin to look at + * + * return: + * the angle in radians that was calculated + * + ************************************************************************************************/ +float CRMArea::LookAt ( vec3_t lookat ) +{ + if (mLookAt) + { // this area orients itself towards a point + vec3_t a; + + VectorCopy ( lookat, mLookAtOrigin ); + VectorSubtract ( lookat, mOrigin, a ); + + mAngle = atan2 ( a[1], a[0] ); + } + + return mAngle; +} + +/************************************************************************************************ + * CRMArea::Mirror + * Mirrors the area to the other side of the map. This includes mirroring the confine origin + * and lookat origin + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +void CRMArea::Mirror ( void ) +{ + mOrigin[0] = -mOrigin[0]; + mOrigin[1] = -mOrigin[1]; + + mConfineOrigin[0] = -mConfineOrigin[0]; + mConfineOrigin[1] = -mConfineOrigin[1]; + + mLookAtOrigin[0] = -mLookAtOrigin[0]; + mLookAtOrigin[1] = -mLookAtOrigin[1]; +} + +/************************************************************************************************ + * CRMAreaManager::CRMAreaManager + * constructor + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMAreaManager::CRMAreaManager ( const vec3_t mins, const vec3_t maxs) +{ + VectorCopy ( mins, mMins ); + VectorCopy ( maxs, mMaxs ); + + mWidth = mMaxs[0] - mMins[0]; + mHeight = mMaxs[1] - mMins[1]; +} + +/************************************************************************************************ + * CRMAreaManager::~CRMAreaManager + * Removes all managed areas + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMAreaManager::~CRMAreaManager ( ) +{ + int i; + + for ( i = mAreas.size() - 1; i >=0; i -- ) + { + delete mAreas[i]; + } + + mAreas.clear(); +} + +/************************************************************************************************ + * CRMAreaManager::MoveArea + * Moves an area within the area manager thus shifting any other areas as needed + * + * inputs: + * area - area to be moved + * origin - new origin to attempt to move to + * + * return: + * none + * + ************************************************************************************************/ +void CRMAreaManager::MoveArea ( CRMArea* movedArea, vec3_t origin) +{ + int index; + int size; + + // Increment the addcount (this is for infinite protection) + movedArea->AddMoveCount (); + + // Infinite recursion prevention + if ( movedArea->GetMoveCount() > 250 ) + { +// assert ( 0 ); + movedArea->EnableCollision ( false ); + return; + } + + // First set the area's origin, This may cause it to be in collision with + // another area but that will get fixed later + movedArea->SetOrigin ( origin ); + + // when symmetric we want to ensure that no instances end up on the "other" side of the imaginary diaganol that cuts the map in two + // mSymmetric tells us which side of the map is legal + if ( movedArea->GetSymmetric ( ) ) + { + const vec3pair_t& bounds = TheRandomMissionManager->GetLandScape()->GetBounds(); + + vec3_t point; + vec3_t dir; + vec3_t tang; + bool push; + float len; + + VectorSubtract( movedArea->GetOrigin(), bounds[0], point ); + VectorSubtract( bounds[1], bounds[0], dir ); + VectorNormalize(dir); + + dir[2] = 0; + point[2] = 0; + VectorMA( bounds[0], DotProduct(point, dir), dir, tang ); + VectorSubtract ( movedArea->GetOrigin(), tang, dir ); + + dir[2] = 0; + push = false; + len = VectorNormalize(dir); + + if ( len < movedArea->GetRadius ( ) ) + { + if ( movedArea->GetLockOrigin ( ) ) + { + movedArea->EnableCollision ( false ); + return; + } + + VectorMA ( point, (movedArea->GetSpacingRadius() - len) + TheRandomMissionManager->GetLandScape()->irand(10,movedArea->GetSpacingRadius()), dir, point ); + origin[0] = point[0] + bounds[0][0]; + origin[1] = point[1] + bounds[0][1]; + movedArea->SetOrigin ( origin ); + } + + switch ( movedArea->GetSymmetric ( ) ) + { + case SYMMETRY_TOPLEFT: + if ( origin[1] > origin[0] ) + { + movedArea->Mirror ( ); + } + break; + + case SYMMETRY_BOTTOMRIGHT: + if ( origin[1] < origin[0] ) + { + movedArea->Mirror ( ); + } + + break; + + default: + // unknown symmetry type + assert ( 0 ); + break; + } + } + + // Confine to area unless we are being pushed back by the same guy who pushed us last time (infinite loop) + if ( movedArea->GetConfineRadius() ) + { + if ( movedArea->GetMoveCount() < 25 ) + { + vec3_t cdiff; + float cdist; + + VectorSubtract ( movedArea->GetOrigin(), movedArea->GetConfineOrigin(), cdiff ); + cdiff[2] = 0; + cdist = VectorLength ( cdiff ); + + if ( cdist + movedArea->GetSpacingRadius() > movedArea->GetConfineRadius() ) + { + cdist = movedArea->GetConfineRadius() - movedArea->GetSpacingRadius(); + VectorNormalize ( cdiff ); + + VectorMA ( movedArea->GetConfineOrigin(), cdist, cdiff, movedArea->GetOrigin()); + } + } + else + { + index = 0; + } + } + + // See if it fell off the world in the x direction + if ( movedArea->GetOrigin()[0] + movedArea->GetSpacingRadius() > mMaxs[0] ) + movedArea->GetOrigin()[0] = mMaxs[0] - movedArea->GetSpacingRadius() - (TheRandomMissionManager->GetLandScape()->irand(10,200)); + else if ( movedArea->GetOrigin()[0] - movedArea->GetSpacingRadius() < mMins[0] ) + movedArea->GetOrigin()[0] = mMins[0] + movedArea->GetSpacingRadius() + (TheRandomMissionManager->GetLandScape()->irand(10,200)); + + // See if it fell off the world in the y direction + if ( movedArea->GetOrigin()[1] + movedArea->GetSpacingRadius() > mMaxs[1] ) + movedArea->GetOrigin()[1] = mMaxs[1] - movedArea->GetSpacingRadius() - (TheRandomMissionManager->GetLandScape()->irand(10,200)); + else if ( movedArea->GetOrigin()[1] - movedArea->GetSpacingRadius() < mMins[1] ) + movedArea->GetOrigin()[1] = mMins[1] + movedArea->GetSpacingRadius() + (TheRandomMissionManager->GetLandScape()->irand(10,200)); + + // Look at what we need to look at + movedArea->LookAt ( movedArea->GetLookAtOrigin() ); + + // Dont collide against things that have no collision +// if ( !movedArea->IsCollisionEnabled ( ) ) +// { +// return; +// } + + // See if its colliding + for(index = 0, size = mAreas.size(); index < size; index ++ ) + { + CRMArea *area = mAreas[index]; + vec3_t diff; + vec3_t newOrigin; + float dist; + float targetdist; + + // Skip the one that was moved in the first place + if ( area == movedArea ) + { + continue; + } + + if ( area->GetLockOrigin ( ) && movedArea->GetLockOrigin( ) ) + { + continue; + } + + // Dont collide against things that have no collision + if ( !area->IsCollisionEnabled ( ) ) + { + continue; + } + + // Grab the distance between the two + // only want the horizontal distance -- dmv + //dist = Distance ( movedArea->GetOrigin ( ), area->GetOrigin ( )); + vec3_t maOrigin; + vec3_t aOrigin; + VectorCopy(movedArea->GetOrigin(), maOrigin); + VectorCopy(area->GetOrigin(), aOrigin); + maOrigin[2] = aOrigin[2] = 0; + dist = Distance ( maOrigin, aOrigin ); + targetdist = movedArea->GetSpacingRadius() + area->GetSpacingRadius() + maximum(movedArea->GetPaddingSize(),area->GetPaddingSize()); + + if ( dist == 0 ) + { + area->GetOrigin()[0] += (50 * (float)(TheRandomMissionManager->GetLandScape()->irand(0,99))/100.0f); + area->GetOrigin()[1] += (50 * (float)(TheRandomMissionManager->GetLandScape()->irand(0,99))/100.0f); + + VectorCopy(area->GetOrigin(), aOrigin); + aOrigin[2] = 0; + + dist = Distance ( maOrigin, aOrigin ); + } + + // Are they are enough apart? + if ( dist >= targetdist ) + { + continue; + } + + // Dont move a step if locked + if ( area->GetLockOrigin ( ) ) + { + MoveArea ( area, area->GetOrigin ( ) ); + continue; + } + + // we got a collision, move the guy we hit + VectorSubtract ( area->GetOrigin(), movedArea->GetOrigin(), diff ); + diff[2] = 0; + VectorNormalize ( diff ); + + // Push by the difference in the distance and no-collide radius + VectorMA ( area->GetOrigin(), targetdist - dist + 1 , diff, newOrigin ); + + // Move the area now + MoveArea ( area, newOrigin ); + } +} + +/************************************************************************************************ + * CRMAreaManager::CreateArea + * Creates an area and adds it to the list of managed areas + * + * inputs: + * none + * + * return: + * a pointer to the newly added area class + * + ************************************************************************************************/ +CRMArea* CRMAreaManager::CreateArea ( + vec3_t origin, + float spacingRadius, + int spacingLine, + float paddingSize, + float confineRadius, + vec3_t confineOrigin, + vec3_t lookAtOrigin, + bool flatten, + bool collide, + bool lockorigin, + int symmetric + ) +{ + CRMArea* area = new CRMArea ( spacingRadius, paddingSize, confineRadius, confineOrigin, lookAtOrigin, flatten, symmetric ); + + if ( lockorigin || spacingLine ) + { + area->LockOrigin ( ); + } + + if (origin[0] != lookAtOrigin[0] || origin[1] != lookAtOrigin[1]) + area->EnableLookAt(true); + + // First add the area to the list + mAreas.push_back ( area ); + + area->EnableCollision(collide); + + // Set the real radius which is used for center line detection + if ( spacingLine ) + { + area->SetRadius ( spacingRadius + (spacingLine - 1) * spacingRadius ); + } + + // Now move the area around + MoveArea ( area, origin ); + + if ( (origin[0] != lookAtOrigin[0] || origin[1] != lookAtOrigin[1]) ) + { + int i; + vec3_t linedir; + vec3_t dir; + vec3_t up = {0,0,1}; + vec3_t zerodvec; + + VectorClear(zerodvec); + + VectorSubtract ( lookAtOrigin, origin, dir ); + VectorNormalize ( dir ); + dir[2] = 0; + CrossProduct ( dir, up, linedir ); + + for ( i = 0; i < spacingLine - 1; i ++ ) + { + CRMArea* linearea; + vec3_t lineorigin; + + linearea = new CRMArea ( spacingRadius, paddingSize, 0, zerodvec, zerodvec, false, symmetric ); + linearea->LockOrigin ( ); + linearea->EnableCollision(collide); + + VectorMA ( origin, spacingRadius + (spacingRadius * 2 * i), linedir, lineorigin ); + mAreas.push_back ( linearea ); + MoveArea ( linearea, lineorigin ); + + linearea = new CRMArea ( spacingRadius, paddingSize, 0, zerodvec, zerodvec, false, symmetric ); + linearea->LockOrigin ( ); + linearea->EnableCollision(collide); + + VectorMA ( origin, -spacingRadius - (spacingRadius * 2 * i), linedir, lineorigin ); + mAreas.push_back ( linearea ); + MoveArea ( linearea, lineorigin ); + } + } + + // Return it for convienience + return area; +} + +/************************************************************************************************ + * CRMAreaManager::EnumArea + * Allows for enumeration through the area list. If an invalid index is given then NULL will + * be returned; + * + * inputs: + * index - current enumeration index + * + * return: + * requested area class pointer or NULL if the index was invalid + * + ************************************************************************************************/ +CRMArea* CRMAreaManager::EnumArea ( const int index ) +{ + // This isnt an assertion case because there is no size method for + // the area manager so the areas are enumerated until NULL is returned. + if ( index < 0 || index >= mAreas.size ( ) ) + { + return NULL; + } + + return mAreas[index]; +} + +#ifdef _WIN32 +#pragma optimize("p", off) +#endif diff --git a/code/RMG/RM_Area.h b/code/RMG/RM_Area.h new file mode 100644 index 0000000..b731f47 --- /dev/null +++ b/code/RMG/RM_Area.h @@ -0,0 +1,99 @@ +/************************************************************************************************ + * + * Copyright (C) 2001-2002 Raven Software + * + * RM_Area.h + * + ************************************************************************************************/ + +#pragma once +#if !defined(RM_AREA_H_INC) +#define RM_AREA_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Area.h") +#endif + +class CRMArea +{ +private: + + float mPaddingSize; + float mSpacingRadius; + float mConfineRadius; + float mRadius; + float mAngle; + int mMoveCount; + vec3_t mOrigin; + vec3_t mConfineOrigin; + vec3_t mLookAtOrigin; + bool mCollision; + bool mFlatten; + bool mLookAt; + bool mLockOrigin; + int mSymmetric; + +public: + + CRMArea ( float spacing, float padding, float confine, vec3_t confineOrigin, vec3_t lookAtOrigin, bool flatten = true, int symmetric = 0 ); + + void Mirror ( void ); + + void SetOrigin(vec3_t origin) { VectorCopy ( origin, mOrigin ); } + void SetAngle(float angle) { mAngle = angle; } + void SetSymmetric(int sym) { mSymmetric = sym; } + + void EnableCollision(bool e) { mCollision = e; } + void EnableLookAt(bool la) {mLookAt = la; } + + float LookAt(vec3_t lookat); + void LockOrigin( void ) { mLockOrigin = true; } + + void AddMoveCount() { mMoveCount++; } + void ClearMoveCount() { mMoveCount=0; } + + float GetPaddingSize() { return mPaddingSize; } + float GetSpacingRadius() { return mSpacingRadius; } + float GetRadius() { return mRadius; } + float GetConfineRadius() { return mConfineRadius; } + float GetAngle() { return mAngle; } + int GetMoveCount() { return mMoveCount; } + vec_t* GetOrigin() { return mOrigin; } + vec_t* GetConfineOrigin() { return mConfineOrigin; } + vec_t* GetLookAtOrigin() { return mLookAtOrigin; } + bool GetLookAt() { return mLookAt;} + bool GetLockOrigin() { return mLockOrigin; } + int GetSymmetric() { return mSymmetric; } + + void SetRadius(float r) { mRadius = r; } + + bool IsCollisionEnabled(){ return mCollision; } + bool IsFlattened (){ return mFlatten; } +}; + +typedef vector rmAreaVector_t; + +class CRMAreaManager +{ +private: + + rmAreaVector_t mAreas; + vec3_t mMins; + vec3_t mMaxs; + float mWidth; + float mHeight; + +public: + + CRMAreaManager ( const vec3_t mins, const vec3_t maxs ); + ~CRMAreaManager ( ); + + CRMArea* CreateArea ( vec3_t origin, float spacing, int spacingline, float padding, float confine, vec3_t confineOrigin, vec3_t lookAtOrigin, bool flatten=true, bool collide=true, bool lockorigin=false, int symmetric=0); + void MoveArea ( CRMArea* area, vec3_t origin); + CRMArea* EnumArea ( const int index ); + +// void CreateMap ( void ); +}; + +#endif + diff --git a/code/RMG/RM_Headers.h b/code/RMG/RM_Headers.h new file mode 100644 index 0000000..3eb821b --- /dev/null +++ b/code/RMG/RM_Headers.h @@ -0,0 +1,71 @@ +#pragma once +#if !defined(RM_HEADERS_H_INC) +#define RM_HEADERS_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Headers.h") +#endif + +#pragma warning (push, 3) +#include +#include +#pragma warning (pop) + +using namespace std; + +#if !defined(GENERICPARSER2_H_INC) +#include "../game/genericparser2.h" +#endif + +#if !defined(CM_LOCAL_H_INC) +#include "../qcommon/cm_local.h" +#endif + +#define MAX_INSTANCE_TRIES 5 + +// on a symmetric map which corner is the first node +typedef enum +{ + SYMMETRY_NONE, + SYMMETRY_TOPLEFT, + SYMMETRY_BOTTOMRIGHT + +} symmetry_t; + +#if !defined(CM_TERRAINMAP_H_INC) + #include "../qcommon/cm_terrainmap.h" +#endif + +#if !defined(RM_AREA_H_INC) + #include "RM_Area.h" +#endif + +#if !defined(RM_PATH_H_INC) + #include "RM_Path.h" +#endif + +#if !defined(RM_OBJECTIVE_H_INC) + #include "RM_Objective.h" +#endif + +#if !defined(RM_INSTANCEFILE_H_INC) + #include "RM_InstanceFile.h" +#endif + +#if !defined(RM_INSTANCE_H_INC) + #include "RM_Instance.h" +#endif + +#if !defined(RM_MISSION_H_INC) + #include "RM_Mission.h" +#endif + +#if !defined(RM_MANAGER_H_INC) + #include "RM_Manager.h" +#endif + +#if !defined(RM_TERRAIN_H_INC) + #include "RM_Terrain.h" +#endif + +#endif diff --git a/code/RMG/RM_Instance.cpp b/code/RMG/RM_Instance.cpp new file mode 100644 index 0000000..91495e7 --- /dev/null +++ b/code/RMG/RM_Instance.cpp @@ -0,0 +1,191 @@ +#include "../server/exe_headers.h" + +#include "rm_headers.h" +#include "../qcommon/cm_terrainmap.h" + +/************************************************************************************************ + * CRMInstance::CRMInstance + * constructs a instnace object using the given parser group + * + * inputs: + * instance: parser group containing information about the instance + * + * return: + * none + * + ************************************************************************************************/ +CRMInstance::CRMInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile ) +{ + mObjective = NULL; + mSpacingRadius = 0; + mFlattenRadius = 0; + mFilter[0] = mTeamFilter[0] = 0; + mArea = NULL; + mAutomapSymbol = 0; + mEntityID = 0; + mSide = 0; + mMirror = 0; + mFlattenHeight = 66; + mSpacingLine = 0; + mSurfaceSprites = true; + mLockOrigin = false; +} + +/************************************************************************************************ + * CRMInstance::PreSpawn + * Prepares the instance for spawning by flattening the ground under it + * + * inputs: + * landscape: landscape the instance will be spawned on + * + * return: + * true: spawn preparation successful + * false: spawn preparation failed + * + ************************************************************************************************/ +bool CRMInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer ) +{ + vec3_t origin; + CArea area; + + VectorCopy(GetOrigin(), origin); + + if (mMirror) + { + origin[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - origin[0]; + origin[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - origin[1]; + } + + const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( ); + const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds(); + + // Align the instance to the center of a terxel + origin[0] = bounds[0][0] + (int)((origin[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0]; + origin[1] = bounds[0][1] + (int)((origin[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1]; + + + // This is BAD - By copying the mirrored origin back into the instance, you've now mirrored the original instance + // so when anything from this point on looks at the instance they'll be looking at a mirrored version but will be expecting the original + // so later in the spawn functions the instance will be re-mirrored, because it thinks the mInstances have not been changed +// VectorCopy(origin, GetOrigin()); + + // Flatten the area below the instance + if ( GetFlattenRadius() ) + { + area.Init( origin, GetFlattenRadius(), 0.0f, AT_NONE, 0, 0 ); + terrain->GetLandScape()->FlattenArea( &area, mFlattenHeight | (mSurfaceSprites?0:0x80), false, true, true ); + } + + return true; +} + +/************************************************************************************************ + * CRMInstance::PostSpawn + * Finishes the spawn by linking any objectives into the world that are associated with it + * + * inputs: + * landscape: landscape the instance was spawned on + * + * return: + * true: post spawn successfull + * false: post spawn failed + * + ************************************************************************************************/ +bool CRMInstance::PostSpawn ( CRandomTerrain* terrain, qboolean IsServer ) +{ + if ( mObjective ) + { + return mObjective->Link ( ); + } + + return true; +} +#ifndef DEDICATED +void CRMInstance::DrawAutomapSymbol() +{ + // draw proper symbol on map for instance + switch (GetAutomapSymbol()) + { + default: + case AUTOMAP_NONE: + if (HasObjective()) + CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide()); + break; + case AUTOMAP_BLD: + CM_TM_AddBuilding(GetOrigin()[0], GetOrigin()[1], GetSide()); + if (HasObjective()) + CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide()); + break; + case AUTOMAP_OBJ: + CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide()); + break; + case AUTOMAP_START: + CM_TM_AddStart(GetOrigin()[0], GetOrigin()[1], GetSide()); + break; + case AUTOMAP_END: + CM_TM_AddEnd(GetOrigin()[0], GetOrigin()[1], GetSide()); + break; + case AUTOMAP_ENEMY: + if (HasObjective()) + CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1]); + if (1 == Cvar_VariableIntegerValue("rmg_automapshowall")) + CM_TM_AddNPC(GetOrigin()[0], GetOrigin()[1], false); + break; + case AUTOMAP_FRIEND: + if (HasObjective()) + CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1]); + if (1 == Cvar_VariableIntegerValue("rmg_automapshowall")) + CM_TM_AddNPC(GetOrigin()[0], GetOrigin()[1], true); + break; + case AUTOMAP_WALL: + CM_TM_AddWallRect(GetOrigin()[0], GetOrigin()[1], GetSide()); + break; + } +} +#endif // !DEDICATED +/************************************************************************************************ + * CRMInstance::Preview + * Renderings debug information about the instance + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +void CRMInstance::Preview ( const vec3_t from ) +{ +/* CEntity *tent; + + // Add a cylindar for the whole settlement + tent = G_TempEntity( GetOrigin(), EV_DEBUG_CYLINDER ); + VectorCopy( GetOrigin(), tent->s.origin2 ); + tent->s.pos.trBase[2] += 40; + tent->s.origin2[2] += 50; + tent->s.time = 1050 + ((int)(GetSpacingRadius())<<16); + tent->s.time2 = GetPreviewColor ( ); + G_AddTempEntity(tent); + + // Origin line + tent = G_TempEntity( GetOrigin ( ), EV_DEBUG_LINE ); + VectorCopy( GetOrigin(), tent->s.origin2 ); + tent->s.origin2[2] += 400; + tent->s.time = 1050; + tent->s.weapon = 10; + tent->s.time2 = (255<<24) + (255<<16) + (255<<8) + 255; + G_AddTempEntity(tent); + + if ( GetFlattenRadius ( ) ) + { + // Add a cylindar for the whole settlement + tent = G_TempEntity( GetOrigin(), EV_DEBUG_CYLINDER ); + VectorCopy( GetOrigin(), tent->s.origin2 ); + tent->s.pos.trBase[2] += 40; + tent->s.origin2[2] += 50; + tent->s.time = 1050 + ((int)(GetFlattenRadius ( ))<<16); + tent->s.time2 = (255<<24) + (80<<16) +(80<<8) + 80; + G_AddTempEntity(tent); + } +*/ +} diff --git a/code/RMG/RM_Instance.h b/code/RMG/RM_Instance.h new file mode 100644 index 0000000..5251389 --- /dev/null +++ b/code/RMG/RM_Instance.h @@ -0,0 +1,122 @@ +#pragma once +#if !defined(RM_INSTANCE_H_INC) +#define RM_INSTANCE_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Instance.h") +#endif + +#if !defined(CM_LANDSCAPE_H_INC) +#include "../qcommon/cm_landscape.h" +#endif + +enum CRMAutomapSymbol +{ + AUTOMAP_NONE = 0, + AUTOMAP_BLD = 1, + AUTOMAP_OBJ = 2, + AUTOMAP_START= 3, + AUTOMAP_END = 4, + AUTOMAP_ENEMY= 5, + AUTOMAP_FRIEND=6, + AUTOMAP_WALL=7 +}; + +class CRMInstance +{ +protected: + char mFilter[MAX_QPATH]; // filter of entities inside of this + char mTeamFilter[MAX_QPATH]; // team specific filter + + vec3pair_t mBounds; // Bounding box for instance itself + + CRMArea* mArea; // Position of the instance + + CRMObjective* mObjective; // Objective associated with this instance + + // optional instance specific strings for objective + string mMessage; // message outputed when objective is completed + string mDescription; // description of objective + string mInfo; // more info for objective + + float mSpacingRadius; // Radius to space instances with + float mFlattenRadius; // Radius to flatten under instances + + int mSpacingLine; // Line of spacing radius's, forces locket + bool mLockOrigin; // Origin cant move + + bool mSurfaceSprites; // allow surface sprites under instance? + + int mAutomapSymbol; // show which symbol on automap 0=none + + int mEntityID; // id of entity spawned + int mSide; // blue or red side + int mMirror; // mirror origin, angle + + int mFlattenHeight; // height to flatten land + +public: + + CRMInstance ( CGPGroup* instance, CRMInstanceFile& instFile); + + virtual ~CRMInstance ( ) { } + + virtual bool IsValid ( ) { return true; } + + virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer ); + virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer ) { return false; } + virtual bool PostSpawn ( CRandomTerrain* terrain, qboolean IsServer ); + + virtual void Preview ( const vec3_t from ); + + virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area ) { mArea = area; } + virtual void SetFilter ( const char *filter ) { strcpy(mFilter, filter); } + virtual void SetTeamFilter ( const char *teamFilter ) { strcpy(mTeamFilter, teamFilter); } + void SetObjective ( CRMObjective* obj ) { mObjective = obj; } + CRMObjective* GetObjective (void) {return mObjective;} + bool HasObjective () {return mObjective != NULL;} + int GetAutomapSymbol () {return mAutomapSymbol;} + void DrawAutomapSymbol (); + const char* GetMessage(void) { return mMessage.c_str(); } + const char* GetDescription(void){ return mDescription.c_str(); } + const char* GetInfo(void) { return mInfo.c_str(); } + void SetMessage(const char* msg) { mMessage = msg; } + void SetDescription(const char* desc) { mDescription = desc; } + void SetInfo(const char* info) { mInfo = info; } + void SetSide(int side) {mSide = side;} + int GetSide ( ) {return mSide;} + + // NOTE: should consider making SetMirror also set all other variables that need flipping + // like the origin and Side, etc... Otherwise an Instance may have had it's origin flipped + // but then later will have mMirror set to false, but the origin is still flipped. So any functions + // that look at the instance later will see mMirror set to false, but not realize the origin has ALREADY been flipped + virtual void SetMirror(int mirror) { mMirror = mirror;} + int GetMirror ( ) { return mMirror;} + + virtual bool GetSurfaceSprites ( ) { return mSurfaceSprites; } + + virtual bool GetLockOrigin ( ) { return mLockOrigin; } + virtual int GetSpacingLine ( ) { return mSpacingLine; } + + virtual int GetPreviewColor ( ) { return 0; } + virtual float GetSpacingRadius ( ) { return mSpacingRadius; } + virtual float GetFlattenRadius ( ) { return mFlattenRadius; } + const char *GetFilter ( ) { return mFilter; } + const char *GetTeamFilter ( ) { return mTeamFilter; } + + CRMArea& GetArea ( ) { return *mArea; } + vec_t* GetOrigin ( ) {return mArea->GetOrigin(); } + float GetAngle ( ) {return mArea->GetAngle();} + void SetAngle(float ang ) { mArea->SetAngle(ang);} + const vec3pair_t& GetBounds(void) const { return(mBounds); } + + void SetFlattenHeight ( int height ) { mFlattenHeight = height; } + int GetFlattenHeight ( void ) { return mFlattenHeight; } + + void SetSpacingRadius (float spacing) { mSpacingRadius = spacing; } +}; + +typedef list::iterator rmInstanceIter_t; +typedef list rmInstanceList_t; + +#endif diff --git a/code/RMG/RM_InstanceFile.cpp b/code/RMG/RM_InstanceFile.cpp new file mode 100644 index 0000000..28c263e --- /dev/null +++ b/code/RMG/RM_InstanceFile.cpp @@ -0,0 +1,200 @@ +/************************************************************************************************ + * + * RM_InstanceFile.cpp + * + * implements the CRMInstanceFile class. This class provides functionality to load + * and create instances from an instance file. First call Open to open the instance file and + * then use CreateInstance to create new instances. When finished call Close to cleanup. + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" + +//#include "rm_instance_npc.h" +#include "rm_instance_bsp.h" +#include "rm_instance_random.h" +#include "rm_instance_group.h" +#include "rm_instance_void.h" + +/************************************************************************************************ + * CRMInstanceFile::CRMInstanceFile + * constructor + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMInstanceFile::CRMInstanceFile ( ) +{ + mInstances = NULL; +} + +/************************************************************************************************ + * CRMInstanceFile::~CRMInstanceFile + * Destroys the instance file by freeing the parser + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMInstanceFile::~CRMInstanceFile ( ) +{ + Close ( ); +} + +/************************************************************************************************ + * CRMInstanceFile::Open + * Opens the given instance file and prepares it for use in instance creation + * + * inputs: + * instance: Name of instance to open. Note that the root path will be automatically + * added and shouldnt be included in the given name + * + * return: + * true: instance file successfully loaded + * false: instance file could not be loaded for some reason + * + ************************************************************************************************/ +bool CRMInstanceFile::Open ( const char* instance ) +{ + char instanceDef[MAX_QPATH]; + CGPGroup *basegroup; + + // Build the filename + Com_sprintf(instanceDef, MAX_QPATH, "ext_data/rmg/%s.instance", instance ); + +#ifndef FINAL_BUILD + // Debug message + Com_Printf("CM_Terrain: Loading and parsing instanceDef %s.....\n", instance); +#endif + + // Parse the text file using the generic parser + if(!Com_ParseTextFile(instanceDef, mParser )) + { + Com_sprintf(instanceDef, MAX_QPATH, "ext_data/arioche/%s.instance", instance ); + if(!Com_ParseTextFile(instanceDef, mParser )) + { + Com_Printf(va("CM_Terrain: Could not open instance file '%s'\n", instanceDef)); + return false; + } + } + + // The whole file.... + basegroup = mParser.GetBaseParseGroup(); + + // The root { } struct + mInstances = basegroup->GetSubGroups(); + + // The "instances" { } structure + mInstances = mInstances->GetSubGroups ( ); + + return true; +} + +/************************************************************************************************ + * CRMInstanceFile::Close + * Closes an open instance file + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +void CRMInstanceFile::Close ( void ) +{ + // If not open then dont close it + if ( NULL == mInstances ) + { + return; + } + mParser.Clean(); + + mInstances = NULL; +} + +/************************************************************************************************ + * CRMInstanceFile::CreateInstance + * Creates an instance (to be freed by caller) using the given instance name. + * + * inputs: + * name: Name of the instance to read from the instance file + * + * return: + * NULL: instance could not be read from the instance file + * NON-NULL: instance created and returned for further use + * + ************************************************************************************************/ +CRMInstance* CRMInstanceFile::CreateInstance ( const char* name ) +{ + static int instanceID = 0; + + CGPGroup* group; + CRMInstance* instance; + + // Make sure we were loaded + assert ( mInstances ); + + // Search through the instances for the one with the given name + for ( group = mInstances; group; group = group->GetNext ( ) ) + { + // Skip it if the name doesnt match + if ( stricmp ( name, group->FindPairValue ( "name", "" ) ) ) + { + continue; + } + + // Handle the various forms of instance types + if ( !stricmp ( group->GetName ( ), "bsp" ) ) + { + instance = new CRMBSPInstance ( group, *this ); + } + else if ( !stricmp ( group->GetName ( ), "npc" ) ) + { +// instance = new CRMNPCInstance ( group, *this ); + continue; + } + else if ( !stricmp ( group->GetName ( ), "group" ) ) + { + instance = new CRMGroupInstance ( group, *this ); + } + else if ( !stricmp ( group->GetName ( ), "random" ) ) + { + instance = new CRMRandomInstance ( group, *this ); + } + else if ( !stricmp ( group->GetName ( ), "void" ) ) + { + instance = new CRMVoidInstance ( group, *this ); + } + else + { + continue; + } + + // If the instance isnt valid after being created then delete it + if ( !instance->IsValid ( ) ) + { + delete instance; + return NULL; + } + + // The instance was successfully created so return it + return instance; + } + +#ifndef FINAL_BUILD + // The instance wasnt found in the file so report it + Com_Printf(va("WARNING: Instance '%s' was not found in the active instance file\n", name )); +#endif + + return NULL; +} diff --git a/code/RMG/RM_InstanceFile.h b/code/RMG/RM_InstanceFile.h new file mode 100644 index 0000000..729722e --- /dev/null +++ b/code/RMG/RM_InstanceFile.h @@ -0,0 +1,28 @@ +#pragma once +#if !defined(RM_INSTANCEFILE_H_INC) +#define RM_INSTANCEFILE_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_InstanceFile.h") +#endif + +class CRMInstance; + +class CRMInstanceFile +{ +public: + + CRMInstanceFile ( ); + ~CRMInstanceFile ( ); + + bool Open ( const char* instance ); + void Close ( void ); + CRMInstance* CreateInstance ( const char* name ); + +protected: + + CGenericParser2 mParser; + CGPGroup* mInstances; +}; + +#endif \ No newline at end of file diff --git a/code/RMG/RM_Instance_BSP.cpp b/code/RMG/RM_Instance_BSP.cpp new file mode 100644 index 0000000..ae912a6 --- /dev/null +++ b/code/RMG/RM_Instance_BSP.cpp @@ -0,0 +1,294 @@ +/************************************************************************************************ + * + * RM_Instance_BSP.cpp + * + * Implements the CRMBSPInstance class. This class is reponsible for parsing a + * bsp instance as well as spawning it into a landscape. + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "../qcommon/cm_local.h" +#include "../server/server.h" +#include "rm_headers.h" + +#include "rm_instance_bsp.h" + +#include "../client/vmachine.h" + +/************************************************************************************************ + * CRMBSPInstance::CRMBSPInstance + * constructs a building instance object using the given parser group + * + * inputs: + * instance: parser group containing information about the building instance + * + * return: + * none + * + ************************************************************************************************/ +CRMBSPInstance::CRMBSPInstance(CGPGroup *instGroup, CRMInstanceFile& instFile) : CRMInstance ( instGroup, instFile ) +{ + strcpy(mBsp, instGroup->FindPairValue("file", "")); + + mAngleVariance = DEG2RAD(atof(instGroup->FindPairValue("anglevariance", "0"))); + mBaseAngle = DEG2RAD(atof(instGroup->FindPairValue("baseangle", "0"))); + mAngleDiff = DEG2RAD(atof(instGroup->FindPairValue("anglediff", "0"))); + mSpacingRadius = atof( instGroup->FindPairValue ( "spacing", "100" ) ); + mSpacingLine = atoi( instGroup->FindPairValue ( "spacingline", "0" ) ); + mSurfaceSprites = (!Q_stricmp ( instGroup->FindPairValue ( "surfacesprites", "no" ), "yes")) ? true : false; + mLockOrigin = (!Q_stricmp ( instGroup->FindPairValue ( "lockorigin", "no" ), "yes")) ? true : false; + mFlattenRadius = atof( instGroup->FindPairValue ( "flatten", "0" ) ); + mHoleRadius = atof( instGroup->FindPairValue ( "hole", "0" ) ); + + const char * automapSymName = instGroup->FindPairValue ( "automap_symbol", "building" ); + if (0 == strcmpi(automapSymName, "none")) mAutomapSymbol = AUTOMAP_NONE ; + else if (0 == strcmpi(automapSymName, "building")) mAutomapSymbol = AUTOMAP_BLD ; + else if (0 == strcmpi(automapSymName, "objective")) mAutomapSymbol = AUTOMAP_OBJ ; + else if (0 == strcmpi(automapSymName, "start")) mAutomapSymbol = AUTOMAP_START; + else if (0 == strcmpi(automapSymName, "end")) mAutomapSymbol = AUTOMAP_END ; + else if (0 == strcmpi(automapSymName, "enemy")) mAutomapSymbol = AUTOMAP_ENEMY; + else if (0 == strcmpi(automapSymName, "friend")) mAutomapSymbol = AUTOMAP_FRIEND; + else if (0 == strcmpi(automapSymName, "wall")) mAutomapSymbol = AUTOMAP_WALL; + else mAutomapSymbol = atoi( automapSymName ); + + // optional instance objective strings + SetMessage(instGroup->FindPairValue("objective_message","")); + SetDescription(instGroup->FindPairValue("objective_description","")); + SetInfo(instGroup->FindPairValue("objective_info","")); + + mBounds[0][0] = 0; + mBounds[0][1] = 0; + mBounds[1][0] = 0; + mBounds[1][1] = 0; + + mBaseAngle += (TheRandomMissionManager->GetLandScape()->irand(0,mAngleVariance) - mAngleVariance/2); +} + +/************************************************************************************************ + * CRMBSPInstance::Spawn + * spawns a bsp into the world using the previously aquired origin + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +bool CRMBSPInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer) +{ +#ifndef PRE_RELEASE_DEMO +// TEntity* ent; + float yaw; + char temp[10000]; + char *savePtr; + vec3_t origin; + vec3_t notmirrored; + float water_level = terrain->GetLandScape()->GetWaterHeight(); + + const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( ); + const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds(); + + // If this entity somehow lost its collision flag then boot it + if ( !GetArea().IsCollisionEnabled ( ) ) + { + return false; + } + + // copy out the unmirrored version + VectorCopy(GetOrigin(), notmirrored); + + // we want to mirror it before determining the Z value just in case the landscape isn't perfectly mirrored + if (mMirror) + { + GetOrigin()[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - GetOrigin()[0]; + GetOrigin()[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - GetOrigin()[1]; + } + + // Align the instance to the center of a terxel + GetOrigin ( )[0] = bounds[0][0] + (int)((GetOrigin ( )[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0]; + GetOrigin ( )[1] = bounds[0][1] + (int)((GetOrigin ( )[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1]; + + // Make sure the bsp is resting on the ground, not below or above it + // NOTE: This check is basically saying "is this instance not a bridge", because when instances are created they are all + // placed above the world's Z boundary, EXCEPT FOR BRIDGES. So this call to GetWorldHeight will move all other instances down to + // ground level except bridges + if ( GetOrigin()[2] > terrain->GetBounds()[1][2] ) + { + if( GetFlattenRadius() ) + { + terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), false ); + GetOrigin()[2] += 5; + } + else if (IsServer) + { // if this instance does not flatten the ground around it, do a trace to more accurately determine its Z value + trace_t tr; + vec3_t end; + vec3_t start; + + VectorCopy(GetOrigin(), end); + VectorCopy(GetOrigin(), start); + // start the trace below the top height of the landscape + start[2] = TheRandomMissionManager->GetLandScape()->GetBounds()[1][2] - 1; + // end the trace at the bottom of the world + end[2] = MIN_WORLD_COORD; + + memset ( &tr, 0, sizeof ( tr ) ); + SV_Trace( &tr, start, vec3_origin, vec3_origin, end, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID, G2_NOCOLLIDE, 0); //qfalse, 0, 10 ); + + if( !(tr.contents & CONTENTS_TERRAIN) || (tr.fraction == 1.0) ) + { + if ( 0 ) + assert(0); // this should never happen + + // restore the unmirrored origin + VectorCopy( notmirrored, GetOrigin() ); + // don't spawn + return false; + } + // assign the Z-value to wherever it hit the terrain + GetOrigin()[2] = tr.endpos[2]; + // lower it a little, otherwise the bottom of the instance might be exposed if on some weird sloped terrain + GetOrigin()[2] -= 16; // FIXME: would it be better to use a number related to the instance itself like 1/5 it's height or something... + } + + } + else + { + terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), true ); + } + + // save away the origin + VectorCopy(GetOrigin(), origin); + // make sure not to spawn if in water + if (!HasObjective() && GetOrigin()[2] < water_level) + return false; + // restore the origin + VectorCopy(origin, GetOrigin()); + + if (mMirror) + { // change blue things to red for symmetric maps + if (strlen(mFilter) > 0) + { + char * blue = strstr(mFilter,"blue"); + if (blue) + { + blue[0] = (char) 0; + strcat(mFilter, "red"); + SetSide(SIDE_RED); + } + } + if (strlen(mTeamFilter) > 0) + { + char * blue = strstr(mTeamFilter,"blue"); + if (blue) + { + strcpy(mTeamFilter, "red"); + SetSide(SIDE_RED); + } + } + yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle) + 180; + } + else + { + yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle); + } + +/* + if( TheRandomMissionManager->GetMission()->GetSymmetric() ) + { + vec3_t diagonal; + vec3_t lineToPoint; + vec3_t mins; + vec3_t maxs; + vec3_t point; + vec3_t vProj; + vec3_t vec; + float distance; + + VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[1], maxs ); + VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[0], mins ); + VectorCopy( GetOrigin(), point ); + mins[2] = maxs[2] = point[2] = 0; + VectorSubtract( point, mins, lineToPoint ); + VectorSubtract( maxs, mins, diagonal); + + + VectorNormalize(diagonal); + VectorMA( mins, DotProduct(lineToPoint, diagonal), diagonal, vProj); + VectorSubtract(point, vProj, vec ); + distance = VectorLength(vec); + + // if an instance is too close to the imaginary diagonal that cuts the world in half, don't spawn it + // otherwise you can get overlapping instances + if( distance < GetSpacingRadius() ) + { +#ifdef _DEBUG + mAutomapSymbol = AUTOMAP_END; +#endif + if( !HasObjective() ) + { + return false; + } + } + } +*/ + + // Spawn in the bsp model + sprintf(temp, + "{\n" + "\"classname\" \"misc_bsp\"\n" + "\"bspmodel\" \"%s\"\n" + "\"origin\" \"%f %f %f\"\n" + "\"angles\" \"0 %f 0\"\n" + "\"filter\" \"%s\"\n" + "\"teamfilter\" \"%s\"\n" + "\"spacing\" \"%d\"\n" + "\"flatten\" \"%d\"\n" + "}\n", + mBsp, + GetOrigin()[0], GetOrigin()[1], GetOrigin()[2], + AngleNormalize360(yaw), + mFilter, + mTeamFilter, + (int)GetSpacingRadius(), + (int)GetFlattenRadius() + ); + + if (IsServer) + { // only allow for true spawning on the server + savePtr = sv.entityParsePoint; + sv.entityParsePoint = temp; +// VM_Call( cgvm, GAME_SPAWN_RMG_ENTITY ); + // char *s; + int bufferSize = 1024; + char buffer[1024]; + + // s = COM_Parse( (const char **)&sv.entityParsePoint ); + Q_strncpyz( buffer, sv.entityParsePoint, bufferSize ); + if ( sv.entityParsePoint && sv.entityParsePoint[0] ) + { + ge->GameSpawnRMGEntity(sv.entityParsePoint); + } + sv.entityParsePoint = savePtr; + } + + +#ifndef DEDICATED + DrawAutomapSymbol(); +#endif + Com_DPrintf( "RMG: Building '%s' spawned at (%f %f %f)\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2] ); + // now restore the instances un-mirrored origin + // NOTE: all this origin flipping, setting the side etc... should be done when mMirror is set + // because right after this function is called, mMirror is set to 0 but all the instance data is STILL MIRRORED -- not good + VectorCopy(notmirrored, GetOrigin()); + +#endif // PRE_RELEASE_DEMO + + return true; +} + + + diff --git a/code/RMG/RM_Instance_BSP.h b/code/RMG/RM_Instance_BSP.h new file mode 100644 index 0000000..b1c4be3 --- /dev/null +++ b/code/RMG/RM_Instance_BSP.h @@ -0,0 +1,35 @@ +#pragma once +#if !defined(RM_INSTANCE_BSP_H_INC) +#define RM_INSTANCE_BSP_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Instance_BSP.h") +#endif + +class CRMBSPInstance : public CRMInstance +{ +private: + + char mBsp[MAX_QPATH]; + float mAngleVariance; + float mBaseAngle; + float mAngleDiff; + + float mHoleRadius; + +public: + + CRMBSPInstance ( CGPGroup *instance, CRMInstanceFile& instFile ); + + virtual int GetPreviewColor ( ) { return (255<<24)+255; } + + virtual float GetHoleRadius ( ) { return mHoleRadius; } + + virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer ); + + const char* GetModelName (void) const { return(mBsp); } + float GetAngleDiff (void) const { return(mAngleDiff); } + bool GetAngularType (void) const { return(mAngleDiff != 0.0f); } +}; + +#endif \ No newline at end of file diff --git a/code/RMG/RM_Instance_Group.cpp b/code/RMG/RM_Instance_Group.cpp new file mode 100644 index 0000000..382e8b6 --- /dev/null +++ b/code/RMG/RM_Instance_Group.cpp @@ -0,0 +1,343 @@ +/************************************************************************************************ + * + * RM_Instance_Group.cpp + * + * Implements the CRMGroupInstance class. This class is reponsible for parsing a + * group instance as well as spawning it into a landscape. + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" + +#include "rm_instance_group.h" + +/************************************************************************************************ + * CRMGroupInstance::CRMGroupInstance + * constructur + * + * inputs: + * settlementID: ID of the settlement being created + * + * return: + * none + * + ************************************************************************************************/ +CRMGroupInstance::CRMGroupInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile ) + : CRMInstance ( instGroup, instFile ) +{ + // Grab the padding and confine radius + mPaddingSize = atof ( instGroup->FindPairValue ( "padding", va("%i", TheRandomMissionManager->GetMission()->GetDefaultPadding() ) ) ); + mConfineRadius = atof ( instGroup->FindPairValue ( "confine", "0" ) ); + + const char * automapSymName = instGroup->FindPairValue ( "automap_symbol", "none" ); + if (0 == strcmpi(automapSymName, "none")) mAutomapSymbol = AUTOMAP_NONE ; + else if (0 == strcmpi(automapSymName, "building")) mAutomapSymbol = AUTOMAP_BLD ; + else if (0 == strcmpi(automapSymName, "objective")) mAutomapSymbol = AUTOMAP_OBJ ; + else if (0 == strcmpi(automapSymName, "start")) mAutomapSymbol = AUTOMAP_START; + else if (0 == strcmpi(automapSymName, "end")) mAutomapSymbol = AUTOMAP_END ; + else if (0 == strcmpi(automapSymName, "enemy")) mAutomapSymbol = AUTOMAP_ENEMY; + else if (0 == strcmpi(automapSymName, "friend")) mAutomapSymbol = AUTOMAP_FRIEND; + else mAutomapSymbol = atoi( automapSymName ); + + // optional instance objective strings + SetMessage(instGroup->FindPairValue("objective_message","")); + SetDescription(instGroup->FindPairValue("objective_description","")); + SetInfo(instGroup->FindPairValue("objective_info","")); + + // Iterate through the sub groups to determine the instances which make up the group + instGroup = instGroup->GetSubGroups ( ); + + while ( instGroup ) + { + CRMInstance* instance; + const char* name; + int mincount; + int maxcount; + int count; + float minrange; + float maxrange; + + // Make sure only instances are specified as sub groups + assert ( 0 == stricmp ( instGroup->GetName ( ), "instance" ) ); + + // Grab the name + name = instGroup->FindPairValue ( "name", "" ); + + // Grab the range information + minrange = atof(instGroup->FindPairValue ( "minrange", "0" ) ); + maxrange = atof(instGroup->FindPairValue ( "maxrange", "0" ) ); + + // Grab the count information and randomly generate a count value + mincount = atoi(instGroup->FindPairValue ( "mincount", "1" ) ); + maxcount = atoi(instGroup->FindPairValue ( "maxcount", "1" ) ); + count = mincount; + + if ( maxcount > mincount ) + { + count += (TheRandomMissionManager->GetLandScape()->irand(0, maxcount-mincount)); + } + + // For each count create and add the instance + for ( ; count ; count -- ) + { + // Create the instance + instance = instFile.CreateInstance ( name ); + + // Skip this instance if it couldnt be created for some reason. The CreateInstance + // method will report an error so no need to do so here. + if ( NULL == instance ) + { + continue; + } + + // Set the min and max range for the instance + instance->SetFilter(mFilter); + instance->SetTeamFilter(mTeamFilter); + + // Add the instance to the list + mInstances.push_back ( instance ); + } + + // Next sub group + instGroup = instGroup->GetNext ( ); + } +} + +/************************************************************************************************ + * CRMGroupInstance::~CRMGroupInstance + * Removes all buildings and inhabitants + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMGroupInstance::~CRMGroupInstance(void) +{ + // Cleanup + RemoveInstances ( ); +} + +/************************************************************************************************ + * CRMGroupInstance::SetFilter + * Sets a filter used to exclude instances + * + * inputs: + * filter: filter name + * + * return: + * none + * + ************************************************************************************************/ +void CRMGroupInstance::SetFilter( const char *filter ) +{ + rmInstanceIter_t it; + + CRMInstance::SetFilter(filter); + for(it = mInstances.begin(); it != mInstances.end(); it++) + { + (*it)->SetFilter(filter); + } +} + +/************************************************************************************************ + * CRMGroupInstance::SetTeamFilter + * Sets the filter used to exclude team based instances + * + * inputs: + * teamFilter: filter name + * + * return: + * none + * + ************************************************************************************************/ +void CRMGroupInstance::SetTeamFilter( const char *teamFilter ) +{ + rmInstanceIter_t it; + + CRMInstance::SetTeamFilter(teamFilter); + for(it = mInstances.begin(); it != mInstances.end(); it++) + { + (*it)->SetTeamFilter(teamFilter); + } +} + +/************************************************************************************************ + * CRMGroupInstance::SetMirror + * Sets the flag to mirror an instance on map + * + * inputs: + * mirror + * + * return: + * none + * + ************************************************************************************************/ +void CRMGroupInstance::SetMirror(int mirror) +{ + rmInstanceIter_t it; + + CRMInstance::SetMirror(mirror); + for(it = mInstances.begin(); it != mInstances.end(); it++) + { + (*it)->SetMirror(mirror); + } +} + + +/************************************************************************************************ + * CRMGroupInstance::RemoveInstances + * Removes all instances associated with the group + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +void CRMGroupInstance::RemoveInstances ( ) +{ + rmInstanceIter_t it; + + for(it = mInstances.begin(); it != mInstances.end(); it++) + { + delete *it; + } + + mInstances.clear(); +} + +/************************************************************************************************ + * CRMGroupInstance::PreSpawn + * Prepares the group for spawning by + * + * inputs: + * landscape: landscape to calculate the position within + * instance: instance to calculate the position for + * + * return: + * none + * + ************************************************************************************************/ +bool CRMGroupInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer ) +{ + rmInstanceIter_t it; + + for(it = mInstances.begin(); it != mInstances.end(); it++ ) + { + CRMInstance* instance = *it; + + instance->SetFlattenHeight ( mFlattenHeight ); + + // Add the instance to the landscape now + instance->PreSpawn ( terrain, IsServer ); + } + + return CRMInstance::PreSpawn ( terrain, IsServer ); +} + +/************************************************************************************************ + * CRMGroupInstance::Spawn + * Adds the group instance to the given landscape using the specified origin. All sub instances + * will be added to the landscape within their min and max range from the origin. + * + * inputs: + * landscape: landscape to add the instance group to + * origin: origin of the instance group + * + * return: + * none + * + ************************************************************************************************/ +bool CRMGroupInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer ) +{ + rmInstanceIter_t it; + + // Spawn all the instances associated with this group + for(it = mInstances.begin(); it != mInstances.end(); it++) + { + CRMInstance* instance = *it; + instance->SetSide(GetSide()); // which side owns it? + + // Add the instance to the landscape now + instance->Spawn ( terrain, IsServer ); + } +#ifndef DEDICATED + DrawAutomapSymbol(); +#endif + return true; +} + +/************************************************************************************************ + * CRMGroupInstance::Preview + * Renders debug information for the instance + * + * inputs: + * from: point to render the preview from + * + * return: + * none + * + ************************************************************************************************/ +void CRMGroupInstance::Preview ( const vec3_t from ) +{ + rmInstanceIter_t it; + + CRMInstance::Preview ( from ); + + // Render all the instances + for(it = mInstances.begin(); it != mInstances.end(); it++) + { + CRMInstance* instance = *it; + + instance->Preview ( from ); + } +} + +/************************************************************************************************ + * CRMGroupInstance::SetArea + * Overidden to make sure the groups area doesnt eat up any room. The collision on the + * groups area will be turned off + * + * inputs: + * area: area to set + * + * return: + * none + * + ************************************************************************************************/ +void CRMGroupInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area ) +{ + rmInstanceIter_t it; + + bool collide = area->IsCollisionEnabled ( ); + + // Disable collision + area->EnableCollision ( false ); + + // Do what really needs to get done + CRMInstance::SetArea ( amanager, area ); + + // Prepare for spawn by calculating all the positions of the sub instances + // and flattening the ground below them. + for(it = mInstances.begin(); it != mInstances.end(); it++ ) + { + CRMInstance *instance = *it; + CRMArea *newarea; + vec3_t origin; + + // Drop it in the center of the group for now + origin[0] = GetOrigin()[0]; + origin[1] = GetOrigin()[1]; + origin[2] = 2500; + + // Set the area of position + newarea = amanager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), mPaddingSize, mConfineRadius, GetOrigin(), GetOrigin(), instance->GetFlattenRadius()?true:false, collide, instance->GetLockOrigin(), area->GetSymmetric ( ) ); + instance->SetArea ( amanager, newarea ); + } +} diff --git a/code/RMG/RM_Instance_Group.h b/code/RMG/RM_Instance_Group.h new file mode 100644 index 0000000..50b89c7 --- /dev/null +++ b/code/RMG/RM_Instance_Group.h @@ -0,0 +1,41 @@ +#pragma once +#if !defined(RM_INSTANCE_GROUP_H_INC) +#define RM_INSTANCE_GROUP_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Instance_Group.h") +#endif + +class CRMGroupInstance : public CRMInstance +{ +protected: + + rmInstanceList_t mInstances; + float mConfineRadius; + float mPaddingSize; + +public: + + CRMGroupInstance( CGPGroup* instGroup, CRMInstanceFile& instFile); + ~CRMGroupInstance(); + + virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer ); + virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer ); + + virtual void Preview ( const vec3_t from ); + + virtual void SetFilter ( const char *filter ); + virtual void SetTeamFilter ( const char *teamFilter ); + virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area ); + + virtual int GetPreviewColor ( ) { return (255<<24)+(255<<8); } + virtual float GetSpacingRadius ( ) { return 0; } + virtual float GetFlattenRadius ( ) { return 0; } + virtual void SetMirror(int mirror); + +protected: + + void RemoveInstances ( ); +}; + +#endif \ No newline at end of file diff --git a/code/RMG/RM_Instance_Random.cpp b/code/RMG/RM_Instance_Random.cpp new file mode 100644 index 0000000..48a5432 --- /dev/null +++ b/code/RMG/RM_Instance_Random.cpp @@ -0,0 +1,187 @@ +/************************************************************************************************ + * + * RM_Instance_Random.cpp + * + * Implements the CRMRandomInstance class. This class is reponsible for parsing a + * random instance as well as spawning it into a landscape. + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" + +#include "rm_instance_random.h" + +/************************************************************************************************ + * CRMRandomInstance::CRMRandomInstance + * constructs a random instance by choosing one of the sub instances and creating it + * + * inputs: + * instGroup: parser group containing infromation about this instance + * instFile: reference to an open instance file for creating sub instances + * + * return: + * none + * + ************************************************************************************************/ +CRMRandomInstance::CRMRandomInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile ) + : CRMInstance ( instGroup, instFile ) +{ + CGPGroup* group; + CGPGroup* groups[MAX_RANDOM_INSTANCES]; + int numGroups; + + // Build a list of the groups one can be chosen + for ( numGroups = 0, group = instGroup->GetSubGroups ( ); + group; + group = group->GetNext ( ) ) + { + // If this isnt an instance group then skip it + if ( stricmp ( group->GetName ( ), "instance" ) ) + { + continue; + } + + int multiplier = atoi(group->FindPairValue ( "multiplier", "1" )); + for ( ; multiplier > 0 && numGroups < MAX_RANDOM_INSTANCES; multiplier -- ) + { + groups[numGroups++] = group; + } + } + + // No groups, no instance + if ( !numGroups ) + { + // Initialize this now + mInstance = NULL; + + Com_Printf ( "WARNING: No sub instances specified for random instance '%s'\n", group->FindPairValue ( "name", "unknown" ) ); + return; + } + + // Now choose a group to parse + instGroup = groups[TheRandomMissionManager->GetLandScape()->irand(0,numGroups-1)]; + + // Create the child instance now. If the instance create fails then the + // IsValid routine will return false and this instance wont be added + mInstance = instFile.CreateInstance ( instGroup->FindPairValue ( "name", "" ) ); + mInstance->SetFilter(mFilter); + mInstance->SetTeamFilter(mTeamFilter); + + mAutomapSymbol = mInstance->GetAutomapSymbol(); + + SetMessage(mInstance->GetMessage()); + SetDescription(mInstance->GetDescription()); + SetInfo(mInstance->GetInfo()); +} + +/************************************************************************************************ + * CRMRandomInstance::~CRMRandomInstance + * Deletes the sub instance + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMRandomInstance::~CRMRandomInstance(void) +{ + if ( mInstance ) + { + delete mInstance; + } +} + +void CRMRandomInstance::SetMirror(int mirror) +{ + CRMInstance::SetMirror(mirror); + if (mInstance) + { + mInstance->SetMirror(mirror); + } +} + +void CRMRandomInstance::SetFilter( const char *filter ) +{ + CRMInstance::SetFilter(filter); + if (mInstance) + { + mInstance->SetFilter(filter); + } +} + +void CRMRandomInstance::SetTeamFilter( const char *teamFilter ) +{ + CRMInstance::SetTeamFilter(teamFilter); + if (mInstance) + { + mInstance->SetTeamFilter(teamFilter); + } +} + +/************************************************************************************************ + * CRMRandomInstance::PreSpawn + * Prepares for the spawn of the random instance + * + * inputs: + * landscape: landscape object this instance will be spawned on + * + * return: + * true: preparation successful + * false: preparation failed + * + ************************************************************************************************/ +bool CRMRandomInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer ) +{ + assert ( mInstance ); + + mInstance->SetFlattenHeight ( GetFlattenHeight( ) ); + + return mInstance->PreSpawn ( terrain, IsServer ); +} + +/************************************************************************************************ + * CRMRandomInstance::Spawn + * Spawns the instance onto the landscape + * + * inputs: + * landscape: landscape object this instance will be spawned on + * + * return: + * true: spawn successful + * false: spawn failed + * + ************************************************************************************************/ +bool CRMRandomInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer ) +{ + mInstance->SetObjective(GetObjective()); + mInstance->SetSide(GetSide()); + + if ( !mInstance->Spawn ( terrain, IsServer ) ) + { + return false; + } + + return true; +} + +/************************************************************************************************ + * CRMRandomInstance::SetArea + * Forwards the given area off to the internal instance + * + * inputs: + * area: area to be set + * + * return: + * none + * + ************************************************************************************************/ +void CRMRandomInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area ) +{ + CRMInstance::SetArea ( amanager, area ); + + mInstance->SetArea ( amanager, mArea ); +} diff --git a/code/RMG/RM_Instance_Random.h b/code/RMG/RM_Instance_Random.h new file mode 100644 index 0000000..20bdad9 --- /dev/null +++ b/code/RMG/RM_Instance_Random.h @@ -0,0 +1,40 @@ +#pragma once +#if !defined(RM_INSTANCE_RANDOM_H_INC) +#define RM_INSTANCE_RANDOM_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Instance_Random.h") +#endif + +#define MAX_RANDOM_INSTANCES 64 + +class CRMRandomInstance : public CRMInstance +{ +protected: + + CRMInstance* mInstance; + +public: + + CRMRandomInstance ( CGPGroup* instGroup, CRMInstanceFile& instFile ); + ~CRMRandomInstance ( ); + + virtual bool IsValid ( ) { return mInstance==NULL?false:true; } + + virtual int GetPreviewColor ( ) { return mInstance->GetPreviewColor ( ); } + + virtual float GetSpacingRadius ( ) { return mInstance->GetSpacingRadius ( ); } + virtual int GetSpacingLine ( ) { return mInstance->GetSpacingLine ( ); } + virtual float GetFlattenRadius ( ) { return mInstance->GetFlattenRadius ( ); } + virtual bool GetLockOrigin ( ) { return mInstance->GetLockOrigin ( ); } + + virtual void SetFilter ( const char *filter ); + virtual void SetTeamFilter ( const char *teamFilter ); + virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area ); + virtual void SetMirror (int mirror); + + virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer ); + virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer ); +}; + +#endif \ No newline at end of file diff --git a/code/RMG/RM_Instance_Void.cpp b/code/RMG/RM_Instance_Void.cpp new file mode 100644 index 0000000..fd1a303 --- /dev/null +++ b/code/RMG/RM_Instance_Void.cpp @@ -0,0 +1,53 @@ +/************************************************************************************************ + * + * RM_Instance_Void.cpp + * + * Implements the CRMVoidInstance class. This class just adds a void into the + * area manager to help space things out. + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" + +#include "rm_instance_void.h" + +/************************************************************************************************ + * CRMVoidInstance::CRMVoidInstance + * constructs a void instance + * + * inputs: + * instGroup: parser group containing infromation about this instance + * instFile: reference to an open instance file for creating sub instances + * + * return: + * none + * + ************************************************************************************************/ +CRMVoidInstance::CRMVoidInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile ) + : CRMInstance ( instGroup, instFile ) +{ + mSpacingRadius = atof( instGroup->FindPairValue ( "spacing", "0" ) ); + mFlattenRadius = atof( instGroup->FindPairValue ( "flatten", "0" ) ); +} + +/************************************************************************************************ + * CRMVoidInstance::SetArea + * Overidden to make sure the void area doesnt continually. + * + * inputs: + * area: area to set + * + * return: + * none + * + ************************************************************************************************/ +void CRMVoidInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area ) +{ + // Disable collision + area->EnableCollision ( false ); + + // Do what really needs to get done + CRMInstance::SetArea ( amanager, area ); +} diff --git a/code/RMG/RM_Instance_Void.h b/code/RMG/RM_Instance_Void.h new file mode 100644 index 0000000..a437d89 --- /dev/null +++ b/code/RMG/RM_Instance_Void.h @@ -0,0 +1,18 @@ +#pragma once +#if !defined(RM_INSTANCE_VOID_H_INC) +#define RM_INSTANCE_VOID_H_INC + +#ifdef DEBUG_LINKING + #pragma message("...including RM_Instance_Void.h") +#endif + +class CRMVoidInstance : public CRMInstance +{ +public: + + CRMVoidInstance ( CGPGroup* instGroup, CRMInstanceFile& instFile ); + + virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area ); +}; + +#endif \ No newline at end of file diff --git a/code/RMG/RM_Manager.cpp b/code/RMG/RM_Manager.cpp new file mode 100644 index 0000000..bded10b --- /dev/null +++ b/code/RMG/RM_Manager.cpp @@ -0,0 +1,402 @@ +/************************************************************************************************ + * + * RM_Manager.cpp + * + * Implements the CRMManager class. The CRMManager class manages the arioche system. + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" +#include "../server/server.h" + +CRMObjective *CRMManager::mCurObjective=0; + +/************************************************************************************************ + * TheRandomMissionManager + * Pointer to only active CRMManager class + * + ************************************************************************************************/ +CRMManager *TheRandomMissionManager; + +/************************************************************************************************ + * CRMManager::CRMManager + * constructor + * + * inputs: + * + * return: + * + ************************************************************************************************/ +CRMManager::CRMManager(void) +{ + mLandScape = NULL; + mTerrain = NULL; + mMission = NULL; + mCurPriority = 1; + mUseTimeLimit = false; +} + +/************************************************************************************************ + * CRMManager::~CRMManager + * destructor + * + * inputs: + * + * return: + * + ************************************************************************************************/ +CRMManager::~CRMManager(void) +{ +#ifndef FINAL_BUILD + Com_Printf ("... Shutting down TheRandomMissionManager\n"); +#endif +#ifndef DEDICATED + CM_TM_Free(); +#endif + if (mMission) + { + delete mMission; + mMission = NULL; + } +} + +/************************************************************************************************ + * CRMManager::SetLandscape + * Sets the landscape and terrain object used to load a mission + * + * inputs: + * landscape - landscape object + * + * return: + * none + * + ************************************************************************************************/ +void CRMManager::SetLandScape(CCMLandScape *landscape) +{ + mLandScape = landscape; + mTerrain = landscape->GetRandomTerrain(); +} + +/************************************************************************************************ + * CRMManager::LoadMission + * Loads the mission using the mission name stored in the ar_mission cvar + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +bool CRMManager::LoadMission ( qboolean IsServer ) +{ +#ifndef PRE_RELEASE_DEMO + char instances[MAX_QPATH]; + char mission[MAX_QPATH]; + char course[MAX_QPATH]; + char map[MAX_QPATH]; + char temp[MAX_QPATH]; + +#ifndef FINAL_BUILD + Com_Printf ("--------- Random Mission Manager ---------\n\n"); + Com_Printf ("RMG version : 0.01\n\n"); +#endif + + if (!mTerrain) + { + return false; + } + + // Grab the arioche variables + Cvar_VariableStringBuffer("rmg_usetimelimit", temp, MAX_QPATH); + if (strcmpi(temp, "yes") == 0) + { + mUseTimeLimit = true; + } + Cvar_VariableStringBuffer("rmg_instances", instances, MAX_QPATH); + Cvar_VariableStringBuffer("RMG_mission", temp, MAX_QPATH); + Cvar_VariableStringBuffer("rmg_map", map, MAX_QPATH); + sprintf(mission, "%s_%s", temp, map); + Cvar_VariableStringBuffer("rmg_course", course, MAX_QPATH); + + // dump existing mission, if any + if (mMission) + { + delete mMission; + mMission = NULL; + } + + // Create a new mission file + mMission = new CRMMission ( mTerrain ); + + // Load the mission using the arioche variables + if ( !mMission->Load ( mission, instances, course ) ) + { + return false; + } + + if (mUseTimeLimit) + { + Cvar_Set("rmg_timelimit", va("%d", mMission->GetTimeLimit())); + } + else + { + Cvar_Set("rmg_timelimit", "0"); + } + + if (IsServer) + { // set the names of the teams + CGenericParser2 parser; + //CGPGroup* root; + + Cvar_VariableStringBuffer("RMG_terrain", temp, MAX_QPATH); + + /* + // Create the parser for the mission file + if(Com_ParseTextFile(va("ext_data/rmg/%s.teams", temp), parser)) + { + root = parser.GetBaseParseGroup()->GetSubGroups(); + if (0 == stricmp(root->GetName(), "teams")) + { + SV_SetConfigstring( CS_GAMETYPE_REDTEAM, root->FindPairValue ( "red", "marine" )); + SV_SetConfigstring( CS_GAMETYPE_BLUETEAM, root->FindPairValue ( "blue", "thug" )); + } + parser.Clean(); + } + */ + //rww - This is single player, no such thing. + } + + // Must have a valid landscape before we can spawn the mission + assert ( mLandScape ); + +#ifndef FINAL_BUILD + Com_Printf ("------------------------------------------\n"); +#endif + + return true; +#else + return false; +#endif // PRE_RELEASE_DEMO +} + +/************************************************************************************************ + * CRMManager::IsMissionComplete + * Determines whether or not all the arioche objectives have been met + * + * inputs: + * none + * + * return: + * true: all objectives have been completed + * false: one or more of the objectives has not been met + * + ************************************************************************************************/ +bool CRMManager::IsMissionComplete(void) +{ + if ( NULL == mMission->GetCurrentObjective ( ) ) + { + return true; + } + + return false; +} + +/************************************************************************************************ + * CRMManager::HasTimeExpired + * Determines whether or not the time limit (if one) has expired + * + * inputs: + * none + * + * return: + * true: time limit has expired + * false: time limit has not expired + * + ************************************************************************************************/ +bool CRMManager::HasTimeExpired(void) +{ +/* if (mMission->GetTimeLimit() == 0 || !mUseTimeLimit) + { // no time limit set + return false; + } + + if (mMission->GetTimeLimit() * 1000 * 60 > level.time - level.startTime) + { // we are still under our time limit + return false; + } + + // over our time limit! + return true;*/ + + return false; +} + +/************************************************************************************************ + * CRMManager::UpdateStatisticCvars + * Updates the statistic cvars with data from the game + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +void CRMManager::UpdateStatisticCvars ( void ) +{ +/* // No player set then nothing more to do + if ( mPlayer ) + { + float accuracy; + + // Calculate the accuracy + accuracy = (float)mPlayer->client->ps.persistant[PERS_SHOTS_HIT]; + accuracy /= (float)mPlayer->client->ps.persistant[PERS_SHOTS]; + accuracy *= 100.0f; + + // set the accuracy cvar + gi.Cvar_Set ( "ar_pl_accuracy", va("%d%%",(int)accuracy) ); + + // Set the # of kills cvar + gi.Cvar_Set ( "ar_kills", va("%d", mPlayer->client->ps.persistant[PERS_SCORE] ) ); + + int hours; + int mins; + int seconds; + int tens; + int millisec = (level.time - level.startTime); + + seconds = millisec / 1000; + hours = seconds / (60 * 60); + seconds -= (hours * 60 * 60); + mins = seconds / 60; + seconds -= mins * 60; + tens = seconds / 10; + seconds -= tens * 10; + + gi.Cvar_Set ( "ar_duration", va("%dhr %dmin %dsec", hours, mins, seconds ) ); + + WpnID wpnID = TheWpnSysMgr().GetFavoriteWeapon ( ); + gi.Cvar_Set ( "ar_fav_wp", CWeaponSystem::GetWpnName ( wpnID ) ); + + // show difficulty + char difficulty[MAX_QPATH]; + gi.Cvar_VariableStringBuffer("g_skill", difficulty, MAX_QPATH); + strupr(difficulty); + gi.Cvar_Set ( "ar_diff", va("&GENERIC_%s&",difficulty) ); + + // compute rank + float compositeRank = 1; + int rankMax = 3; // max rank less 1 + float timeRank = mUseTimeLimit ? (1.0f - (mins / (float)mMission->GetTimeLimit())) : 0; + float killRank = mPlayer->client->ps.persistant[PERS_SCORE] / (float)GetCharacterManager().GetAllSize(); + killRank = (killRank > 0) ? killRank : 1.0f; + float accuRank = (accuracy > 0) ? accuracy*0.01f : 1.0f; + float weapRank = 1.0f - CWeaponSystem::GetRank(wpnID); + + compositeRank = ((timeRank + killRank + accuRank + weapRank) / 3.0f) * rankMax + 1; + + if (compositeRank > 4) + compositeRank = 4; + + gi.Cvar_Set ( "ar_rank", va("&RMG_RANK%d&",((int)compositeRank)) ); + }*/ +} + +/************************************************************************************************ + * CRMManager::CompleteMission + * Does end-of-mission stuff (pause game, end screen, return to menu) + * * + * Input * + * : * + * Output / Return * + * : * + ************************************************************************************************/ +void CRMManager::CompleteMission(void) +{ + UpdateStatisticCvars ( ); + + mMission->CompleteMission(); +} + +/************************************************************************************************ + * CRMManager::FailedMission + * Does end-of-mission stuff (pause game, end screen, return to menu) + * * + * Input * + * TimeExpired: indicates if the reason failed was because of time + * Output / Return * + * : * + ************************************************************************************************/ +void CRMManager::FailedMission(bool TimeExpired) +{ + UpdateStatisticCvars ( ); + + mMission->FailedMission(TimeExpired); +} + +/************************************************************************************************ + * CRMManager::CompleteObjective + * Marks the given objective as completed + * + * inputs: + * obj: objective to set as completed + * + * return: + * none + * + ************************************************************************************************/ +void CRMManager::CompleteObjective ( CRMObjective *obj ) +{ + assert ( obj ); + + mMission->CompleteObjective ( obj ); +} + +/************************************************************************************************ + * CRMManager::Preview + * previews the random mission genration information + * + * inputs: + * from: origin being previed from + * + * return: + * none + * + ************************************************************************************************/ +void CRMManager::Preview ( const vec3_t from ) +{ + // Dont bother if we havent reached our timer yet +/* if ( level.time < mPreviewTimer ) + { + return; + } + + // Let the mission do all the previewing + mMission->Preview ( from ); + + // Another second + mPreviewTimer = level.time + 1000;*/ +} + +/************************************************************************************************ + * CRMManager::Preview + * previews the random mission genration information + * + * inputs: + * from: origin being previed from + * + * return: + * none + * + ************************************************************************************************/ +bool CRMManager::SpawnMission ( qboolean IsServer ) +{ + // Spawn the mission + mMission->Spawn ( mTerrain, IsServer ); + + return true; +} diff --git a/code/RMG/RM_Manager.h b/code/RMG/RM_Manager.h new file mode 100644 index 0000000..c423a06 --- /dev/null +++ b/code/RMG/RM_Manager.h @@ -0,0 +1,55 @@ +#pragma once +#if !defined(RM_MANAGER_H_INC) +#define RM_MANAGER_H_INC + +#if !defined(CM_LANDSCAPE_H_INC) +#include "../qcommon/cm_landscape.h" +#endif + +class CRMManager +{ +private: + + CRMMission* mMission; + CCMLandScape* mLandScape; + CRandomTerrain* mTerrain; + int mPreviewTimer; + int mCurPriority; + bool mUseTimeLimit; + + void UpdateStatisticCvars ( void ); + +public: + + // Constructors + CRMManager (void); + ~CRMManager (void); + + bool LoadMission ( qboolean IsServer ); + bool SpawnMission ( qboolean IsServer ); + + // Accessors + void SetLandScape (CCMLandScape *landscape); + void SetCurPriority (int priority) { mCurPriority = priority; } + + CRandomTerrain* GetTerrain (void) { return mTerrain; } + CCMLandScape* GetLandScape (void) { return mLandScape; } + CRMMission* GetMission (void) { return mMission; } + int GetCurPriority (void) { return mCurPriority; } + + void Preview ( const vec3_t from ); + + bool IsMissionComplete (void); + bool HasTimeExpired (void); + void CompleteObjective ( CRMObjective *obj ); + void CompleteMission (void); + void FailedMission (bool TimeExpired); + + // eek + static CRMObjective *mCurObjective; +}; + +extern CRMManager* TheRandomMissionManager; + + +#endif // RANDOMMISSION_H_INC \ No newline at end of file diff --git a/code/RMG/RM_Mission.cpp b/code/RMG/RM_Mission.cpp new file mode 100644 index 0000000..193fc52 --- /dev/null +++ b/code/RMG/RM_Mission.cpp @@ -0,0 +1,1930 @@ +/************************************************************************************************ + * + * RM_Mission.cpp + * + * implements the CRMMission class. The CRMMission class loads and manages an arioche mission + * + ************************************************************************************************/ + +#include "../server/exe_headers.h" + +#include "rm_headers.h" + +#define ARIOCHE_CLIPBRUSH_SIZE 300 +#define CVAR_OBJECTIVE 0 + +/************************************************************************************************ + * CRMMission::CRMMission + * constructor + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMMission::CRMMission ( CRandomTerrain* landscape ) +{ + mCurrentObjective = NULL; + mValidPaths = false; + mValidRivers = false; + mValidNodes = false; + mValidWeapons = false; + mValidAmmo = false; + mValidObjectives = false; + mValidInstances = false; + mTimeLimit = 0; + mMaxInstancePosition = 1; + mAccuracyMultiplier = 1.0f; + mHealthMultiplier = 1.0f; + mPickupHealth = 1.0f; + mPickupArmor = 1.0f; + mPickupAmmo = 1.0f; + mPickupWeapon = 1.0f; + mPickupEquipment = 1.0f; + + mDefaultPadding = 0; + mSymmetric = SYMMETRY_NONE; + +// mCheckedEnts.clear(); + + mLandScape = landscape; + + // cut down the possible area that is 'legal' for area manager to use by 20% + vec3_t land_min, land_max; + + land_min[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * 0.1f; + land_min[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * 0.1f; + land_min[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * 0.1f; + + land_max[0] = mLandScape->GetBounds ( )[1][0] - (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * 0.1f; + land_max[1] = mLandScape->GetBounds ( )[1][1] - (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * 0.1f; + land_max[2] = mLandScape->GetBounds ( )[1][2] - (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * 0.1f; + + // Create a new area manager for the landscape + mAreaManager = new CRMAreaManager ( land_min, + land_max ); + + // Create a new path manager + mPathManager = new CRMPathManager ( mLandScape ); +} + +/************************************************************************************************ + * CRMMission::~CRMMission + * destructor + * + * inputs: + * none + * + * return: + * none + * + ************************************************************************************************/ +CRMMission::~CRMMission ( ) +{ + rmObjectiveIter_t oit; + rmInstanceIter_t iit; + +// mCheckedEnts.clear(); + + // Cleanup the objectives + for (oit = mObjectives.begin(); oit != mObjectives.end(); oit++) + { + delete (*oit); + } + + // Cleanup the instances + for (iit = mInstances.begin(); iit != mInstances.end(); iit++) + { + delete (*iit); + } + + if (mPathManager) + { + delete mPathManager; + mPathManager = 0; + } + + if (mAreaManager) + { + delete mAreaManager; + mAreaManager = 0; + } +} + +/************************************************************************************************ + * CRMMission::FindObjective + * searches through the missions objectives for the one with the given name + * + * inputs: + * name: name of objective to find + * + * return: + * objective: objective matching the given name or NULL if it couldnt be found + * + ************************************************************************************************/ +CRMObjective* CRMMission::FindObjective ( const char* name ) +{ + rmObjectiveIter_t it; + + for (it = mObjectives.begin(); it != mObjectives.end(); it++) + { + // Does it match? + if (!stricmp ((*it)->GetName(), name )) + { + return (*it); + } + } + + // Not found + return NULL; +} + +void CRMMission::MirrorPos(vec3_t pos) +{ + pos[0] = 1.0f - pos[0]; + pos[1] = 1.0f - pos[1]; +} + +/************************************************************************************************ + * CRMMission::ParseOrigin + * parses an origin block which includes linking to a node and absolute origins + * + * inputs: + * group: parser group containing the node or origin + * + * return: + * true: parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseOrigin ( CGPGroup* originGroup, vec3_t origin, vec3_t lookat, int* flattenHeight ) +{ + const char* szNodeName; + vec3_t mins; + vec3_t maxs; + + if ( flattenHeight ) + { + *flattenHeight = 66; + } + + // If no group was given then use 0,0,0 + if ( NULL == originGroup ) + { + VectorCopy ( vec3_origin, origin ); + return false; + } + + // See if attaching to a named node + szNodeName = originGroup->FindPairValue ( "node", "" ); + if ( *szNodeName ) + { + CRMNode* node; + // Find the node being attached to + node = mPathManager->FindNodeByName ( szNodeName ); + if ( node ) + { + if ( flattenHeight ) + { + if ( node->GetFlattenHeight ( ) == -1 ) + { + node->SetFlattenHeight ( 40 + mLandScape->irand(0,40) ); + } + + *flattenHeight = node->GetFlattenHeight ( ); + } + + VectorCopy(node->GetPos(), origin); + + VectorCopy ( origin, lookat ); + + int dir; + int rnd_offset = mLandScape->irand(0, DIR_MAX-1); + for (dir=0; dirPathExist(d)) + { + vec4_t tmp_pt, tmp_dir; + int pathID = node->GetPath(d); + mLandScape->GetPathInfo(pathID, 0.1f, tmp_pt, tmp_dir ); + lookat[0] = tmp_pt[0]; + lookat[1] = tmp_pt[1]; + lookat[2] = 0; + return true; + } + } + return true; + } + } + + mins[0] = atof( originGroup->FindPairValue ( "left", ".1" ) ); + mins[1] = atof( originGroup->FindPairValue ( "top", ".1" ) ); + maxs[0] = atof( originGroup->FindPairValue ( "right", ".9" ) ); + maxs[1] = atof( originGroup->FindPairValue ( "bottom", ".9" ) ); + + lookat[0] = origin[0] = mLandScape->flrand(mins[0],maxs[0]); + lookat[1] = origin[1] = mLandScape->flrand(mins[1],maxs[1]); + lookat[2] = origin[2] = 0; + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseNodes + * parses all the named nodes in the file + * + * inputs: + * group: parser group containing the named nodes + * + * return: + * true: parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseNodes ( CGPGroup* group ) +{ + // If NULL that means this particular difficulty level has no named nodes + if ( NULL == group || mValidNodes) + { + return true; + } + + // how many nodes spaced over map? + int x_cells; + int y_cells; + + x_cells = atoi ( group->FindPairValue ( "x_cells", "3" ) ); + y_cells = atoi ( group->FindPairValue ( "y_cells", "3" ) ); + + mPathManager->CreateArray(x_cells, y_cells); + + // Loop through all the nodes and generate each as specified + for ( group = group->GetSubGroups(); + group; + group=group->GetNext() ) + { + int min_depth = atof( group->FindPairValue ( "min_depth", "0" ) ); + int max_depth = atof( group->FindPairValue ( "max_depth", "5" ) ); + int min_paths = atoi( group->FindPairValue ( "min_paths", "1" ) ); + int max_paths = atoi( group->FindPairValue ( "max_paths", "1" ) ); + + mPathManager->CreateLocation( group->GetName(), min_depth, max_depth, min_paths, max_paths ); + } + + mValidNodes = true; + return true; +} + +/************************************************************************************************ + * CRMMission::ParsePaths + * parses all path styles in the file and then generates paths + * + * inputs: + * group: parser group containing the list of path styles + * + * return: + * true: parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParsePaths ( CGPGroup* group ) +{ + // If NULL that means this particular difficulty level has no paths + if ( NULL == group || mValidPaths) + { + return true; + } + + // path style info + float depth; + float deviation; + float breadth; + float minwidth; + float maxwidth; + int points; + + points = atoi ( group->FindPairValue ( "points", "10" ) ); + depth = atof ( group->FindPairValue ( "depth", ".31" ) ); + deviation = atof ( group->FindPairValue ( "deviation", ".025" ) ); + breadth = atof ( group->FindPairValue ( "breadth", "5" ) ); + minwidth = atof ( group->FindPairValue ( "minwidth", ".03" ) ); + maxwidth = atof ( group->FindPairValue ( "maxwidth", ".05" ) ); + + mPathManager->SetPathStyle( points, minwidth, maxwidth, depth, deviation, breadth); + + if (!mValidPaths) + { // we must create paths + mPathManager->GeneratePaths( mSymmetric ); + mValidPaths = true; + } + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseRivers + * parses all river styles in the file and then generates rivers + * + * inputs: + * group: parser group containing the list of path styles + * + * return: + * true: parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseRivers ( CGPGroup* group ) +{ + // If NULL that means this particular difficulty level has no rivers + if ( NULL == group || mValidRivers) + { + return true; + } + + // river style info + int maxdepth; + float beddepth; + float deviation; + float breadth; + float minwidth; + float maxwidth; + int points; + string bridge_name; + + maxdepth = atoi ( group->FindPairValue ( "maxpathdepth", "5" ) ); + points = atoi ( group->FindPairValue ( "points", "10" ) ); + beddepth = atof ( group->FindPairValue ( "depth", "1" ) ); + deviation = atof ( group->FindPairValue ( "deviation", ".03" ) ); + breadth = atof ( group->FindPairValue ( "breadth", "7" ) ); + minwidth = atof ( group->FindPairValue ( "minwidth", ".01" ) ); + maxwidth = atof ( group->FindPairValue ( "maxwidth", ".03" ) ); + bridge_name= group->FindPairValue ( "bridge", "" ) ; + + mPathManager->SetRiverStyle( maxdepth, points, minwidth, maxwidth, beddepth, deviation, breadth, bridge_name); + + if (!mValidRivers && + beddepth < 1) // use a depth of 1 if we don't want any rivers + { // we must create rivers + mPathManager->GenerateRivers(); + mValidRivers = true; + } + + return true; +} + +void CRMMission::PlaceBridges() +{ + if (!mValidRivers || strlen(mPathManager->GetBridgeName()) < 1) + return; + + int max_bridges = 0; + int path; + float t; + float river_depth = mLandScape->GetLandScape()->GetWaterHeight(); + vec3_t pos, lastpos; + vec3pair_t bounds; + VectorSet(bounds[0], 0,0,0); + VectorSet(bounds[1], 0,0,0); + + // walk along paths looking for dips + for (path = 0; path < mPathManager->GetPathCount(); path++) + { + vec4_t tmp_pt, tmp_dir; + bool new_water = true; + + mLandScape->GetPathInfo(path, 0, tmp_pt, tmp_dir ); + lastpos[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * tmp_pt[0]; + lastpos[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * tmp_pt[1]; + lastpos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * tmp_pt[2]; + mLandScape->GetLandScape()->GetWorldHeight ( lastpos, bounds, true ); + + const float delta = 0.05f; + for (t= delta; t < 1.0f; t += delta) + { + mLandScape->GetPathInfo(path, t, tmp_pt, tmp_dir ); + pos[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * tmp_pt[0]; + pos[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * tmp_pt[1]; + pos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * tmp_pt[2]; + mLandScape->GetLandScape()->GetWorldHeight ( pos, bounds, true ); + + if (new_water && + lastpos[2] < river_depth && + pos[2] < river_depth && + pos[2] > lastpos[2]) + { // add a bridge + if (max_bridges < 3) + { + CRMArea* area; + CRMInstance* instance; + + max_bridges++; + + // create a single bridge + lastpos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * mPathManager->GetPathDepth(); + instance = mInstanceFile.CreateInstance ( mPathManager->GetBridgeName() ); + + if ( NULL != instance ) + { // Set the area + vec3_t zerodvec; + VectorClear(zerodvec); + area = mAreaManager->CreateArea ( lastpos, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, zerodvec, pos, instance->GetFlattenRadius()?true:false, false, instance->GetLockOrigin() ); + area->EnableLookAt(false); + + instance->SetArea ( mAreaManager, area ); + mInstances.push_back ( instance ); + new_water = false; + } + } + } + else if (pos[2] > river_depth) + { // hit land again + new_water = true; + } + VectorCopy ( pos, lastpos ); + } + } +} + +void CRMMission::PlaceWallInstance(CRMInstance* instance, float xpos, float ypos, float zpos, int x, int y, float angle) +{ + if (NULL == instance) + return; + + float spacing = instance->GetSpacingRadius(); + CRMArea* area; + vec3_t origin; + vec3_t zerodvec; + VectorClear(zerodvec); + + origin[0] = xpos + spacing * x; + origin[1] = ypos + spacing * y; + origin[2] = zpos; + + // Set the area of position + area = mAreaManager->CreateArea ( origin, (spacing / 2.1f), 0, GetDefaultPadding(), 0, zerodvec, origin, instance->GetFlattenRadius()?true:false, false, instance->GetLockOrigin() ); + area->EnableLookAt(false); + area->SetAngle(angle); + instance->SetArea ( mAreaManager, area ); + + mInstances.push_back ( instance ); +} + + +/************************************************************************************************ + * CRMMission::ParseWallRect + * creates instances for walled rectangle at this node (fence) + * + * inputs: + * group: parser group containing the wall rect info + * + * return: + * true: parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseWallRect(CGPGroup* group , int side) +{ +#ifndef PRE_RELEASE_DEMO + CGPGroup* wallGroup = group->FindSubGroup ( "wallrect" ) ; + + // If NULL that means this particular instance has no wall rect + if ( NULL == group || NULL == wallGroup) + { + return true; + } + + const char* wallName = wallGroup->FindPairValue ( "wall_instance", "" ); + const char* cornerName = wallGroup->FindPairValue ( "corner_instance", "" ); + const char* towerName = wallGroup->FindPairValue ( "tower_instance", "" ); + const char* gateName = wallGroup->FindPairValue ( "gate_instance", "" ); + const char* ripName = wallGroup->FindPairValue ( "rip_instance", "" ); + + if ( NULL != wallName ) + { + int xcount = atoi( wallGroup->FindPairValue ( "xcount", "0" ) ); + int ycount = atoi( wallGroup->FindPairValue ( "ycount", "0" ) ); + + int gateCount = atoi( wallGroup->FindPairValue ( "gate_count", "1" ) ); + int gateMin = atoi( wallGroup->FindPairValue ( "gate_min", "0" ) ); + int gateMax = atoi( wallGroup->FindPairValue ( "gate_max", "0" ) ); + + int ripCount = atoi( wallGroup->FindPairValue ( "rip_count", "0" ) ); + int ripMin = atoi( wallGroup->FindPairValue ( "rip_min", "0" ) ); + int ripMax = atoi( wallGroup->FindPairValue ( "rip_max", "0" ) ); + + int towerCount = atoi( wallGroup->FindPairValue ( "tower_count", "0" ) ); + int towerMin = atoi( wallGroup->FindPairValue ( "tower_min", "0" ) ); + int towerMax = atoi( wallGroup->FindPairValue ( "tower_max", "0" ) ); + + if (gateMin != gateMax) + gateCount = mLandScape->irand(gateMin,gateMax); + + if (ripMin != ripMax) + ripCount = mLandScape->irand(ripMin,ripMax); + + if (towerMin != towerMax) + towerCount = mLandScape->irand(towerMin,towerMax); + + if (NULL == gateName) + gateCount = 0; + + if (NULL == towerName) + towerCount = 0; + + if (NULL == ripName) + ripCount = 0; + + const char* nodename; + CGPGroup* originGroup = group->FindSubGroup ( "origin" ); + if (originGroup) + { + nodename = originGroup->FindPairValue ( "node", "" ); + if (*nodename) + { + CRMNode* node; + // Find the node being attached to + node = mPathManager->FindNodeByName ( nodename ); + if ( node ) + { + CRMInstance* instance; + int x,y; + int halfx = xcount/2; + int halfy = ycount/2; + float xpos = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * node->GetPos()[0]; + float ypos = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * node->GetPos()[1]; + float zpos = mLandScape->GetBounds ( )[1][2] + 100; + float angle = 0; + int lastGate = 0; + int lastRip = 0; + + // corners + x = -halfx; + y = -halfy; + if (towerCount > 3 || + (towerCount > 0 && mLandScape->irand(1,2) == 1) ) + { + towerCount--; + instance = mInstanceFile.CreateInstance ( towerName ); + } + else + instance = mInstanceFile.CreateInstance ( cornerName ); + angle = (float)DEG2RAD(90); + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle); + + x = halfx; + y = -halfy; + if (towerCount > 3 || + (towerCount > 0 && mLandScape->irand(1,2) == 1) ) + { + towerCount--; + instance = mInstanceFile.CreateInstance ( towerName ); + } + else + instance = mInstanceFile.CreateInstance ( cornerName ); + angle = (float)DEG2RAD(180); + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle); + + x = halfx; + y = halfy; + if (towerCount > 3 || + (towerCount > 0 && mLandScape->irand(1,2) == 1) ) + { + towerCount--; + instance = mInstanceFile.CreateInstance ( towerName ); + } + else + instance = mInstanceFile.CreateInstance ( cornerName ); + angle = (float)DEG2RAD(270); + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle); + + x = -halfx; + y = halfy; + if (towerCount > 3 || + (towerCount > 0 && mLandScape->irand(1,2) == 1) ) + { + towerCount--; + instance = mInstanceFile.CreateInstance ( towerName ); + } + else + instance = mInstanceFile.CreateInstance ( cornerName ); + angle = DEG2RAD(0); + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle); + + // walls + angle = DEG2RAD(0); + for (x = -halfx+1; x <= halfx-1; x++) + { + if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1) + { // gate + gateCount--; + lastGate = 3; + instance = mInstanceFile.CreateInstance ( gateName ); + } + else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1) + { // damaged fence + ripCount--; + lastRip = 3; + instance = mInstanceFile.CreateInstance ( ripName ); + } + else + { // just a wall + instance = mInstanceFile.CreateInstance ( wallName ); + lastRip--; + lastGate--; + } + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, x, -halfy, angle); + } + for (x = -halfx+1; x <= halfx-1; x++) + { + if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1) + { // gate + gateCount--; + lastGate = 3; + instance = mInstanceFile.CreateInstance ( gateName ); + } + else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1) + { // damaged fence + ripCount--; + lastRip = 3; + instance = mInstanceFile.CreateInstance ( ripName ); + } + else + { // just a wall + instance = mInstanceFile.CreateInstance ( wallName ); + lastRip--; + lastGate--; + } + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, x, halfy, angle); + } + + angle = (float)DEG2RAD(90); + for (y = -halfy+1; y <= halfy-1; y++) + { + if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1) + { // gate + gateCount--; + lastGate = 3; + instance = mInstanceFile.CreateInstance ( gateName ); + } + else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1) + { // damaged fence + ripCount--; + lastRip = 3; + instance = mInstanceFile.CreateInstance ( ripName ); + } + else + { // just a wall + instance = mInstanceFile.CreateInstance ( wallName ); + lastRip--; + lastGate--; + } + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, -halfx, y, angle); + } + for (y = -halfy+1; y <= halfy-1; y++) + { + if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1) + { // gate + gateCount--; + lastGate = 3; + instance = mInstanceFile.CreateInstance ( gateName ); + } + else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1) + { // damaged fence + ripCount--; + lastRip = 3; + instance = mInstanceFile.CreateInstance ( ripName ); + } + else + { // just a wall + instance = mInstanceFile.CreateInstance ( wallName ); + lastRip--; + lastGate--; + } + instance->SetSide(side); + PlaceWallInstance(instance, xpos, ypos, zpos, halfx, y, angle); + } + } + } + } + } + else + return false; +#endif // #ifndef PRE_RELEASE_DEMO + + return true; +} + + +/************************************************************************************************ + * CRMMission::ParseInstancesOnPath + * creates instances on path between nodes + * + * inputs: + * group: parser group containing the defenses, other instances on the path between nodes + * + * return: + * true: parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseInstancesOnPath ( CGPGroup* group ) +{ +#ifndef PRE_RELEASE_DEMO + CGPGroup* defenseGroup; + for ( defenseGroup = group->GetSubGroups(); + defenseGroup; + defenseGroup=defenseGroup->GetNext() ) + if (stricmp ( defenseGroup->GetName ( ), "defenses" )==0 || + stricmp ( defenseGroup->GetName(), "instanceonpath")==0) + { + const char* defName = defenseGroup->FindPairValue ( "instance", "" ); + if ( *defName ) + { + float minpos; + float maxpos; + int mincount; + int maxcount; + + // how far along path does this get placed? + minpos = atof( defenseGroup->FindPairValue ( "minposition", "0.5" ) ); + maxpos = atof( defenseGroup->FindPairValue ( "maxposition", "0.5" ) ); + mincount = atoi( defenseGroup->FindPairValue ( "mincount", "1" ) ); + maxcount = atoi( defenseGroup->FindPairValue ( "maxcount", "1" ) ); + + const char* nodename; + CGPGroup* originGroup = group->FindSubGroup ( "origin" ); + if (originGroup) + { + nodename = originGroup->FindPairValue ( "node", "" ); + if (*nodename) + { + CRMNode* node; + // Find the node being attached to + node = mPathManager->FindNodeByName ( nodename ); + if ( node ) + { + int dir; + // look at each connection from this node to others, if there is a path, create a defense + for (dir=0; dirPathExist(dir)) + { // path leads out of this node + CRMArea* area; + CRMInstance* instance; + float spacing; + vec3_t origin; + vec3_t lookat; + vec4_t tmp_pt, tmp_dir; + int n,num_insts = mLandScape->irand(mincount,maxcount); + int pathID = node->GetPath(dir); + + if (0 == num_insts) + continue; + + float posdelta = (maxpos - minpos) / num_insts; + + for (n=0; nFindPairValue ( "spacing", "0" ) ); + if ( spacing ) + { + instance->SetSpacingRadius ( spacing ); + } + + instance->SetFilter(group->FindPairValue("filter", "")); + instance->SetTeamFilter(group->FindPairValue("teamfilter", "")); + + if (strstr(instance->GetTeamFilter(),"red")) + instance->SetSide(SIDE_RED); + else if (strstr(instance->GetTeamFilter(),"blue")) + instance->SetSide(SIDE_BLUE); + + float pos_along_path = mLandScape->flrand(minpos + posdelta*n, minpos + posdelta*(n+1)); + float look_along_path = atof( defenseGroup->FindPairValue ( "pathalign", "1" ) ) ; + mLandScape->GetPathInfo (pathID, pos_along_path, tmp_pt, tmp_dir ); + origin[0] = tmp_pt[0]; + origin[1] = tmp_pt[1]; + + mLandScape->GetPathInfo (pathID, look_along_path, tmp_dir, tmp_pt ); + lookat[0] = tmp_pt[0]; + lookat[1] = tmp_pt[1]; + + origin[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * origin[0]; + origin[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * origin[1]; + origin[2] = mLandScape->GetBounds ( )[0][2] ; + + // look at a point along the path at this location + lookat[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * lookat[0]; + lookat[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * lookat[1]; + lookat[2] = 0; + + // Fixed height? (used for bridges) + if ( !atoi(group->FindPairValue ( "nodrop", "0" )) ) + { + origin[2] = mLandScape->GetBounds ( )[1][2] + 100; + } + + // Set the area of position + area = mAreaManager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, origin, lookat, instance->GetFlattenRadius()?true:false, true, instance->GetLockOrigin(), mSymmetric ); + area->EnableLookAt(false); + + if ( node->GetFlattenHeight ( ) == -1 ) + { + node->SetFlattenHeight ( 66 + mLandScape->irand(0,40) ); + } + instance->SetFlattenHeight ( node->GetFlattenHeight ( ) ); + + instance->SetArea ( mAreaManager, area ); + + mInstances.push_back ( instance ); + } + } + } + } + } + } + else + return false; + } + else + return false; + + } +#endif // #ifndef PRE_RELEASE_DEMO + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseInstance + * Parses an individual instance + * + * inputs: + * group: parser group containing the list of instances + * + * return: + * true: instances parsed successfully + * false: instances failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseInstance ( CGPGroup* group ) +{ + CRMArea* area; + CRMInstance* instance; + float spacing; + vec3_t origin; + vec3_t lookat; + int flattenHeight; + vec3_t zerodvec; + + VectorClear(zerodvec); + + // create fences / walls + + // Create the instance using the instance file helper class + instance = mInstanceFile.CreateInstance ( group->GetName ( ) ); + + // Failed to create, not good + if ( NULL == instance ) + { + return false; + } + + // If a spacing radius was specified then override the one thats + // in the instance + spacing = atof( group->FindPairValue ( "spacing", "0" ) ); + if ( spacing ) + { + instance->SetSpacingRadius ( spacing ); + } + + instance->SetFilter(group->FindPairValue("filter", "")); + instance->SetTeamFilter(group->FindPairValue("teamfilter", "")); + + if (strstr(instance->GetTeamFilter(),"red")) + instance->SetSide( SIDE_RED); + else if (strstr(instance->GetTeamFilter(),"blue")) + instance->SetSide( SIDE_BLUE ); + +// ParseWallRect(group, instance->GetSide()); + + // Get its origin now + ParseOrigin ( group->FindSubGroup ( "origin" ), origin, lookat, &flattenHeight ); + origin[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * origin[0]; + origin[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * origin[1]; + origin[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * origin[2]; + + lookat[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * lookat[0]; + lookat[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * lookat[1]; + lookat[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * lookat[2]; + + // Fixed height? (used for bridges) + if ( !atoi(group->FindPairValue ( "nodrop", "0" )) ) + { + origin[2] = mLandScape->GetBounds ( )[1][2] + 100; + } + + // Set the area of position + area = mAreaManager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, zerodvec, lookat, instance->GetFlattenRadius()?true:false, true, instance->GetLockOrigin(), mSymmetric ); + instance->SetArea ( mAreaManager, area ); + instance->SetFlattenHeight ( flattenHeight ); + + mInstances.push_back ( instance ); + + // create defenses? + ParseInstancesOnPath(group ); + + return true; +} + + +/************************************************************************************************ + * CRMMission::ParseInstances + * parses all instances within the mission and populates the instance list + * + * inputs: + * group: parser group containing the list of instances + * + * return: + * true: instances parsed successfully + * false: instances failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseInstances ( CGPGroup* group ) +{ +#ifndef PRE_RELEASE_DEMO + // If NULL that means this particular difficulty level has no instances + if ( NULL == group ) + { + return true; + } + + // Loop through all the instances in the mission and add each + // to the master list of instances + for ( group = group->GetSubGroups(); + group; + group=group->GetNext() ) + { + ParseInstance ( group ); + } +#endif // #ifndef PRE_RELEASE_DEMO + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseObjectives + * parses all objectives within the mission and populates the objective list + * + * inputs: + * group: parser group containing the list of objectives + * + * return: + * true: objectives parsed successfully + * false: objectives failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseObjectives ( CGPGroup* group ) +{ + // If NULL that means this particular difficulty level has no objectives + if ( NULL == group ) + { + return true; + } + + // Loop through all the objectives in the mission and add each + // to the master list of objectives + for ( group = group->GetSubGroups(); + group; + group=group->GetNext() ) + { + CRMObjective* objective; + + // Create the new objective + objective = new CRMObjective ( group ); + + mObjectives.push_back ( objective ); + } + + mValidObjectives = true; + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseAmmo + * parses the given ammo list and sets the necessary ammo cvars to grant those + * weapons to the players + * + * inputs: + * ammos: parser group containing the ammo list + * + * return: + * true: ammo parsed successfully + * false: ammo failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseAmmo ( CGPGroup* ammos ) +{ +/* CGPValue* ammo; + + // No weapons, no success + if ( NULL == ammos ) + { + return false; + } + + if (0 == gi.Cvar_VariableIntegerValue("ar_wpnselect")) + { + // Make sure the ammo cvars are all reset so ammo from the last map or + // another difficulty level wont carry over + CWeaponSystem::ClearAmmoCvars (TheWpnSysHelper()); + + ammo = ammos->GetPairs ( ); + + // Loop through the weapons listed and grant them to the player + while ( ammo ) + { + // Grab the weapons ID + AmmoID id = CWeaponSystem::GetAmmoID ( ammo->GetName ( ) ); + + // Now set the weapon cvar with the given data + TheWpnSysHelper().CvarSet ( CWeaponSystem::GetAmmoCvar ( id ), ammo->GetTopValue ( ), CVAR_AMMO ); + + // Move on to the next weapon + ammo = (CGPValue*)ammo->GetNext(); + } + } +*/ + mValidAmmo = true; + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseWeapons + * parses the given weapon list and sets the necessary weapon cvars to grant those + * weapons to the players + * + * inputs: + * weapons: parser group containing the weapons list + * + * return: + * true: weapons parsed successfully + * false: weapons failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseWeapons ( CGPGroup* weapons ) +{ +/* CGPValue* weapon; + WpnID id; + + // No weapons, no success + if ( NULL == weapons ) + { + return false; + } + + if (0 == gi.Cvar_VariableIntegerValue("ar_wpnselect")) + { + // Make sure the weapon cvars are all reset so weapons from the last map or + // another difficulty level wont carry over + CWeaponSystem::ClearWpnCvars (TheWpnSysHelper()); + + id = NULL_WpnID; + weapon = weapons->GetPairs ( ); + + // Loop through the weapons listed and grant them to the player + while ( weapon ) + { + // Grab the weapons ID + id = CWeaponSystem::GetWpnID ( weapon->GetName ( ) ); + + // Now set the weapon cvar with the given data + TheWpnSysHelper().CvarSet ( CWeaponSystem::GetWpnCvar ( id ), weapon->GetTopValue ( ) ); + + // Move on to the next weapon + weapon = (CGPValue*)weapon->GetNext(); + } + + // If we found at least one weapon then ready the last one in the list + if ( NULL_WpnID != id ) + { + TheWpnSysHelper().CvarSet("wp_righthand", va("%i/%i/0/0",id,CWeaponSystem::GetClipSize ( id )), CVAR_MISC ); + } + } +*/ + mValidWeapons = true; + + return true; +} + +/************************************************************************************************ + * CRMMission::ParseOutfit + * parses the outfit (weapons and ammo) + * + * inputs: + * outfit: parser group containing the outfit + * + * return: + * true: weapons and ammo parsed successfully + * false: failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseOutfit ( CGPGroup* outfit ) +{ + if ( NULL == outfit ) + { + return false; + } + +/* // Its ok to fail parsing weapons as long as weapons have + // already been parsed at some point + if ( !ParseWeapons ( ParseRandom ( outfit->FindSubGroup ( "weapons" ) ) ) ) + { + if ( !mValidWeapons ) + { + return false; + } + } + + // Its ok to fail parsing ammo as long as ammo have + // already been parsed at some point + if ( !ParseAmmo ( ParseRandom ( outfit->FindSubGroup ( "ammo" ) ) ) ) + { + if ( !mValidAmmo) + { + return false; + } + } +*/ + return true; +} + +/************************************************************************************************ + * CRMMission::ParseRandom + * selects a random sub group with from all within this one + * + * inputs: + * random: parser group containing the various subgroups + * + * return: + * true: parsed successfuly + * false: failed to parse + * + ************************************************************************************************/ +CGPGroup* CRMMission::ParseRandom ( CGPGroup* randomGroup ) +{ + if (NULL == randomGroup) + return NULL; + + CGPGroup* group; + CGPGroup* groups[MAX_RANDOM_CHOICES]; + int numGroups; + + // Build a list of the groups one can be chosen + for ( numGroups = 0, group = randomGroup->GetSubGroups ( ); + group; + group = group->GetNext ( ) ) + { + if ( stricmp ( group->GetName ( ), "random_choice" ) ) + { + continue; + } + + int weight = atoi ( group->FindPairValue ( "random_weight", "1" ) ); + while (weight-- > 0) + groups[numGroups++] = group; + assert (numGroups <= MAX_RANDOM_CHOICES); + } + + // No groups! + if ( !numGroups ) + { + return randomGroup; + } + + // Now choose a group to parse + return groups[mLandScape->irand(0,numGroups-1)]; +} + +/************************************************************************************************ + * CRMMission::ParseDifficulty + * parses the given difficulty and populates the mission with its data + * + * inputs: + * difficulty: parser group containing the difficulties info + * + * return: + * true: difficulty parsed successfully + * false: difficulty failed to parse + * + ************************************************************************************************/ +bool CRMMission::ParseDifficulty ( CGPGroup* difficulty, CGPGroup *parent ) +{ + // If a null difficulty then stop the recursion. Make sure to + // return true here so the parsing doesnt fail + if ( NULL == difficulty ) + { + return true; + } + + if (difficulty->GetParent()) + { + parent = difficulty->GetParent(); + } + + // is map supposed to be symmetric? + mSymmetric = (symmetry_t)atoi(parent->FindPairValue ( "symmetric", "0" )); + mBackUpPath = atoi(parent->FindPairValue ( "backuppath", "0" )); + if( mSymmetric ) + {// pick between the 2 starting corners -- yes this is a hack + mSymmetric = SYMMETRY_TOPLEFT; + if( TheRandomMissionManager->GetLandScape()->irand(0, 1) ) + { + mSymmetric = SYMMETRY_BOTTOMRIGHT; + } + } + + mDefaultPadding = atoi(parent->FindPairValue ( "padding", "0" )); + + // Parse the nodes + if ( !ParseNodes ( ParseRandom ( difficulty->FindSubGroup ( "nodes" ) ) ) ) + { + return false; + } + + // Parse the paths + if ( !ParsePaths ( ParseRandom ( difficulty->FindSubGroup ( "paths" ) ) ) ) + { + return false; + } + + // Parse the rivers + if ( !ParseRivers ( ParseRandom ( difficulty->FindSubGroup ( "rivers" ) ) ) ) + { + return false; + } + + // Handle inherited properties + if ( !ParseDifficulty ( parent->FindSubGroup ( difficulty->FindPairValue ( "inherit", "" ) ), parent ) ) + { + return false; + } + + // parse the player's outfit (weapons and ammo) + if ( !ParseOutfit( ParseRandom ( difficulty->FindSubGroup ( "outfit" ) ) ) ) + { + // Its ok to fail parsing weapons as long as weapons have + // already been parsed at some point + if ( !ParseWeapons ( ParseRandom ( difficulty->FindSubGroup ( "weapons" ) ) ) ) + { + if ( !mValidWeapons ) + { + return false; + } + } + + // Its ok to fail parsing ammo as long as ammo have + // already been parsed at some point + if ( !ParseAmmo ( ParseRandom ( difficulty->FindSubGroup ( "ammo" ) ) ) ) + { + if ( !mValidAmmo) + { + return false; + } + } + } + + // Its ok to fail parsing objectives as long as objectives have + // already been parsed at some point + if ( !ParseObjectives ( ParseRandom ( difficulty->FindSubGroup ( "objectives" ) ) ) ) + { + if ( !mValidObjectives ) + { + return false; + } + } + + // Set the cvars with the available values + Cvar_Set ( "mi_health", difficulty->FindPairValue ( "health", "100" ) ); + Cvar_Set ( "mi_armor", difficulty->FindPairValue ( "armor", "0" ) ); + + // Parse out the timelimit + mTimeLimit = atol(difficulty->FindPairValue("timelimit", "0")); + + // NPC multipliers + mAccuracyMultiplier = atof(difficulty->FindPairValue("npcaccuracy", "1")); + mHealthMultiplier = atof(difficulty->FindPairValue("npchealth", "1")); + + // keep only some of RMG pickups 1 = 100% + mPickupHealth = atof(difficulty->FindPairValue("pickup_health", "1")); + mPickupArmor = atof(difficulty->FindPairValue("pickup_armor", "1")); + mPickupAmmo = atof(difficulty->FindPairValue("pickup_ammo", "1")); + mPickupWeapon = atof(difficulty->FindPairValue("pickup_weapon", "1")); + mPickupEquipment = atof(difficulty->FindPairValue("pickup_equipment", "1")); + + // Its ok to fail parsing instances as long as instances have + // already been parsed at some point + if ( !ParseInstances ( ParseRandom ( difficulty->FindSubGroup ( "instances" ) ) ) ) + { + if ( !mValidInstances ) + { + return false; + } + } + + return true; +} + +/************************************************************************************************ + * CRMMission::Load + * Loads the given mission using the given difficulty level + * + * inputs: + * name: Name of the mission to load (should only be the name rather than the full path) + * difficulty: difficulty level to load + * + * return: + * true: mission successfully loaded + * false: mission failed to load + * + ************************************************************************************************/ +bool CRMMission::Load ( const char* mission, const char* instances, const char* difficulty ) +{ + CGenericParser2 parser; + CGPGroup* root; + + // Create the parser for the mission file + if(!Com_ParseTextFile(va("ext_data/rmg/%s.mission", mission), parser)) + { + if(!Com_ParseTextFile(va("ext_data/arioche/%s.mission", mission), parser)) + { + Com_Printf("ERROR: Failed to open mission file '%s'\n", mission); + return false; + } + } + + // Grab the root parser groop and make sure its mission, otherwise this + // isnt a valid mission file + root = parser.GetBaseParseGroup()->GetSubGroups(); + if(stricmp(root->GetName(), "mission")) + { + Com_Printf("ERROR: '%s' is not a valid mission file\n", mission ); + parser.Clean(); + return false; + } + + // Grab the mission description and set the cvar for it + mDescription = root->FindPairValue ( "description", "" ); +// Cvar_Set("ar_obj_main0",mDescription.c_str(), CVAR_OBJECTIVE); +// Cvar_Set("ar_obj_maincom0", "&OBJECTIVES_INPROGRESS&", CVAR_OBJECTIVE); +// Cvar_SetValue ("ar_cur_objective", 0, CVAR_OBJECTIVE); + + string mInfo = root->FindPairValue ( "info", "" ); +// Cvar_Set("ar_obj_info0",mInfo.c_str(), CVAR_OBJECTIVE); + + mExitScreen = root->FindPairValue ( "exitScreen", "" ); + mTimeExpiredScreen = root->FindPairValue ( "TimeExpiredScreen", "