Initial commit.
This commit is contained in:
774
code/0_compiled_first/0_SH_Leak.cpp
Normal file
774
code/0_compiled_first/0_SH_Leak.cpp
Normal file
@@ -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 <windows.h>
|
||||
|
||||
#include "..\smartheap\smrtheap.h"
|
||||
#include "../game/q_shared.h"
|
||||
#include "..\qcommon\qcommon.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
|
||||
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<const char *,int,CMyStrComparator> 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<const char *,int,CMyStrComparator>::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;i<nStack;i++)
|
||||
{
|
||||
if (!strcmpi(start,StackNames[i]))
|
||||
break;
|
||||
}
|
||||
if (i<nStack)
|
||||
{
|
||||
StackSize[i]+=info->argSize;
|
||||
StackCount[i]++;
|
||||
StackCache[StackCacheAt]=i;
|
||||
StackCacheAt++;
|
||||
if (StackCacheAt>=48)
|
||||
StackCacheAt=0;
|
||||
}
|
||||
else if (i<maxStack)
|
||||
{
|
||||
strcpy(StackNames[i],start);
|
||||
StackSize[i]=info->argSize;
|
||||
StackCount[i]=1;
|
||||
nStack++;
|
||||
}
|
||||
else if (nStack<maxStack)
|
||||
{
|
||||
nStack++;
|
||||
strcpy(StackNames[maxStack-1],"*****OTHER*****");
|
||||
StackSize[maxStack-1]=info->argSize;
|
||||
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<const char *,int,CMyStrComparator>::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;i<nStack;i++)
|
||||
{
|
||||
if (!strcmpi(start,StackNames[i]))
|
||||
break;
|
||||
}
|
||||
if (i<nStack)
|
||||
{
|
||||
StackSize[i]+=info->argSize;
|
||||
StackCount[i]++;
|
||||
StackCache[StackCacheAt]=i;
|
||||
StackCacheAt++;
|
||||
if (StackCacheAt>=48)
|
||||
StackCacheAt=0;
|
||||
}
|
||||
else if (i<maxStack)
|
||||
{
|
||||
strcpy(StackNames[i],start);
|
||||
StackSize[i]=info->argSize;
|
||||
StackCount[i]=1;
|
||||
nStack++;
|
||||
}
|
||||
else if (nStack<maxStack)
|
||||
{
|
||||
nStack++;
|
||||
strcpy(StackNames[maxStack-1],"*****OTHER*****");
|
||||
StackSize[maxStack-1]=info->argSize;
|
||||
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<int> 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<int,pair<int,char *> > sortit;
|
||||
multimap<int,pair<int,char *> >::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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackSize[i],pair<int,char *>(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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(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<nStack;i++)
|
||||
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(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<int,int> sorted;
|
||||
for (i=0;i<1000;i++)
|
||||
{
|
||||
if (CheckpointCount[i])
|
||||
{
|
||||
sorted.insert(pair<int,int>(-CheckpointSize[i],i));
|
||||
}
|
||||
}
|
||||
multimap<int,int>::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<int,int>(-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 <frequency>\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
|
||||
BIN
code/ALut.lib
Normal file
BIN
code/ALut.lib
Normal file
Binary file not shown.
BIN
code/EaxMan.dll
Normal file
BIN
code/EaxMan.dll
Normal file
Binary file not shown.
BIN
code/IFC22.dll
Normal file
BIN
code/IFC22.dll
Normal file
Binary file not shown.
BIN
code/JediAcademy.ncb
Normal file
BIN
code/JediAcademy.ncb
Normal file
Binary file not shown.
86
code/JediAcademy.sln
Normal file
86
code/JediAcademy.sln
Normal file
@@ -0,0 +1,86 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_exe", "x_exe\x_exe.vcproj", "{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA} = {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB} = {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "goblib", "goblib\goblib.vcproj", "{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_game", "x_game\x_game.vcproj", "{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
DemoDebug = DemoDebug
|
||||
DemoFinal = DemoFinal
|
||||
DemoRelease = DemoRelease
|
||||
FinalBuild = FinalBuild
|
||||
Release = Release
|
||||
SHDebug = SHDebug
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.ActiveCfg = Debug|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.Build.0 = Debug|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoDebug.ActiveCfg = DemoDebug|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoDebug.Build.0 = DemoDebug|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoFinal.ActiveCfg = DemoFinal|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoFinal.Build.0 = DemoFinal|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoRelease.ActiveCfg = DemoRelease|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoRelease.Build.0 = DemoRelease|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.FinalBuild.ActiveCfg = FinalBuild|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.FinalBuild.Build.0 = FinalBuild|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Release.ActiveCfg = Release|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Release.Build.0 = Release|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.SHDebug.ActiveCfg = Debug|Xenon
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.SHDebug.Build.0 = Debug|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Debug.ActiveCfg = Debug|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Debug.Build.0 = Debug|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoDebug.ActiveCfg = DemoDebug|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoDebug.Build.0 = DemoDebug|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoFinal.ActiveCfg = DemoFinal|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoFinal.Build.0 = DemoFinal|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoRelease.ActiveCfg = DemoRelease|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoRelease.Build.0 = DemoRelease|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.FinalBuild.ActiveCfg = FinalBuild|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.FinalBuild.Build.0 = FinalBuild|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Release.ActiveCfg = Release|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Release.Build.0 = Release|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.SHDebug.ActiveCfg = Debug|Xenon
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.SHDebug.Build.0 = Debug|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.ActiveCfg = Debug|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.Build.0 = Debug|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoDebug.ActiveCfg = DemoDebug|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoDebug.Build.0 = DemoDebug|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoFinal.ActiveCfg = DemoFinal|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoFinal.Build.0 = DemoFinal|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoRelease.ActiveCfg = DemoRelease|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoRelease.Build.0 = DemoRelease|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.FinalBuild.ActiveCfg = FinalBuild|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.FinalBuild.Build.0 = FinalBuild|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Release.ActiveCfg = Release|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Release.Build.0 = Release|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.SHDebug.ActiveCfg = Debug|Xenon
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.SHDebug.Build.0 = Debug|Xenon
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionItems) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(DevPartner) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(DevPartner) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
76
code/JediAcademy.sln.old
Normal file
76
code/JediAcademy.sln.old
Normal file
@@ -0,0 +1,76 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||
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
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_game", "x_game\x_game.vcproj", "{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
ConfigName.0 = Debug
|
||||
ConfigName.1 = DemoDebug
|
||||
ConfigName.2 = DemoFinal
|
||||
ConfigName.3 = DemoRelease
|
||||
ConfigName.4 = FinalBuild
|
||||
ConfigName.5 = Release
|
||||
ConfigName.6 = SHDebug
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectDependencies) = postSolution
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.0 = {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.1 = {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.ActiveCfg = Debug|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.Build.0 = Debug|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoDebug.ActiveCfg = DemoDebug|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoDebug.Build.0 = DemoDebug|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoFinal.ActiveCfg = DemoFinal|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoFinal.Build.0 = DemoFinal|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoRelease.ActiveCfg = DemoRelease|Xbox
|
||||
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.DemoRelease.Build.0 = DemoRelease|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}.DemoDebug.ActiveCfg = DemoDebug|Xbox
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoDebug.Build.0 = DemoDebug|Xbox
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoFinal.ActiveCfg = DemoFinal|Xbox
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoFinal.Build.0 = DemoFinal|Xbox
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoRelease.ActiveCfg = DemoRelease|Xbox
|
||||
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.DemoRelease.Build.0 = DemoRelease|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
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.ActiveCfg = Debug|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.Build.0 = Debug|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoDebug.ActiveCfg = DemoDebug|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoDebug.Build.0 = DemoDebug|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoFinal.ActiveCfg = DemoFinal|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoFinal.Build.0 = DemoFinal|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoRelease.ActiveCfg = DemoRelease|Xbox
|
||||
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.DemoRelease.Build.0 = DemoRelease|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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionItems) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(DevPartner) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(DevPartner) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
BIN
code/JediAcademy.suo
Normal file
BIN
code/JediAcademy.suo
Normal file
Binary file not shown.
BIN
code/OpenAL32.dll
Normal file
BIN
code/OpenAL32.dll
Normal file
Binary file not shown.
BIN
code/OpenAL32.lib
Normal file
BIN
code/OpenAL32.lib
Normal file
Binary file not shown.
480
code/RMG/RM_Area.cpp
Normal file
480
code/RMG/RM_Area.cpp
Normal file
@@ -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
|
||||
99
code/RMG/RM_Area.h
Normal file
99
code/RMG/RM_Area.h
Normal file
@@ -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<CRMArea*> 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
|
||||
|
||||
71
code/RMG/RM_Headers.h
Normal file
71
code/RMG/RM_Headers.h
Normal file
@@ -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 <vector>
|
||||
#include <list>
|
||||
#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
|
||||
191
code/RMG/RM_Instance.cpp
Normal file
191
code/RMG/RM_Instance.cpp
Normal file
@@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
122
code/RMG/RM_Instance.h
Normal file
122
code/RMG/RM_Instance.h
Normal file
@@ -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<CRMInstance*>::iterator rmInstanceIter_t;
|
||||
typedef list<CRMInstance*> rmInstanceList_t;
|
||||
|
||||
#endif
|
||||
200
code/RMG/RM_InstanceFile.cpp
Normal file
200
code/RMG/RM_InstanceFile.cpp
Normal file
@@ -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;
|
||||
}
|
||||
28
code/RMG/RM_InstanceFile.h
Normal file
28
code/RMG/RM_InstanceFile.h
Normal file
@@ -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
|
||||
294
code/RMG/RM_Instance_BSP.cpp
Normal file
294
code/RMG/RM_Instance_BSP.cpp
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
35
code/RMG/RM_Instance_BSP.h
Normal file
35
code/RMG/RM_Instance_BSP.h
Normal file
@@ -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
|
||||
343
code/RMG/RM_Instance_Group.cpp
Normal file
343
code/RMG/RM_Instance_Group.cpp
Normal file
@@ -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 );
|
||||
}
|
||||
}
|
||||
41
code/RMG/RM_Instance_Group.h
Normal file
41
code/RMG/RM_Instance_Group.h
Normal file
@@ -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
|
||||
187
code/RMG/RM_Instance_Random.cpp
Normal file
187
code/RMG/RM_Instance_Random.cpp
Normal file
@@ -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 );
|
||||
}
|
||||
40
code/RMG/RM_Instance_Random.h
Normal file
40
code/RMG/RM_Instance_Random.h
Normal file
@@ -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
|
||||
53
code/RMG/RM_Instance_Void.cpp
Normal file
53
code/RMG/RM_Instance_Void.cpp
Normal file
@@ -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 );
|
||||
}
|
||||
18
code/RMG/RM_Instance_Void.h
Normal file
18
code/RMG/RM_Instance_Void.h
Normal file
@@ -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
|
||||
402
code/RMG/RM_Manager.cpp
Normal file
402
code/RMG/RM_Manager.cpp
Normal file
@@ -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)
|
||||
* <Description> *
|
||||
* Input *
|
||||
* <Variable>: <Description> *
|
||||
* Output / Return *
|
||||
* <Variable>: <Description> *
|
||||
************************************************************************************************/
|
||||
void CRMManager::CompleteMission(void)
|
||||
{
|
||||
UpdateStatisticCvars ( );
|
||||
|
||||
mMission->CompleteMission();
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::FailedMission
|
||||
* Does end-of-mission stuff (pause game, end screen, return to menu)
|
||||
* <Description> *
|
||||
* Input *
|
||||
* TimeExpired: indicates if the reason failed was because of time
|
||||
* Output / Return *
|
||||
* <Variable>: <Description> *
|
||||
************************************************************************************************/
|
||||
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;
|
||||
}
|
||||
55
code/RMG/RM_Manager.h
Normal file
55
code/RMG/RM_Manager.h
Normal file
@@ -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
|
||||
1930
code/RMG/RM_Mission.cpp
Normal file
1930
code/RMG/RM_Mission.cpp
Normal file
File diff suppressed because it is too large
Load Diff
129
code/RMG/RM_Mission.h
Normal file
129
code/RMG/RM_Mission.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
#if !defined(RM_MISSION_H_INC)
|
||||
#define RM_MISSION_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Mission.h")
|
||||
#endif
|
||||
|
||||
// maximum random choices
|
||||
#define MAX_RANDOM_CHOICES 100
|
||||
|
||||
typedef vector<int> rmIntVector_t;
|
||||
|
||||
|
||||
class CRMMission
|
||||
{
|
||||
private:
|
||||
|
||||
rmObjectiveList_t mObjectives;
|
||||
rmInstanceList_t mInstances;
|
||||
|
||||
CRMInstanceFile mInstanceFile;
|
||||
CRMObjective* mCurrentObjective;
|
||||
|
||||
bool mValidNodes;
|
||||
bool mValidPaths;
|
||||
bool mValidRivers;
|
||||
bool mValidWeapons;
|
||||
bool mValidAmmo;
|
||||
bool mValidObjectives;
|
||||
bool mValidInstances;
|
||||
|
||||
int mTimeLimit;
|
||||
int mMaxInstancePosition;
|
||||
|
||||
// npc multipliers
|
||||
float mAccuracyMultiplier;
|
||||
float mHealthMultiplier;
|
||||
|
||||
// % chance that RMG pickup is actually spawned
|
||||
float mPickupHealth;
|
||||
float mPickupArmor;
|
||||
float mPickupAmmo;
|
||||
float mPickupWeapon;
|
||||
float mPickupEquipment;
|
||||
|
||||
string mDescription;
|
||||
string mExitScreen;
|
||||
string mTimeExpiredScreen;
|
||||
|
||||
// symmetric landscape style
|
||||
symmetry_t mSymmetric;
|
||||
|
||||
// if set to 1 in the mission file, adds an extra connecting path in symmetric maps
|
||||
// to ensure both sides actually do connect
|
||||
int mBackUpPath;
|
||||
|
||||
int mDefaultPadding;
|
||||
|
||||
CRMAreaManager* mAreaManager;
|
||||
|
||||
CRMPathManager* mPathManager;
|
||||
|
||||
CRandomTerrain* mLandScape;
|
||||
|
||||
public:
|
||||
|
||||
CRMMission ( CRandomTerrain* );
|
||||
~CRMMission ( );
|
||||
|
||||
bool Load ( const char* name, const char* instances, const char* difficulty );
|
||||
bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
|
||||
void Preview ( const vec3_t from );
|
||||
|
||||
CRMObjective* FindObjective ( const char* name );
|
||||
CRMObjective* GetCurrentObjective ( ) { return mCurrentObjective; }
|
||||
|
||||
void CompleteMission (void);
|
||||
void FailedMission (bool TimeExpired);
|
||||
void CompleteObjective ( CRMObjective* ojective );
|
||||
|
||||
int GetTimeLimit (void) { return mTimeLimit; }
|
||||
int GetMaxInstancePosition (void) { return mMaxInstancePosition; }
|
||||
const char* GetDescription (void) { return mDescription.c_str(); }
|
||||
const char* GetExitScreen (void) { return mExitScreen.c_str(); }
|
||||
int GetSymmetric (void) { return mSymmetric; }
|
||||
int GetBackUpPath (void) { return mBackUpPath; }
|
||||
int GetDefaultPadding (void) { return mDefaultPadding; }
|
||||
|
||||
// void CreateMap ( void );
|
||||
|
||||
bool DenyPickupHealth () {return mLandScape->flrand(0.0f,1.0f) > mPickupHealth;}
|
||||
bool DenyPickupArmor () {return mLandScape->flrand(0.0f,1.0f) > mPickupArmor;}
|
||||
bool DenyPickupAmmo () {return mLandScape->flrand(0.0f,1.0f) > mPickupAmmo;}
|
||||
bool DenyPickupWeapon () {return mLandScape->flrand(0.0f,1.0f) > mPickupWeapon;}
|
||||
bool DenyPickupEquipment () {return mLandScape->flrand(0.0f,1.0f) > mPickupEquipment;}
|
||||
|
||||
private:
|
||||
|
||||
// void PurgeUnlinkedTriggers ( );
|
||||
// void PurgeTrigger ( CEntity* trigger );
|
||||
|
||||
void MirrorPos (vec3_t pos);
|
||||
CGPGroup* ParseRandom ( CGPGroup* random );
|
||||
bool ParseOrigin ( CGPGroup* originGroup, vec3_t origin, vec3_t lookat, int* flattenHeight );
|
||||
bool ParseNodes ( CGPGroup* group );
|
||||
bool ParsePaths ( CGPGroup *paths);
|
||||
bool ParseRivers ( CGPGroup *rivers);
|
||||
void PlaceBridges ();
|
||||
void PlaceWallInstance(CRMInstance* instance, float xpos, float ypos, float zpos, int x, int y, float angle);
|
||||
|
||||
|
||||
bool ParseDifficulty ( CGPGroup* difficulty, CGPGroup *parent );
|
||||
bool ParseWeapons ( CGPGroup* weapons );
|
||||
bool ParseAmmo ( CGPGroup* ammo );
|
||||
bool ParseOutfit ( CGPGroup* outfit );
|
||||
bool ParseObjectives ( CGPGroup* objectives );
|
||||
bool ParseInstance ( CGPGroup* instance );
|
||||
bool ParseInstances ( CGPGroup* instances );
|
||||
bool ParseInstancesOnPath ( CGPGroup* group );
|
||||
bool ParseWallRect ( CGPGroup* group, int side);
|
||||
|
||||
// void SpawnNPCTriggers ( CCMLandScape* landscape );
|
||||
// void AttachNPCTriggers ( CCMLandScape* landscape );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
134
code/RMG/RM_Objective.cpp
Normal file
134
code/RMG/RM_Objective.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Objective.cpp
|
||||
*
|
||||
* Implements the CRMObjective class. This class is reponsible for parsing an objective
|
||||
* from the mission file as well as linking the objective into the world.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMObjective::CRMObjective
|
||||
* Constructs a random mission objective and fills in the default properties
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMObjective::CRMObjective ( CGPGroup* group )
|
||||
{
|
||||
SetPriority(atoi(group->FindPairValue("priority", "0")));
|
||||
SetMessage( group->FindPairValue("message",va("Objective %i Completed", GetPriority()) ) );
|
||||
SetDescription(group->FindPairValue("description",va("Objective %i", GetPriority()) ) );
|
||||
SetInfo(group->FindPairValue("info",va("Info %i", GetPriority()) ) );
|
||||
SetTrigger(group->FindPairValue("trigger",""));
|
||||
SetName(group->GetName());
|
||||
|
||||
/* const char * soundPath = group->FindPairValue("completed_sound", "" );
|
||||
if (soundPath)
|
||||
mCompleteSoundID = G_SoundIndex(soundPath);
|
||||
*/
|
||||
|
||||
mCompleted = false;
|
||||
mOrderIndex = -1;
|
||||
|
||||
// If no priority was specified for this objective then its active by default.
|
||||
if ( GetPriority ( ) )
|
||||
{
|
||||
mActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMObjective::FindRandomTrigger
|
||||
* Searches the entitySystem form a random arioche trigger that matches the objective name
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* trigger: a random trigger or NULL if one couldnt be found
|
||||
*
|
||||
************************************************************************************************/
|
||||
/*CTriggerAriocheObjective* CRMObjective::FindRandomTrigger ( )
|
||||
{
|
||||
CEntity* search;
|
||||
CEntity* triggers[20];
|
||||
int numTriggers;
|
||||
|
||||
// Start off the first trigger
|
||||
numTriggers = 0;
|
||||
search = entitySystem->GetEntityFromClassname ( NULL, "trigger_arioche_objective" );
|
||||
|
||||
// Make a list of triggers
|
||||
while ( numTriggers < 20 && search )
|
||||
{
|
||||
CTriggerAriocheObjective* trigger = (CTriggerAriocheObjective*) search;
|
||||
|
||||
// Move on to the next trigger
|
||||
search = entitySystem->GetEntityFromClassname ( search, "trigger_arioche_objective" );
|
||||
|
||||
// See if this trigger is already in use
|
||||
if ( trigger->GetObjective ( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the objective names dont match then ignore this trigger
|
||||
if ( stricmp ( trigger->GetObjectiveName ( ), GetTrigger() ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the trigger to the list
|
||||
triggers[numTriggers++] = trigger;
|
||||
}
|
||||
|
||||
// If no matching triggers then just return NULL
|
||||
if ( 0 == numTriggers )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return a random choice from the trigger list
|
||||
return (CTriggerAriocheObjective*)triggers[TheRandomMissionManager->GetLandScape()->irand(0,numTriggers-1)];
|
||||
}
|
||||
*/
|
||||
/************************************************************************************************
|
||||
* CRMObjective::Link
|
||||
* Links the objective into the world using the current state of the world to determine
|
||||
* where it should link
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* true: objective successfully linked
|
||||
* false: objective failed to link
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMObjective::Link ( )
|
||||
{
|
||||
/* CTriggerAriocheObjective* trigger;
|
||||
|
||||
// Look for a random trigger to associate this objective to.
|
||||
trigger = FindRandomTrigger ( );
|
||||
if ( NULL != trigger )
|
||||
{
|
||||
trigger->SetObjective ( this );
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
65
code/RMG/RM_Objective.h
Normal file
65
code/RMG/RM_Objective.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#if !defined(RM_OBJECTIVE_H_INC)
|
||||
#define RM_OBJECTIVE_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Objective.h")
|
||||
#endif
|
||||
|
||||
class CRMObjective
|
||||
{
|
||||
protected:
|
||||
|
||||
bool mCompleted; // Is objective completed?
|
||||
bool mActive; // set to false if the objective requires another objective to be met first
|
||||
int mPriority; // sequence in which objectives need to be completed
|
||||
int mOrderIndex; // objective index in ui
|
||||
int mCompleteSoundID; // sound for when objective is finished
|
||||
string mMessage; // message outputed when objective is completed
|
||||
string mDescription; // description of objective
|
||||
string mInfo; // more info for objective
|
||||
string mName; // name of objective
|
||||
string mTrigger; // trigger associated with objective
|
||||
|
||||
public:
|
||||
|
||||
CRMObjective(CGPGroup *group);
|
||||
~CRMObjective(void) {}
|
||||
|
||||
bool Link (void);
|
||||
|
||||
bool IsCompleted (void) const { return mCompleted; }
|
||||
bool IsActive (void) const { return mActive; }
|
||||
|
||||
void Activate (void) { mActive = true; }
|
||||
void Complete (bool comp) { mCompleted = comp;}
|
||||
|
||||
// Get methods
|
||||
int GetPriority(void){return mPriority;}
|
||||
int GetOrderIndex(void) { return mOrderIndex; }
|
||||
const char* GetMessage(void) { return mMessage.c_str(); }
|
||||
const char* GetDescription(void) { return mDescription.c_str(); }
|
||||
const char* GetInfo(void) { return mInfo.c_str(); }
|
||||
const char* GetName(void) { return mName.c_str(); }
|
||||
const char* GetTrigger(void) { return mTrigger.c_str(); }
|
||||
int CompleteSoundID() { return mCompleteSoundID; };
|
||||
|
||||
// Set methods
|
||||
void SetPriority(int priority){mPriority = priority;}
|
||||
void SetOrderIndex(int order) { mOrderIndex = order; }
|
||||
void SetMessage(const char* msg) { mMessage = msg; }
|
||||
void SetDescription(const char* desc) { mDescription = desc; }
|
||||
void SetInfo(const char* info) { mInfo = info; }
|
||||
void SetName(const char* name) { mName = name; }
|
||||
void SetTrigger(const char* name) { mTrigger = name; }
|
||||
|
||||
private:
|
||||
|
||||
// CTriggerAriocheObjective* FindRandomTrigger ( );
|
||||
};
|
||||
|
||||
typedef list<CRMObjective *>::iterator rmObjectiveIter_t;
|
||||
typedef list<CRMObjective *> rmObjectiveList_t;
|
||||
|
||||
|
||||
#endif
|
||||
721
code/RMG/RM_Path.cpp
Normal file
721
code/RMG/RM_Path.cpp
Normal file
@@ -0,0 +1,721 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* Copyright (C) 2001-2002 Raven Software
|
||||
*
|
||||
* RM_Path.cpp
|
||||
*
|
||||
************************************************************************************************/
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMNode::CRMNode
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMNode::CRMNode ( )
|
||||
{
|
||||
int i;
|
||||
|
||||
mFlattenHeight = -1;
|
||||
|
||||
mPos[0] = 0;
|
||||
mPos[1] = 0;
|
||||
mPos[2] = 0;
|
||||
|
||||
// no paths
|
||||
for (i = 0; i < DIR_MAX; i++)
|
||||
mPathID[i] = -1;
|
||||
|
||||
mAreaPointPlaced = false;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::CRMPathManager
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMPathManager::CRMPathManager ( CRandomTerrain* terrain )
|
||||
: mXNodes(0), mYNodes(0), mPathCount(0), mRiverCount(0), mMaxDepth(0), mDepth(0),
|
||||
mPathPoints(10), mPathMinWidth(0.02f), mPathMaxWidth(0.04f), mPathDepth(0.3f), mPathDeviation(0.03f), mPathBreadth(5),
|
||||
mRiverDepth(5), mRiverPoints(10), mRiverMinWidth(0.01f), mRiverMaxWidth(0.02f), mRiverBedDepth(1), mRiverDeviation(0.01f), mRiverBreadth(7),
|
||||
mTerrain(terrain), mCrossed(false)
|
||||
{
|
||||
}
|
||||
|
||||
CRMPathManager::~CRMPathManager ( )
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for ( i = mLocations.size() - 1; i >=0; i-- )
|
||||
{
|
||||
if (mLocations[i])
|
||||
delete mLocations[i];
|
||||
}
|
||||
mLocations.clear();
|
||||
|
||||
for ( j = mNodes.size() - 1; j >=0; j-- )
|
||||
{
|
||||
if (mNodes[j])
|
||||
delete mNodes[j];
|
||||
}
|
||||
mNodes.clear();
|
||||
}
|
||||
|
||||
void CRMPathManager::CreateLocation ( const char* name, const int min_depth, int max_depth, const int min_paths, int max_paths )
|
||||
{
|
||||
int i;
|
||||
|
||||
// sanity checks -- dmv
|
||||
if( max_paths < min_paths )
|
||||
{
|
||||
Com_Printf("[CreateLocation()] ERROR : max_paths < min_paths :: set max_paths = min_paths\n" );
|
||||
max_paths = min_paths;
|
||||
}
|
||||
if( max_depth < min_depth )
|
||||
{
|
||||
Com_Printf("[CreateLocation()] ERROR : max_depth < min_depth :: set max_depth = min_depth\n" );
|
||||
max_depth = min_depth;
|
||||
}
|
||||
|
||||
for (i = mLocations.size()-1; i>=0; --i)
|
||||
if ( !stricmp ( name, mLocations[i]->GetName ( ) ) )
|
||||
{
|
||||
mLocations[i]->SetMinDepth(min_depth);
|
||||
mLocations[i]->SetMaxDepth(max_depth);
|
||||
mLocations[i]->SetMinPaths(min_paths);
|
||||
mLocations[i]->SetMaxPaths(max_paths);
|
||||
return;
|
||||
}
|
||||
|
||||
CRMLoc* pLoc= new CRMLoc(name, min_depth, max_depth, min_paths, max_paths);
|
||||
mLocations.push_back(pLoc);
|
||||
mMaxDepth = max(mMaxDepth, max_depth);
|
||||
}
|
||||
|
||||
void CRMPathManager::ClearCells(int x_nodes, int y_nodes)
|
||||
{
|
||||
int x,y;
|
||||
|
||||
// clear cell array - used for generating paths
|
||||
CRMCell empty;
|
||||
for (x=0; x < x_nodes * y_nodes; x++)
|
||||
{
|
||||
if (x >= mCells.size())
|
||||
mCells.push_back(empty);
|
||||
else
|
||||
mCells[x] = empty;
|
||||
}
|
||||
|
||||
// set borders of world
|
||||
for (y = 0; y < y_nodes; y++)
|
||||
{
|
||||
mCells[y * x_nodes].SetBorder(DIR_W );
|
||||
mCells[y * x_nodes].SetBorder(DIR_SW );
|
||||
mCells[y * x_nodes].SetBorder(DIR_NW );
|
||||
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_E );
|
||||
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_NE );
|
||||
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_SE );
|
||||
}
|
||||
|
||||
for (x = 0; x < x_nodes; x++)
|
||||
{
|
||||
mCells[x].SetBorder( DIR_N );
|
||||
mCells[x].SetBorder( DIR_NE );
|
||||
mCells[x].SetBorder( DIR_NW );
|
||||
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_S );
|
||||
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_SE );
|
||||
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_SW );
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::CreateArray
|
||||
* Create array of nodes that are spaced over the landscape.
|
||||
* Create array of cells, which is used to determine how nodes are connected.
|
||||
*
|
||||
* inputs:
|
||||
* x_nodes, y_nodes - how many nodes in each dimension to layout
|
||||
*
|
||||
* return:
|
||||
* true if the node array was created, false if we have a problem
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMPathManager::CreateArray(const int x_nodes, const int y_nodes)
|
||||
{
|
||||
mXNodes = x_nodes;
|
||||
mYNodes = y_nodes;
|
||||
|
||||
// fill node array with positions that are spaced over the landscape
|
||||
int x,y;
|
||||
|
||||
// dump existing nodes
|
||||
for ( x = mNodes.size() - 1; x >=0; x-- )
|
||||
{
|
||||
if (mNodes[x])
|
||||
delete mNodes[x];
|
||||
}
|
||||
mNodes.clear();
|
||||
mNodes.resize(mXNodes * mYNodes, NULL);
|
||||
|
||||
// add a small amount of random jitter to spots chosen
|
||||
float x_rnd = 0.2f / (mXNodes+1);
|
||||
float y_rnd = 0.2f / (mYNodes+1);
|
||||
|
||||
for (x = 0; x < mXNodes; x++)
|
||||
{
|
||||
float cell_x = (x + 1.0f) / (mXNodes+1);
|
||||
// float cell_x = (x + 2.0f) / (mXNodes+3);
|
||||
|
||||
for (y = 0; y < mYNodes; y++)
|
||||
{
|
||||
vec3_t pos;
|
||||
CRMNode * pnode = new CRMNode();
|
||||
mNodes[x + y*mXNodes] = pnode;
|
||||
|
||||
float cell_y = (y + 1.0f) / (mYNodes+1);
|
||||
// float cell_y = (y + 2.0f) / (mYNodes+3);
|
||||
|
||||
pos[0] = TheRandomMissionManager->GetLandScape()->flrand(cell_x - x_rnd, cell_x + x_rnd);
|
||||
pos[1] = TheRandomMissionManager->GetLandScape()->flrand(cell_y - y_rnd, cell_y + y_rnd);
|
||||
pos[2] = 0;
|
||||
|
||||
SetNodePos(x, y, pos);
|
||||
}
|
||||
}
|
||||
|
||||
ClearCells(mXNodes, mYNodes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// neighbor offsets - easy way to turn a direction into the array position for a neighboring cell or node
|
||||
int CRMPathManager::neighbor_x[DIR_MAX] = { 0, 1, 1, 1, 0,-1,-1,-1};
|
||||
int CRMPathManager::neighbor_y[DIR_MAX] = {-1,-1, 0, 1, 1, 1, 0,-1};
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::PlaceLocation
|
||||
* This method is used to determine if a named location should be placed at this node.
|
||||
*
|
||||
* inputs:
|
||||
* c_x, c_y - cell to examine
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::PlaceLocation(const int c_x, const int c_y)
|
||||
{
|
||||
if ( !Node(c_x,c_y)->IsLocation() )
|
||||
{ // not currently a location
|
||||
|
||||
// how many paths lead to this cell?
|
||||
int count_paths = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i<DIR_MAX; i++)
|
||||
if (Node(c_x,c_y)->PathExist(i))
|
||||
count_paths++;
|
||||
|
||||
int deepest_depth = -1;
|
||||
int deepest_loc = -1;
|
||||
for (i = mLocations.size()-1; i>=0; --i)
|
||||
{
|
||||
if (!mLocations[i]->Placed() && // node has not been placed
|
||||
mLocations[i]->MinDepth() <= mDepth && // our current depth is in the proper range
|
||||
mLocations[i]->MaxDepth() >= mDepth &&
|
||||
mLocations[i]->MinPaths() <= count_paths && // our path count is in the proper range
|
||||
mLocations[i]->MaxPaths() >= count_paths &&
|
||||
mLocations[i]->MaxDepth() > deepest_depth) // and this is the deepest location of the ones that match
|
||||
{
|
||||
deepest_loc = i;
|
||||
deepest_depth = mLocations[i]->MaxDepth();
|
||||
}
|
||||
}
|
||||
|
||||
if (deepest_loc >= 0 && deepest_loc < mLocations.size())
|
||||
{ // found a location to place at this node / cell
|
||||
const char * name = mLocations[deepest_loc]->GetName();
|
||||
Node(c_x,c_y)->SetName(name);
|
||||
mLocations[deepest_loc]->SetPlaced(true);
|
||||
|
||||
// need a new max depth
|
||||
int max_depth = -1;
|
||||
for (i = mLocations.size()-1; i>=0; --i)
|
||||
{
|
||||
// figure out new max depth based on the max depth of unplaced locations
|
||||
if (!mLocations[i]->Placed() && // node has not been placed
|
||||
mLocations[i]->MaxDepth() > max_depth) // and this is the deepest
|
||||
{
|
||||
max_depth = mLocations[i]->MaxDepth();
|
||||
}
|
||||
}
|
||||
mMaxDepth = max_depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::PathVisit
|
||||
* This method is called recursively to create a network of nodes connected with paths.
|
||||
*
|
||||
* inputs:
|
||||
* c_x, c_y - cell to visit
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::PathVisit(const int c_x, const int c_y)
|
||||
{
|
||||
// does this cell have any neighbors with all walls intact?
|
||||
int i,off;
|
||||
|
||||
// look at neighbors in random order
|
||||
off = TheRandomMissionManager->GetLandScape()->irand(DIR_FIRST, DIR_MAX-1);
|
||||
|
||||
++mDepth; // track our depth of recursion
|
||||
|
||||
for (i = DIR_FIRST; i<DIR_MAX && mDepth <= mMaxDepth; i++)
|
||||
{
|
||||
int d = (i + off) % DIR_MAX;
|
||||
if ( !Cell(c_x, c_y).Border(d) )
|
||||
{ // we can move this way, since no border
|
||||
int new_c_x = c_x + neighbor_x[d];
|
||||
int new_c_y = c_y + neighbor_y[d];
|
||||
if (Cell(new_c_x,new_c_y).Wall() == DIR_ALL)
|
||||
{ // we have a new cell that has not been visited!
|
||||
int new_dir;
|
||||
// d is the direction relative to the current cell
|
||||
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||
if( d < HALF_DIR_MAX )
|
||||
{
|
||||
new_dir = d + HALF_DIR_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dir = d - HALF_DIR_MAX;
|
||||
}
|
||||
|
||||
// knock down walls
|
||||
Cell(c_x,c_y).RemoveWall(d);
|
||||
Cell(new_c_x,new_c_y).RemoveWall(new_dir); //DIR_MAX - d);
|
||||
|
||||
// set path id
|
||||
Node(c_x, c_y)->SetPath(d, mPathCount);
|
||||
Node(new_c_x, new_c_y)->SetPath(new_dir, mPathCount); //DIR_MAX - d, mPathCount);
|
||||
|
||||
// create path between cells
|
||||
mTerrain->CreatePath( mPathCount++,
|
||||
-1,
|
||||
0,
|
||||
mPathPoints,
|
||||
GetNodePos(c_x,c_y)[0],
|
||||
GetNodePos(c_x,c_y)[1],
|
||||
GetNodePos(new_c_x,new_c_y)[0],
|
||||
GetNodePos(new_c_x,new_c_y)[1],
|
||||
mPathMinWidth,
|
||||
mPathMaxWidth,
|
||||
mPathDepth,
|
||||
mPathDeviation,
|
||||
mPathBreadth );
|
||||
|
||||
// flatten a small spot
|
||||
CArea area;
|
||||
float flat_radius = mPathMaxWidth *
|
||||
fabs(TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - TheRandomMissionManager->GetLandScape()->GetBounds()[0][0]);
|
||||
area.Init( GetNodePos(c_x,c_y), flat_radius, 0.0f, AT_NONE, 0, 0 );
|
||||
TheRandomMissionManager->GetLandScape()->FlattenArea(&area, 255 * mPathDepth, false, true, true );
|
||||
|
||||
// recurse
|
||||
PathVisit(new_c_x, new_c_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--mDepth;
|
||||
|
||||
// NOTE: *whoop* hack alert, the first time this is reached, it should be the very last placed node.
|
||||
if( !mCrossed && TheRandomMissionManager->GetMission()->GetSymmetric() &&
|
||||
TheRandomMissionManager->GetMission()->GetBackUpPath() )
|
||||
{
|
||||
mCrossed = true;
|
||||
|
||||
int directionSet[3][3] = {DIR_NW,DIR_W,DIR_SW,DIR_N,-1,DIR_S,DIR_NE,DIR_E,DIR_SE};
|
||||
int ncx = (mXNodes-1)-c_x;
|
||||
int ncy = (mYNodes-1)-c_y;
|
||||
|
||||
int x_delta = ncx - c_x;
|
||||
int y_delta = ncy - c_y;
|
||||
|
||||
if( x_delta < -1 )
|
||||
{
|
||||
x_delta = -1;
|
||||
}
|
||||
else if( x_delta > 1 )
|
||||
{
|
||||
x_delta = 1;
|
||||
}
|
||||
|
||||
if( y_delta < -1 )
|
||||
{
|
||||
y_delta = -1;
|
||||
}
|
||||
else if( y_delta > 1 )
|
||||
{
|
||||
y_delta = 1;
|
||||
}
|
||||
|
||||
// make sure the mirror is actually in a different position than then un-mirrored node
|
||||
if( x_delta || y_delta )
|
||||
{
|
||||
|
||||
int d = directionSet[x_delta][y_delta];
|
||||
int new_dir;
|
||||
// d is the direction relative to the current cell
|
||||
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||
if( d < HALF_DIR_MAX )
|
||||
{
|
||||
new_dir = d + HALF_DIR_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dir = d - HALF_DIR_MAX;
|
||||
}
|
||||
|
||||
//NOTE: Knocking down these walls will cause instances to be created on this new artificial path
|
||||
// Since this path could span more than just the normal 1 cell, these walls being knocked down are not exactly correct... but get the job done
|
||||
|
||||
// knock down walls
|
||||
Cell(c_x,c_y).RemoveWall(d);
|
||||
Cell(ncx,ncy).RemoveWall(new_dir); //DIR_MAX - d);
|
||||
|
||||
// set path id
|
||||
Node(c_x, c_y)->SetPath(d, mPathCount);
|
||||
Node(ncx, ncy)->SetPath(new_dir, mPathCount); //DIR_MAX - d, mPathCount);
|
||||
|
||||
// create an artificial path that crosses over to connect the symmetric and non-symmetric map parts
|
||||
mTerrain->CreatePath( mPathCount++,
|
||||
-1,
|
||||
0,
|
||||
mPathPoints,
|
||||
GetNodePos(c_x,c_y)[0],
|
||||
GetNodePos(c_x,c_y)[1],
|
||||
GetNodePos(ncx,ncy)[0],
|
||||
GetNodePos(ncx,ncy)[1],
|
||||
mPathMinWidth,
|
||||
mPathMaxWidth,
|
||||
mPathDepth,
|
||||
mPathDeviation,
|
||||
mPathBreadth );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
PlaceLocation(c_x, c_y);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::FindNodeByName
|
||||
* Finds the managed node with the matching case-insensivity name
|
||||
*
|
||||
* inputs:
|
||||
* name - name of the node to find
|
||||
*
|
||||
* return:
|
||||
* a pointer to the found node or NULL if the node couldn't be found
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMNode* CRMPathManager::FindNodeByName ( const char* name )
|
||||
{
|
||||
int j;
|
||||
|
||||
for ( j = mNodes.size() - 1; j >=0; j-- )
|
||||
{
|
||||
if ( !stricmp ( name, mNodes[j]->GetName ( ) ) )
|
||||
return mNodes[j];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::SetPathStyle
|
||||
* sets style for all paths
|
||||
*
|
||||
* inputs:
|
||||
* settings for paths that are created
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::SetPathStyle (
|
||||
const int points,
|
||||
const float minwidth,
|
||||
const float maxwidth,
|
||||
const float depth,
|
||||
const float deviation,
|
||||
const float breadth
|
||||
)
|
||||
{
|
||||
// save path style
|
||||
mPathPoints = points ;
|
||||
mPathMinWidth = minwidth;
|
||||
mPathMaxWidth = maxwidth;
|
||||
mPathDepth = depth ;
|
||||
mPathDeviation= deviation;
|
||||
mPathBreadth = breadth ;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::SetRiverStyle
|
||||
* sets style for all rivers
|
||||
*
|
||||
* inputs:
|
||||
* settings for river paths that are created
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::SetRiverStyle (const int depth,
|
||||
const int points,
|
||||
const float minwidth,
|
||||
const float maxwidth,
|
||||
const float beddepth,
|
||||
const float deviation,
|
||||
const float breadth,
|
||||
string bridge_name)
|
||||
{
|
||||
// save river style
|
||||
mRiverDepth = depth;
|
||||
mRiverPoints = points ;
|
||||
mRiverMinWidth = minwidth;
|
||||
mRiverMaxWidth = maxwidth;
|
||||
mRiverBedDepth = beddepth ;
|
||||
mRiverDeviation= deviation;
|
||||
mRiverBreadth = breadth ;
|
||||
mRiverBridge = bridge_name;
|
||||
}
|
||||
|
||||
vec3_t& CRMPathManager::GetRiverPos( const int x, const int y )
|
||||
{
|
||||
mRiverPos[0] = (float)(x + 1.0f) / (float)(mXNodes+2);
|
||||
mRiverPos[1] = (float)(y + 1.0f) / (float)(mYNodes+2);
|
||||
return mRiverPos;
|
||||
}
|
||||
|
||||
void CRMPathManager::RiverVisit(const int c_x, const int c_y)
|
||||
{
|
||||
// does this cell have any neighbors with all walls intact?
|
||||
int i,off;
|
||||
|
||||
// look at neighbors in random order
|
||||
off = TheRandomMissionManager->GetLandScape()->irand(DIR_FIRST, DIR_MAX-1);
|
||||
|
||||
++mDepth; // track our depth of recursion
|
||||
|
||||
for (i = DIR_FIRST; i<DIR_MAX && mDepth <= mMaxDepth; i+=2)
|
||||
{
|
||||
int d = (i + off) % DIR_MAX;
|
||||
if ( !Cell(c_x, c_y).Border(d) )
|
||||
{ // we can move this way, since no border
|
||||
int new_c_x = c_x + neighbor_x[d];
|
||||
int new_c_y = c_y + neighbor_y[d];
|
||||
if (RiverCell(new_c_x,new_c_y).Wall() == DIR_ALL)
|
||||
{ // we have a new cell that has not been visited!
|
||||
|
||||
int new_dir;
|
||||
// d is the direction relative to the current cell
|
||||
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||
if( d < HALF_DIR_MAX )
|
||||
{
|
||||
new_dir = d + HALF_DIR_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dir = d - HALF_DIR_MAX;
|
||||
}
|
||||
// knock down walls
|
||||
RiverCell(c_x,c_y).RemoveWall(d);
|
||||
RiverCell(new_c_x,new_c_y).RemoveWall(new_dir); //DIR_MAX - d);
|
||||
|
||||
// create river between cells
|
||||
mTerrain->CreatePath ( mPathCount++,
|
||||
-1,
|
||||
0,
|
||||
mRiverPoints,
|
||||
GetRiverPos(c_x,c_y)[0],
|
||||
GetRiverPos(c_x,c_y)[1],
|
||||
GetRiverPos(new_c_x,new_c_y)[0],
|
||||
GetRiverPos(new_c_x,new_c_y)[1],
|
||||
mRiverMinWidth,
|
||||
mRiverMaxWidth,
|
||||
mRiverBedDepth,
|
||||
mRiverDeviation,
|
||||
mRiverBreadth );
|
||||
|
||||
// flatten a small spot
|
||||
CArea area;
|
||||
float flat_radius = mRiverMinWidth *
|
||||
fabs(TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - TheRandomMissionManager->GetLandScape()->GetBounds()[0][0]);
|
||||
area.Init( GetRiverPos(c_x,c_y), flat_radius, 0.0f, AT_NONE, 0, 0 );
|
||||
TheRandomMissionManager->GetLandScape()->FlattenArea (&area, 255 * mRiverBedDepth, false, true, true );
|
||||
|
||||
// recurse
|
||||
RiverVisit(new_c_x, new_c_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --mDepth;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::GenerateRivers
|
||||
* Creates a river which intersects the main path
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::GenerateRivers ()
|
||||
{
|
||||
if (mRiverBedDepth == 1)
|
||||
// no rivers
|
||||
return;
|
||||
|
||||
mMaxDepth = mRiverDepth;
|
||||
mDepth = 0;
|
||||
|
||||
int cell_x = 0;
|
||||
int cell_y = 0;
|
||||
|
||||
// choose starting cell along an edge
|
||||
int edge = TheRandomMissionManager->GetLandScape()->irand(0, 7);
|
||||
switch ( edge )
|
||||
{
|
||||
case 0:
|
||||
cell_x = mXNodes / 2; cell_y = 0;
|
||||
break;
|
||||
case 1:
|
||||
cell_x = mXNodes; cell_y = 0;
|
||||
break;
|
||||
case 2:
|
||||
cell_x = mXNodes; cell_y = mYNodes / 2;
|
||||
break;
|
||||
case 3:
|
||||
cell_x = mXNodes; cell_y = mYNodes;
|
||||
break;
|
||||
case 4:
|
||||
cell_x = mXNodes / 2; cell_y = mYNodes;
|
||||
break;
|
||||
case 5:
|
||||
cell_x = 0; cell_y = mYNodes;
|
||||
break;
|
||||
case 6:
|
||||
cell_x = 0; cell_y = mYNodes / 2;
|
||||
break;
|
||||
case 7:
|
||||
cell_x = 0; cell_y = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ClearCells(mXNodes+1, mYNodes+1);
|
||||
|
||||
mRiverCount = mPathCount;
|
||||
|
||||
// visit the first cell
|
||||
RiverVisit(cell_x,cell_y);
|
||||
|
||||
mRiverCount = mPathCount - mRiverCount;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::GeneratePaths
|
||||
* Creates all paths
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::GeneratePaths ( symmetry_t symmetric )
|
||||
{
|
||||
int cell_x = 0;
|
||||
int cell_y = 0;
|
||||
|
||||
switch ( symmetric )
|
||||
{
|
||||
case SYMMETRY_TOPLEFT:
|
||||
cell_x = mXNodes-1;
|
||||
cell_y = 0;
|
||||
break;
|
||||
|
||||
case SYMMETRY_BOTTOMRIGHT:
|
||||
cell_x = 0;
|
||||
cell_y = mYNodes-1;
|
||||
break;
|
||||
|
||||
default:
|
||||
case SYMMETRY_NONE:
|
||||
// choose starting cell along an edge
|
||||
switch ( TheRandomMissionManager->GetLandScape()->irand(0, 7) )
|
||||
{
|
||||
case 0:
|
||||
cell_x = mXNodes / 2;
|
||||
break;
|
||||
case 1:
|
||||
cell_x = mXNodes-1;
|
||||
break;
|
||||
case 2:
|
||||
cell_x = mXNodes-1; cell_y = mYNodes / 2;
|
||||
break;
|
||||
case 3:
|
||||
cell_x = mXNodes-1; cell_y = mYNodes-1;
|
||||
break;
|
||||
case 4:
|
||||
cell_x = mXNodes / 2; cell_y = mYNodes-1;
|
||||
break;
|
||||
case 5:
|
||||
cell_y = mYNodes-1;
|
||||
break;
|
||||
case 6:
|
||||
cell_y = mYNodes / 2;
|
||||
break;
|
||||
default:
|
||||
case 7:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// visit the first cell
|
||||
PathVisit(cell_x,cell_y);
|
||||
}
|
||||
|
||||
223
code/RMG/RM_Path.h
Normal file
223
code/RMG/RM_Path.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* Copyright (C) 2001-2002 Raven Software
|
||||
*
|
||||
* RM_Path.h
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#if !defined(RM_PATH_H_INC)
|
||||
#define RM_PATH_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Path.h")
|
||||
#endif
|
||||
|
||||
#if !defined(CM_RANDOMTERRAIN_H_INC)
|
||||
#include "../qcommon/cm_randomterrain.h"
|
||||
#endif
|
||||
|
||||
class CRMPathManager;
|
||||
|
||||
// directions you can proceed from cells
|
||||
enum ERMDir
|
||||
{
|
||||
DIR_FIRST= 0,
|
||||
DIR_N = 0,
|
||||
DIR_NE,
|
||||
DIR_E ,
|
||||
DIR_SE,
|
||||
DIR_S ,
|
||||
DIR_SW,
|
||||
DIR_W ,
|
||||
DIR_NW,
|
||||
DIR_MAX,
|
||||
DIR_ALL = 255
|
||||
};
|
||||
|
||||
#define HALF_DIR_MAX (DIR_MAX/2)
|
||||
|
||||
class CRMNode
|
||||
{
|
||||
private:
|
||||
|
||||
string mName; // name of node - "" if not used yet
|
||||
vec3_t mPos; // where node is
|
||||
int mPathID[DIR_MAX]; // path id's that lead from this node
|
||||
bool mAreaPointPlaced; // false if no area point here yet.
|
||||
|
||||
int mFlattenHeight;
|
||||
|
||||
public:
|
||||
|
||||
CRMNode ( );
|
||||
|
||||
bool IsLocation() {return strlen(mName.c_str())>0;};
|
||||
const char* GetName ( ) { return mName.c_str(); }
|
||||
vec3_t& GetPos ( ) { return mPos; }
|
||||
const float PathExist( const int dir) { return (mPathID[dir % DIR_MAX] != -1); };
|
||||
const float GetPath ( const int dir) { return mPathID[dir % DIR_MAX]; };
|
||||
bool AreaPoint() {return mAreaPointPlaced;};
|
||||
|
||||
void SetName ( const char* name ) { mName = name; }
|
||||
void SetPos ( const vec3_t& v ) { VectorCopy ( v, mPos ); }
|
||||
void SetPath( const int dir, const int id) { mPathID[dir % DIR_MAX] = id; };
|
||||
void SetAreaPoint(bool ap) {mAreaPointPlaced = ap;};
|
||||
|
||||
void SetFlattenHeight(int flattenHeight) {mFlattenHeight = flattenHeight; }
|
||||
int GetFlattenHeight() {return mFlattenHeight; }
|
||||
};
|
||||
|
||||
typedef vector<CRMNode*> rmNodeVector_t;
|
||||
|
||||
// named spots on the map, should be placed into nodes
|
||||
class CRMLoc
|
||||
{
|
||||
private:
|
||||
|
||||
string mName; // name of location
|
||||
int mMinDepth;
|
||||
int mMaxDepth;
|
||||
int mMinPaths;
|
||||
int mMaxPaths;
|
||||
bool mPlaced; // location has been placed at a node
|
||||
|
||||
public:
|
||||
CRMLoc (const char *name, const int min_depth, const int max_depth, const int min_paths =1, const int max_paths=1 )
|
||||
: mMinDepth(min_depth), mMaxDepth(max_depth), mPlaced(false), mMinPaths(min_paths), mMaxPaths(max_paths)
|
||||
{ mName = name; };
|
||||
|
||||
const char* GetName ( ) { return mName.c_str(); }
|
||||
void SetName ( const char* name ) { mName = name; }
|
||||
|
||||
int MinDepth() {return mMinDepth;};
|
||||
void SetMinDepth(const int deep) {mMinDepth = deep;};
|
||||
|
||||
int MaxDepth() {return mMaxDepth;};
|
||||
void SetMaxDepth(const int deep) {mMaxDepth = deep;};
|
||||
|
||||
int MinPaths() {return mMinPaths;};
|
||||
void SetMinPaths(const int paths) {mMinPaths = paths;};
|
||||
|
||||
int MaxPaths() {return mMaxPaths;};
|
||||
void SetMaxPaths(const int paths) {mMaxPaths = paths;};
|
||||
|
||||
bool Placed() { return mPlaced; };
|
||||
void SetPlaced(bool p) { mPlaced = p;};
|
||||
};
|
||||
|
||||
typedef vector<CRMLoc*> rmLocVector_t;
|
||||
|
||||
|
||||
// cells are used for figuring out node connections / paths
|
||||
struct CRMCell
|
||||
{
|
||||
private:
|
||||
int border;
|
||||
int wall;
|
||||
|
||||
public:
|
||||
CRMCell() { border = 0; wall = DIR_ALL; };
|
||||
|
||||
int Border() {return border;};
|
||||
int Wall() {return wall;};
|
||||
bool Border(const int dir) { return (border & (1<<dir))!=0; };
|
||||
bool Wall(const int dir) { return (wall & (1<<dir))!=0; };
|
||||
void SetBorder(const int dir) { border |= (1<<dir); };
|
||||
void SetWall(const int dir) { wall |= (1<<dir); };
|
||||
void RemoveWall(const int dir) { wall &= ~(1<<dir); };
|
||||
};
|
||||
|
||||
typedef vector<CRMCell> rmCellVector_t;
|
||||
|
||||
|
||||
class CRMPathManager
|
||||
{
|
||||
public:
|
||||
int mXNodes; // number of nodes in the x dimension
|
||||
int mYNodes; // number of nodes in the y dimension
|
||||
|
||||
private:
|
||||
rmLocVector_t mLocations; // location, named spots to be placed at nodes
|
||||
rmNodeVector_t mNodes; // nodes, spots on map that *may* be connected by paths
|
||||
rmCellVector_t mCells; // array of cells for doing path generation
|
||||
|
||||
int mPathCount;
|
||||
int mRiverCount;
|
||||
int mMaxDepth; // deepest any location wants to be
|
||||
int mDepth; // current depth
|
||||
|
||||
bool mCrossed; // used to indicate if paths crossed the imaginary diagonal that cuts symmetric maps in half
|
||||
|
||||
// path style
|
||||
int mPathPoints;
|
||||
float mPathMinWidth;
|
||||
float mPathMaxWidth;
|
||||
float mPathDepth;
|
||||
float mPathDeviation;
|
||||
float mPathBreadth;
|
||||
|
||||
// river style
|
||||
int mRiverDepth;
|
||||
int mRiverPoints;
|
||||
float mRiverMinWidth;
|
||||
float mRiverMaxWidth;
|
||||
float mRiverBedDepth;
|
||||
float mRiverDeviation;
|
||||
float mRiverBreadth;
|
||||
string mRiverBridge;
|
||||
vec3_t mRiverPos;
|
||||
|
||||
static int neighbor_x[DIR_MAX];
|
||||
static int neighbor_y[DIR_MAX];
|
||||
|
||||
CRandomTerrain* mTerrain;
|
||||
|
||||
public:
|
||||
CRMPathManager ( CRandomTerrain* terrain );
|
||||
~CRMPathManager ( );
|
||||
|
||||
void ClearCells (int x_nodes, int y_nodes);
|
||||
bool CreateArray ( const int x_nodes, const int y_nodes );
|
||||
|
||||
CRMNode* FindNodeByName ( const char* name );
|
||||
CRMNode* Node ( const int x, const int y ) {return mNodes[x + y*mXNodes];};
|
||||
|
||||
void CreateLocation ( const char* name, const int min_depth, int max_depth, const int min_paths =1, int max_paths =1 );
|
||||
|
||||
vec3_t& GetNodePos ( const int x, const int y ) { return mNodes[x + y*mXNodes]->GetPos(); };
|
||||
void SetNodePos ( const int x, const int y, const vec3_t& pos) { mNodes[x + y*mXNodes]->SetPos(pos); };
|
||||
int GetPathCount () {return mPathCount;};
|
||||
int GetRiverCount () {return mRiverCount;};
|
||||
float GetRiverDepth () {return mRiverBedDepth;};
|
||||
float GetPathDepth () {return mPathDepth;};
|
||||
const char *GetBridgeName () {return mRiverBridge.c_str();};
|
||||
vec3_t& GetRiverPos ( const int x, const int y );
|
||||
|
||||
CRMCell& Cell ( const int x, const int y ) {return mCells[x + y*mXNodes];};
|
||||
CRMCell& RiverCell ( const int x, const int y ) {return mCells[x + y*(mXNodes+1)];};
|
||||
void PlaceLocation ( const int x, const int y );
|
||||
void PathVisit ( const int x, const int y );
|
||||
void RiverVisit ( const int x, const int y );
|
||||
void SetPathStyle ( const int points = 10,
|
||||
const float minwidth = 0.01f,
|
||||
const float maxwidth = 0.05f,
|
||||
const float depth = 0.3f,
|
||||
const float deviation = 0.2f,
|
||||
const float breadth = 5);
|
||||
|
||||
void SetRiverStyle ( const int depth = 5,
|
||||
const int points = 10,
|
||||
const float minwidth = 0.01,
|
||||
const float maxwidth = 0.03,
|
||||
const float beddepth = 0.0f,
|
||||
const float deviation = 0.25f,
|
||||
const float breadth = 7,
|
||||
string bridge_name = "");
|
||||
|
||||
void GeneratePaths ( symmetry_t symmetric = SYMMETRY_NONE );
|
||||
void GenerateRivers ( );
|
||||
};
|
||||
|
||||
#endif
|
||||
533
code/RMG/RM_Terrain.cpp
Normal file
533
code/RMG/RM_Terrain.cpp
Normal file
@@ -0,0 +1,533 @@
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "../client/client.h"
|
||||
#include "../qcommon/cm_local.h"
|
||||
#include "../renderer/tr_types.h"
|
||||
#include "rm_headers.h"
|
||||
|
||||
//#include "../qcommon/q_imath.h"
|
||||
|
||||
#pragma optimize("", off)
|
||||
|
||||
void R_LoadDataImage ( const char *name, byte **pic, int *width, int *height);
|
||||
void R_InvertImage ( byte *data, int width, int height, int depth);
|
||||
void R_Resample ( byte *source, int swidth, int sheight, byte *dest, int dwidth, int dheight, int components);
|
||||
void RE_GetModelBounds (refEntity_t *refEnt, vec3_t bounds1, vec3_t bounds2);
|
||||
|
||||
static CRMLandScape *rm_landscape;
|
||||
static CCMLandScape *origin_land;
|
||||
|
||||
CRMLandScape::CRMLandScape(void)
|
||||
{
|
||||
common = NULL;
|
||||
mDensityMap = NULL;
|
||||
}
|
||||
|
||||
CRMLandScape::~CRMLandScape(void)
|
||||
{
|
||||
if(mDensityMap)
|
||||
{
|
||||
Z_Free(mDensityMap);
|
||||
mDensityMap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CCGHeightDetails::AddModel(const CRandomModel *hd)
|
||||
{
|
||||
if(mNumModels < MAX_RANDOM_MODELS)
|
||||
{
|
||||
mTotalFrequency += hd->GetFrequency();
|
||||
mModels[mNumModels++] = *hd;
|
||||
}
|
||||
}
|
||||
|
||||
void CRMLandScape::AddModel(const int height, int maxheight, const CRandomModel *hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(maxheight > HEIGHT_RESOLUTION)
|
||||
{
|
||||
maxheight = HEIGHT_RESOLUTION;
|
||||
}
|
||||
|
||||
for(i = height; hd->GetModel() && (i < maxheight); i++)
|
||||
{
|
||||
mHeightDetails[i].AddModel(hd);
|
||||
}
|
||||
}
|
||||
|
||||
void CRMLandScape::LoadMiscentDef(const char *td)
|
||||
{
|
||||
char miscentDef[MAX_QPATH];
|
||||
CGenericParser2 parse;
|
||||
CGPGroup *basegroup, *classes, *items, *model;
|
||||
CGPValue *pair;
|
||||
|
||||
Com_sprintf(miscentDef, MAX_QPATH, "ext_data/RMG/%s.miscents", Info_ValueForKey(td, "miscentDef"));
|
||||
Com_DPrintf("CG_Terrain: Loading and parsing miscentDef %s.....\n", Info_ValueForKey(td, "miscentDef"));
|
||||
|
||||
if(!Com_ParseTextFile(miscentDef, parse))
|
||||
{
|
||||
Com_sprintf(miscentDef, MAX_QPATH, "ext_data/arioche/%s.miscents", Info_ValueForKey(td, "miscentDef"));
|
||||
if(!Com_ParseTextFile(miscentDef, parse))
|
||||
{
|
||||
Com_Printf("Could not open %s\n", miscentDef);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The whole file....
|
||||
basegroup = parse.GetBaseParseGroup();
|
||||
|
||||
// The root { } struct
|
||||
classes = basegroup->GetSubGroups();
|
||||
while(classes)
|
||||
{
|
||||
items = classes->GetSubGroups();
|
||||
while(items)
|
||||
{
|
||||
if(!stricmp(items->GetName(), "miscent"))
|
||||
{
|
||||
int height, maxheight;
|
||||
|
||||
// Height must exist - the rest are optional
|
||||
height = atol(items->FindPairValue("height", "0"));
|
||||
maxheight = atol(items->FindPairValue("maxheight", "255"));
|
||||
|
||||
model = items->GetSubGroups();
|
||||
while(model)
|
||||
{
|
||||
if(!stricmp(model->GetName(), "model"))
|
||||
{
|
||||
CRandomModel hd;
|
||||
|
||||
// Set defaults
|
||||
hd.SetModel("");
|
||||
hd.SetFrequency(1.0f);
|
||||
hd.SetMinScale(1.0f);
|
||||
hd.SetMaxScale(1.0f);
|
||||
|
||||
pair = model->GetPairs();
|
||||
while(pair)
|
||||
{
|
||||
if(!stricmp(pair->GetName(), "name"))
|
||||
{
|
||||
hd.SetModel(pair->GetTopValue());
|
||||
}
|
||||
else if(!stricmp(pair->GetName(), "frequency"))
|
||||
{
|
||||
hd.SetFrequency((float)atof(pair->GetTopValue()));
|
||||
}
|
||||
else if(!stricmp(pair->GetName(), "minscale"))
|
||||
{
|
||||
hd.SetMinScale((float)atof(pair->GetTopValue()));
|
||||
}
|
||||
else if(!stricmp(pair->GetName(), "maxscale"))
|
||||
{
|
||||
hd.SetMaxScale((float)atof(pair->GetTopValue()));
|
||||
}
|
||||
pair = (CGPValue *)pair->GetNext();
|
||||
}
|
||||
AddModel(height, maxheight, &hd);
|
||||
}
|
||||
model = (CGPGroup *)model->GetNext();
|
||||
}
|
||||
}
|
||||
items = (CGPGroup *)items->GetNext();
|
||||
}
|
||||
classes = (CGPGroup *)classes->GetNext();
|
||||
}
|
||||
Com_ParseTextFileDestroy(parse);
|
||||
}
|
||||
|
||||
void CG_Decrease(byte *work, float lerp, int *info)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = *work - origin_land->irand(2, 5);
|
||||
*work = (byte)Com_Clamp(1, 255, val);
|
||||
}
|
||||
|
||||
void CRMLandScape::CreateRandomDensityMap(byte *density, int width, int height, int seed)
|
||||
{
|
||||
// int i, border, inc;
|
||||
int x, y, count;
|
||||
// byte *work, *work2;
|
||||
CArea *area;
|
||||
vec3_t derxelSize, pos;
|
||||
ivec3_t dmappos;
|
||||
byte *hm_map = common->GetHeightMap();
|
||||
int hm_width = common->GetRealWidth();
|
||||
int hm_height = common->GetRealHeight();
|
||||
int xpos, ypos, dx, dy;
|
||||
byte *densityPos = density;
|
||||
bool foundUneven;
|
||||
|
||||
// Init to linear spread
|
||||
memset(density, 0, width * height);
|
||||
|
||||
/* // Make more prevalent towards the edges
|
||||
border = Com_Clamp(6, 12, (width + height) >> 4);
|
||||
|
||||
for(i = 0; i < border; i++)
|
||||
{
|
||||
inc = (border - i + 1) * 9;
|
||||
|
||||
// Top line
|
||||
work = density + i + (i * width);
|
||||
for(x = i; x < width - i; x++, work++)
|
||||
{
|
||||
*work += (byte)common->irand(inc >> 1, inc);
|
||||
}
|
||||
|
||||
// Left and right edges
|
||||
work = density + i + ((i + 1) * width);
|
||||
work2 = density + (width - i) + ((i + 1) * width);
|
||||
for(y = i + 1; y < height - i - 2; y++, work += width, work2 += width)
|
||||
{
|
||||
*work += (byte)common->irand(inc >> 1, inc);
|
||||
*work2 += (byte)common->irand(inc >> 1, inc);
|
||||
}
|
||||
|
||||
// Bottom line
|
||||
work = density + i + ((height - i - 1) * width);
|
||||
for(x = i; x < width - i; x++, work++)
|
||||
{
|
||||
*work += (byte)common->irand(inc >> 1, inc);
|
||||
}
|
||||
}
|
||||
*/
|
||||
count = 0;
|
||||
|
||||
for(y=0;y<height;y++)
|
||||
{
|
||||
for(x=0;x<width;x++,densityPos++)
|
||||
{
|
||||
xpos = (x * hm_width / width);
|
||||
ypos = (y * hm_height / height);
|
||||
ypos = hm_height - ypos - 1;
|
||||
|
||||
if (hm_map[ypos*hm_width + xpos] < 150)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foundUneven = false;
|
||||
for(dx=-4;(dx<=4 && !foundUneven);dx++)
|
||||
{
|
||||
for(dy=-4;(dy<=4 && !foundUneven);dy++)
|
||||
{
|
||||
if (dx == 0 && dy == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((xpos+dx) >= 0 && (xpos+dx) < hm_width && (ypos+dy) >= 0 && (ypos+dy) < hm_height)
|
||||
{
|
||||
if (hm_map[(ypos+dy)*hm_width + (xpos+dx)] < 190)
|
||||
{
|
||||
*densityPos = 205;
|
||||
count++;
|
||||
foundUneven = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FILE *FH;
|
||||
|
||||
FH = fopen("c:\o.raw", "wb");
|
||||
fwrite(hm_map, 1, common->GetRealWidth() * common->GetRealHeight(), FH);
|
||||
fclose(FH);
|
||||
|
||||
FH = fopen("c:\d.raw", "wb");
|
||||
fwrite(density, 1, width*height, FH);
|
||||
fclose(FH);
|
||||
*/
|
||||
// Reduce severely for any settlements/buildings/objectives
|
||||
VectorScale(common->GetSize(), 1.0f / width, derxelSize);
|
||||
|
||||
origin_land = common;
|
||||
area = common->GetFirstArea();
|
||||
while(area)
|
||||
{
|
||||
// Skip group types since they encompass to much open area
|
||||
if ( area->GetType ( ) == AT_GROUP )
|
||||
{
|
||||
area = common->GetNextArea();
|
||||
continue;
|
||||
}
|
||||
|
||||
VectorSubtract(area->GetPosition(), common->GetMins(), pos);
|
||||
VectorInverseScaleVector(pos, derxelSize, dmappos);
|
||||
// Damn upside down gensurf
|
||||
dmappos[1] = height - dmappos[1];
|
||||
|
||||
count = ceilf(area->GetRadius() / derxelSize[1]);
|
||||
|
||||
while(count > 0)
|
||||
{
|
||||
CM_CircularIterate(density, width, height, dmappos[0], dmappos[1], 0, count, NULL, CG_Decrease);
|
||||
count--;
|
||||
}
|
||||
area = common->GetNextArea();
|
||||
}
|
||||
}
|
||||
|
||||
void CRMLandScape::LoadDensityMap(const char *td)
|
||||
{
|
||||
char densityMap[MAX_QPATH];
|
||||
byte *imageData;
|
||||
int iWidth, iHeight, seed;
|
||||
char *ptr;
|
||||
|
||||
// Fill in with default values
|
||||
mDensityMap = (byte *)Z_Malloc(common->GetBlockCount(), TAG_R_TERRAIN, qfalse);
|
||||
memset(mDensityMap, 128, common->GetBlockCount());
|
||||
|
||||
// Load in density map (if any)
|
||||
Com_sprintf(densityMap, MAX_QPATH, "%s", Info_ValueForKey(td, "densityMap"));
|
||||
if(strlen(densityMap))
|
||||
{
|
||||
Com_DPrintf("CG_Terrain: Loading density map %s.....\n", densityMap);
|
||||
R_LoadDataImage(densityMap, &imageData, &iWidth, &iHeight);
|
||||
if(imageData)
|
||||
{
|
||||
if(strstr(densityMap, "density_"))
|
||||
{
|
||||
seed = strtoul(Info_ValueForKey(td, "seed"),&ptr,10);
|
||||
CreateRandomDensityMap(imageData, iWidth, iHeight, seed);
|
||||
}
|
||||
R_Resample(imageData, iWidth, iHeight, mDensityMap, common->GetBlockWidth(), common->GetBlockHeight(), 1);
|
||||
R_InvertImage(mDensityMap, common->GetBlockWidth(), common->GetBlockHeight(), 1);
|
||||
Z_Free(imageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRandomModel *CCGHeightDetails::GetRandomModel(CCMLandScape *land)
|
||||
{
|
||||
int seek, i;
|
||||
|
||||
seek = land->irand(0, mTotalFrequency);
|
||||
for(i = 0; i < mNumModels; i++)
|
||||
{
|
||||
seek -= mModels[i].GetFrequency();
|
||||
if(seek <= 0)
|
||||
{
|
||||
return(mModels + i);
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return(NULL);
|
||||
}
|
||||
#ifndef DEDICATED
|
||||
void CRMLandScape::Sprinkle(CCMPatch *patch, CCGHeightDetails *hd, int level)
|
||||
{
|
||||
int i, count, px, py;
|
||||
float density;
|
||||
vec3_t origin, scale, angles, bounds[2];
|
||||
refEntity_t refEnt;
|
||||
CRandomModel *rm;
|
||||
CArea area;
|
||||
// int areaTypes[] = { AT_BSP, AT_OBJECTIVE };
|
||||
// TCGMiscEnt *data = (TCGMiscEnt *)cl.mSharedMemory;
|
||||
// TCGTrace *td = (TCGTrace *)cl.mSharedMemory;
|
||||
|
||||
// memset(&refEnt, 0, sizeof(refEntity_t));
|
||||
|
||||
px = patch->GetHeightMapX() / common->GetTerxels();
|
||||
py = patch->GetHeightMapY() / common->GetTerxels();
|
||||
// Get a number -5.3f to 5.3f
|
||||
density = (mDensityMap[px + (common->GetBlockWidth() * py)] - 128) / 24.0f;
|
||||
// ..and multiply that into the count
|
||||
count = Round(common->GetPatchScalarSize() * hd->GetAverageFrequency() * powf(2.0f, density) * 0.001);
|
||||
|
||||
for(i = 0; i < count; i++)
|
||||
{
|
||||
if(!common->irand(0, 10))
|
||||
{
|
||||
vec3_t temp;
|
||||
trace_t tr;
|
||||
float average;
|
||||
|
||||
rm = hd->GetRandomModel(common);
|
||||
|
||||
refEnt.hModel = re.RegisterModel(rm->GetModelName());
|
||||
refEnt.frame = 0;
|
||||
RE_GetModelBounds(&refEnt, bounds[0], bounds[1]);
|
||||
|
||||
// Calculate the scale using some magic to help ensure that the
|
||||
// scales are never too different from eachother. Otherwise you
|
||||
// could get an entity that is really small on one axis but huge
|
||||
// on another.
|
||||
temp[0] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||
temp[1] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||
temp[2] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||
|
||||
// Average of the three random numbers and divide that by two
|
||||
average = ( ( temp[0] + temp[1] + temp[2] ) / 3) / 2;
|
||||
|
||||
// Add in half of the other two numbers and then subtract half the average to prevent.
|
||||
// any number from going beyond the range. If all three numbers were the same then
|
||||
// they would remain unchanged after this calculation.
|
||||
scale[0] = temp[0] + (temp[1]+temp[2]) / 2 - average;
|
||||
scale[1] = temp[1] + (temp[0]+temp[2]) / 2 - average;
|
||||
scale[2] = temp[2] + (temp[0]+temp[1]) / 2 - average;
|
||||
|
||||
angles[0] = 0.0f;
|
||||
angles[1] = common->flrand((float)-M_PI, (float)M_PI);
|
||||
angles[2] = 0.0f;
|
||||
|
||||
VectorCopy(patch->GetMins(), origin);
|
||||
origin[0] += common->flrand(0.0f, common->GetPatchWidth());
|
||||
origin[1] += common->flrand(0.0f, common->GetPatchHeight());
|
||||
// Get above world height
|
||||
float slope = common->GetWorldHeight(origin, bounds, true);
|
||||
|
||||
if (slope > 1.33)
|
||||
{ // spot has too steep of a slope
|
||||
continue;
|
||||
}
|
||||
if(origin[2] < common->GetWaterHeight())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// very that we aren't dropped too low
|
||||
if (origin[2] < common->CalcWorldHeight(level))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hack-ariffic, don't allow them to drop below the big player clip brush.
|
||||
if (origin[2] < 1280 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// FIXME: shouldn't be using a hard-coded 1280 number, only allow to spawn if inside player clip brush?
|
||||
// if( !(CONTENTS_PLAYERCLIP & VM_Call( cgvm, CG_POINT_CONTENTS )) )
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// Simple radius check for buildings
|
||||
/* area.Init(origin, VectorLength(bounds[0]));
|
||||
if(common->AreaCollision(&area, areaTypes, sizeof(areaTypes) / sizeof(int)))
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
// Make sure there is no architecture around - doesn't work for ents though =(
|
||||
|
||||
/*
|
||||
memset(td, sizeof(*td), 0);
|
||||
VectorCopy(origin, td->mStart);
|
||||
VectorCopy(bounds[0], td->mMins);
|
||||
VectorCopy(bounds[1], td->mMaxs);
|
||||
VectorCopy(origin, td->mEnd);
|
||||
td->mSkipNumber = -1;
|
||||
td->mMask = MASK_PLAYERSOLID;
|
||||
*/
|
||||
SV_Trace(&tr, origin, bounds[0], bounds[1], origin, -1, (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY|CONTENTS_TERRAIN));
|
||||
|
||||
/*
|
||||
VM_Call( cgvm, CG_TRACE );
|
||||
if(td->mResult.surfaceFlags & SURF_NOMISCENTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(td->mResult.startsolid)
|
||||
{
|
||||
// continue;
|
||||
}
|
||||
*/
|
||||
if (tr.surfaceFlags & SURF_NOMISCENTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (tr.startsolid)
|
||||
{
|
||||
// continue;
|
||||
}
|
||||
|
||||
// Get minimum height of area
|
||||
common->GetWorldHeight(origin, bounds, false);
|
||||
// Account for relative origin
|
||||
origin[2] -= bounds[0][2] * scale[2];
|
||||
origin[2] -= common->flrand(2.0, (bounds[1][2] - bounds[0][2]) / 4);
|
||||
|
||||
//rwwFIXMEFIXME: Do this properly
|
||||
// Spawn the client model
|
||||
/*
|
||||
strcpy(data->mModel, rm->GetModelName());
|
||||
VectorCopy(origin, data->mOrigin);
|
||||
VectorCopy(angles, data->mAngles);
|
||||
VectorCopy(scale, data->mScale);
|
||||
VM_Call( cgvm, CG_MISC_ENT);
|
||||
*/
|
||||
|
||||
mModelCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
|
||||
void CRMLandScape::SpawnPatchModels(CCMPatch *patch)
|
||||
{
|
||||
int i;
|
||||
CCGHeightDetails *hd;
|
||||
|
||||
// Rand_Init(10);
|
||||
#ifndef DEDICATED
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
hd = mHeightDetails + patch->GetHeight(i);
|
||||
if(hd->GetNumModels())
|
||||
{
|
||||
Sprinkle(patch, hd, patch->GetHeight(i));
|
||||
}
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
}
|
||||
|
||||
void SpawnPatchModelsWrapper(CCMPatch *patch, void *userdata)
|
||||
{
|
||||
CRMLandScape *landscape = (CRMLandScape *)userdata;
|
||||
landscape->SpawnPatchModels(patch);
|
||||
}
|
||||
|
||||
void RM_CreateRandomModels(int terrainId, const char *terrainInfo)
|
||||
{
|
||||
CRMLandScape *landscape;
|
||||
|
||||
landscape = rm_landscape = new CRMLandScape;
|
||||
landscape->SetCommon(cmg.landScape);
|
||||
|
||||
Com_DPrintf("CG_Terrain: Creating random models.....\n");
|
||||
landscape->LoadMiscentDef(terrainInfo);
|
||||
landscape->LoadDensityMap(terrainInfo);
|
||||
landscape->ClearModelCount();
|
||||
CM_TerrainPatchIterate(landscape->GetCommon(), SpawnPatchModelsWrapper, landscape);
|
||||
|
||||
Com_DPrintf(".....%d random client models spawned\n", landscape->GetModelCount());
|
||||
}
|
||||
|
||||
void RM_InitTerrain(void)
|
||||
{
|
||||
rm_landscape = NULL;
|
||||
}
|
||||
|
||||
void RM_ShutdownTerrain(void)
|
||||
{
|
||||
CRMLandScape *landscape;
|
||||
|
||||
landscape = rm_landscape;
|
||||
if(landscape)
|
||||
{
|
||||
// CM_ShutdownTerrain(i);
|
||||
delete landscape;
|
||||
rm_landscape = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
|
||||
#pragma optimize("", on)
|
||||
97
code/RMG/RM_Terrain.h
Normal file
97
code/RMG/RM_Terrain.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#if !defined(RM_TERRAIN_H_INC)
|
||||
#define RM_TERRAIN_H_INC
|
||||
|
||||
#define MAX_RANDOM_MODELS 8
|
||||
|
||||
class CRandomModel
|
||||
{
|
||||
private:
|
||||
char mModelName[MAX_QPATH];
|
||||
float mFrequency;
|
||||
float mMinScale;
|
||||
float mMaxScale;
|
||||
public:
|
||||
CRandomModel(void) { }
|
||||
~CRandomModel(void) { }
|
||||
|
||||
// Accessors
|
||||
const bool GetModel( void ) const { return(!!strlen(mModelName)); }
|
||||
const char *GetModelName( void ) const { return(mModelName); }
|
||||
void SetModel(const char *name) { Com_sprintf(mModelName, MAX_QPATH, "%s.md3", name); }
|
||||
const float GetFrequency(void) const { return(mFrequency); }
|
||||
void SetFrequency(const float freq) { mFrequency = freq; }
|
||||
const float GetMinScale(void) const { return(mMinScale); }
|
||||
void SetMinScale(const float minscale) { mMinScale = minscale; }
|
||||
const float GetMaxScale(void) const { return(mMaxScale); }
|
||||
void SetMaxScale(const float maxscale) { mMaxScale = maxscale; }
|
||||
};
|
||||
|
||||
class CCGHeightDetails
|
||||
{
|
||||
private:
|
||||
int mNumModels;
|
||||
int mTotalFrequency;
|
||||
CRandomModel mModels[MAX_RANDOM_MODELS];
|
||||
public:
|
||||
// Constructors
|
||||
CCGHeightDetails( void ) { memset(this, 0, sizeof(*this)); }
|
||||
~CCGHeightDetails( void ) { }
|
||||
|
||||
// Accessors
|
||||
const int GetNumModels(void) const { return(mNumModels); }
|
||||
const int GetAverageFrequency(void) const { return(mTotalFrequency / mNumModels); }
|
||||
|
||||
// Prototypes
|
||||
void AddModel(const CRandomModel *hd);
|
||||
CRandomModel *GetRandomModel(CCMLandScape *land);
|
||||
};
|
||||
|
||||
class CCGPatch
|
||||
{
|
||||
private:
|
||||
class CCMLandScape *owner;
|
||||
class CCGLandScape *localowner;
|
||||
CCMPatch *common;
|
||||
public:
|
||||
};
|
||||
|
||||
class CRMLandScape
|
||||
{
|
||||
private:
|
||||
CCMLandScape *common;
|
||||
|
||||
byte *mDensityMap; // Data image of model densities
|
||||
int mModelCount; // Count of spawned client models
|
||||
CCGHeightDetails mHeightDetails[HEIGHT_RESOLUTION]; // Array of info specific to height
|
||||
|
||||
public:
|
||||
CRMLandScape(void);
|
||||
~CRMLandScape(void);
|
||||
|
||||
// Accessors
|
||||
void SetCommon(CCMLandScape *landscape) { common = landscape; }
|
||||
const CCMLandScape *GetCommon( void ) const { return(common); }
|
||||
const thandle_t GetCommonId( void ) const { return(common->GetTerrainId()); }
|
||||
const int GetTerxels(void) const { return(common->GetTerxels()); }
|
||||
const int GetRealWidth(void) const { return(common->GetRealWidth()); }
|
||||
const float GetPatchScalarSize(void) const { return(common->GetPatchScalarSize()); }
|
||||
const CCGHeightDetails *GetHeightDetail(int height) const { return(mHeightDetails + height); }
|
||||
void ClearModelCount(void) { mModelCount = 0; }
|
||||
const int GetModelCount(void) const { return(mModelCount); }
|
||||
|
||||
// Prototypes
|
||||
void SetShaders(const int height, const qhandle_t shader);
|
||||
void AddModel(const int height, int maxheight, const CRandomModel *hd);
|
||||
void LoadMiscentDef(const char *td);
|
||||
void LoadDensityMap(const char *td);
|
||||
void SpawnPatchModels(CCMPatch *patch);
|
||||
void Sprinkle(CCMPatch *patch, CCGHeightDetails *hd, int level);
|
||||
void CreateRandomDensityMap(byte *imageData, int width, int height, int seed);
|
||||
};
|
||||
|
||||
void RM_CreateRandomModels(int terrainId, const char *terrainInfo);
|
||||
void RM_InitTerrain(void);
|
||||
void RM_ShutdownTerrain(void);
|
||||
|
||||
#endif // RM_TERRAIN_H_INC
|
||||
BIN
code/SHDebug/HA312W32.DLL
Normal file
BIN
code/SHDebug/HA312W32.DLL
Normal file
Binary file not shown.
BIN
code/SHDebug/SHW32.DLL
Normal file
BIN
code/SHDebug/SHW32.DLL
Normal file
Binary file not shown.
BIN
code/StarWars.opt
Normal file
BIN
code/StarWars.opt
Normal file
Binary file not shown.
231
code/bspthing/bsp.h
Normal file
231
code/bspthing/bsp.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Common stuff
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#define MAX_QPATH 64 // max length of a quake game pathname
|
||||
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
typedef vec_t vec5_t[5];
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
#define LIGHTMAP_SIZE 128
|
||||
|
||||
#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models
|
||||
|
||||
#define POINTS_ST_SCALE 128.0f
|
||||
#define POINTS_LIGHT_SCALE 65536.0f
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
.BSP file format
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'R')
|
||||
#define BSP_VERSION 1
|
||||
|
||||
// there shouldn't be any problem with increasing these values at the
|
||||
// expense of more memory allocation in the utilities
|
||||
#define MAX_MAP_MODELS 0x400
|
||||
#define MAX_MAP_BRUSHES 0x8000
|
||||
#define MAX_MAP_ENTITIES 0x800
|
||||
#define MAX_MAP_ENTSTRING 0x40000
|
||||
#define MAX_MAP_SHADERS 0x400
|
||||
|
||||
#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
|
||||
#define MAX_MAP_FOGS 0x100
|
||||
#define MAX_MAP_PLANES 0x20000
|
||||
#define MAX_MAP_NODES 0x20000
|
||||
#define MAX_MAP_BRUSHSIDES 0x20000
|
||||
#define MAX_MAP_LEAFS 0x20000
|
||||
#define MAX_MAP_LEAFFACES 0x20000
|
||||
#define MAX_MAP_LEAFBRUSHES 0x40000
|
||||
#define MAX_MAP_PORTALS 0x20000
|
||||
#define MAX_MAP_LIGHTING 0x800000
|
||||
#define MAX_MAP_LIGHTGRID 65535
|
||||
#define MAX_MAP_LIGHTGRID_ARRAY 0x100000
|
||||
|
||||
#define MAX_MAP_VISIBILITY 0x400000
|
||||
|
||||
#define MAX_MAP_DRAW_SURFS 0x20000
|
||||
#define MAX_MAP_DRAW_VERTS 0x80000
|
||||
#define MAX_MAP_DRAW_INDEXES 0x80000
|
||||
|
||||
|
||||
// key / value pair sizes in the entities lump
|
||||
#define MAX_KEY 32
|
||||
#define MAX_VALUE 1024
|
||||
|
||||
// the editor uses these predefined yaw angles to orient entities up or down
|
||||
#define ANGLE_UP -1
|
||||
#define ANGLE_DOWN -2
|
||||
|
||||
#define LIGHTMAP_WIDTH 128
|
||||
#define LIGHTMAP_HEIGHT 128
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
typedef struct {
|
||||
int fileofs, filelen;
|
||||
} lump_t;
|
||||
|
||||
#define LUMP_ENTITIES 0
|
||||
#define LUMP_SHADERS 1
|
||||
#define LUMP_PLANES 2
|
||||
#define LUMP_NODES 3
|
||||
#define LUMP_LEAFS 4
|
||||
#define LUMP_LEAFSURFACES 5
|
||||
#define LUMP_LEAFBRUSHES 6
|
||||
#define LUMP_MODELS 7
|
||||
#define LUMP_BRUSHES 8
|
||||
#define LUMP_BRUSHSIDES 9
|
||||
#define LUMP_DRAWVERTS 10
|
||||
#define LUMP_DRAWINDEXES 11
|
||||
#define LUMP_FOGS 12
|
||||
#define LUMP_SURFACES 13
|
||||
#define LUMP_LIGHTMAPS 14
|
||||
#define LUMP_LIGHTGRID 15
|
||||
#define LUMP_VISIBILITY 16
|
||||
#define LUMP_LIGHTARRAY 17
|
||||
#define HEADER_LUMPS 18
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
|
||||
lump_t lumps[HEADER_LUMPS];
|
||||
} dheader_t;
|
||||
|
||||
typedef struct {
|
||||
float mins[3], maxs[3];
|
||||
int firstSurface, numSurfaces;
|
||||
int firstBrush, numBrushes;
|
||||
} dmodel_t;
|
||||
|
||||
typedef struct {
|
||||
char shader[MAX_QPATH];
|
||||
int surfaceFlags;
|
||||
int contentFlags;
|
||||
} dshader_t;
|
||||
|
||||
// planes x^1 is allways the opposite of plane x
|
||||
|
||||
typedef struct {
|
||||
float normal[3];
|
||||
float dist;
|
||||
} dplane_t;
|
||||
|
||||
typedef struct {
|
||||
int planeNum;
|
||||
int children[2]; // negative numbers are -(leafs+1), not nodes
|
||||
int mins[3]; // for frustom culling
|
||||
int maxs[3];
|
||||
} dnode_t;
|
||||
|
||||
typedef struct {
|
||||
int cluster; // -1 = opaque cluster (do I still store these?)
|
||||
int area;
|
||||
|
||||
int mins[3]; // for frustum culling
|
||||
int maxs[3];
|
||||
|
||||
int firstLeafSurface;
|
||||
int numLeafSurfaces;
|
||||
|
||||
int firstLeafBrush;
|
||||
int numLeafBrushes;
|
||||
} dleaf_t;
|
||||
|
||||
typedef struct {
|
||||
int planeNum; // positive plane side faces out of the leaf
|
||||
int shaderNum;
|
||||
int drawSurfNum;
|
||||
} dbrushside_t;
|
||||
|
||||
typedef struct {
|
||||
int firstSide;
|
||||
int numSides;
|
||||
int shaderNum; // the shader that determines the contents flags
|
||||
} dbrush_t;
|
||||
|
||||
typedef struct {
|
||||
char shader[MAX_QPATH];
|
||||
int brushNum;
|
||||
int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
|
||||
} dfog_t;
|
||||
|
||||
// Light Style Constants
|
||||
#define MAXLIGHTMAPS 4
|
||||
#define LS_NORMAL 0x00
|
||||
#define LS_UNUSED 0xfe
|
||||
#define LS_NONE 0xff
|
||||
#define MAX_LIGHT_STYLES 64
|
||||
|
||||
typedef struct {
|
||||
vec3_t xyz;
|
||||
float st[2];
|
||||
float lightmap[MAXLIGHTMAPS][2];
|
||||
vec3_t normal;
|
||||
byte color[MAXLIGHTMAPS][4];
|
||||
} mapVert_t;
|
||||
|
||||
#define DRAWVERT_LIGHTMAP_SCALE 32768.0f
|
||||
#define DRAWVERT_ST_SCALE 16.0f
|
||||
typedef struct {
|
||||
vec3_t xyz;
|
||||
short dvst[2];
|
||||
short dvlightmap[MAXLIGHTMAPS][2];
|
||||
vec3_t normal;
|
||||
byte dvcolor[MAXLIGHTMAPS][2];
|
||||
} drawVert_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte ambientLight[MAXLIGHTMAPS][3];
|
||||
byte directLight[MAXLIGHTMAPS][3];
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
byte latLong[2];
|
||||
} dgrid_t;
|
||||
|
||||
typedef enum {
|
||||
MST_BAD,
|
||||
MST_PLANAR,
|
||||
MST_PATCH,
|
||||
MST_TRIANGLE_SOUP,
|
||||
MST_FLARE
|
||||
} mapSurfaceType_t;
|
||||
|
||||
typedef struct {
|
||||
int shaderNum;
|
||||
int fogNum;
|
||||
int surfaceType;
|
||||
|
||||
int firstVert;
|
||||
int numVerts;
|
||||
|
||||
int firstIndex;
|
||||
int numIndexes;
|
||||
|
||||
byte lightmapStyles[MAXLIGHTMAPS], vertexStyles[MAXLIGHTMAPS];
|
||||
int lightmapNum[MAXLIGHTMAPS];
|
||||
int lightmapX[MAXLIGHTMAPS], lightmapY[MAXLIGHTMAPS];
|
||||
int lightmapWidth, lightmapHeight;
|
||||
|
||||
vec3_t lightmapOrigin;
|
||||
vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
|
||||
|
||||
int patchWidth;
|
||||
int patchHeight;
|
||||
} dsurface_t;
|
||||
21
code/bspthing/bspthing.sln
Normal file
21
code/bspthing/bspthing.sln
Normal file
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bspthing", "bspthing.vcproj", "{613ECD87-EBE1-47D9-A23D-68F52218AEB6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
ConfigName.0 = Debug
|
||||
ConfigName.1 = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectDependencies) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{613ECD87-EBE1-47D9-A23D-68F52218AEB6}.Debug.ActiveCfg = Debug|Win32
|
||||
{613ECD87-EBE1-47D9-A23D-68F52218AEB6}.Debug.Build.0 = Debug|Win32
|
||||
{613ECD87-EBE1-47D9-A23D-68F52218AEB6}.Release.ActiveCfg = Release|Win32
|
||||
{613ECD87-EBE1-47D9-A23D-68F52218AEB6}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
113
code/bspthing/bspthing.vcproj
Normal file
113
code/bspthing/bspthing.vcproj
Normal file
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding = "Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.00"
|
||||
Name="bspthing"
|
||||
ProjectGUID="{613ECD87-EBE1-47D9-A23D-68F52218AEB6}"
|
||||
Keyword="ManagedCProj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
ManagedExtensions="TRUE">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG"
|
||||
MinimalRebuild="FALSE"
|
||||
BasicRuntimeChecks="0"
|
||||
RuntimeLibrary="1"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/bspthing.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
ManagedExtensions="TRUE">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="1"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG"
|
||||
MinimalRebuild="FALSE"
|
||||
WarningLevel="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/bspthing.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
|
||||
<File
|
||||
RelativePath="main.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc">
|
||||
<File
|
||||
RelativePath="bsp.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="pbsp.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;r">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
1111
code/bspthing/main.cpp
Normal file
1111
code/bspthing/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
132
code/bspthing/pbsp.h
Normal file
132
code/bspthing/pbsp.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Packed .BSP structures
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
char shader[MAX_QPATH];
|
||||
int brushNum;
|
||||
int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
|
||||
} pdfog_t;
|
||||
|
||||
typedef struct {
|
||||
int firstSide;
|
||||
byte numSides;
|
||||
unsigned short shaderNum; // the shader that determines the contents flags
|
||||
} pdbrush_t;
|
||||
|
||||
typedef struct {
|
||||
int planeNum; // positive plane side faces out of the leaf
|
||||
byte shaderNum;
|
||||
} pdbrushside_t;
|
||||
|
||||
typedef struct {
|
||||
int planeNum;
|
||||
short children[2]; // negative numbers are -(leafs+1), not nodes
|
||||
short mins[3]; // for frustom culling
|
||||
short maxs[3];
|
||||
} pdnode_t;
|
||||
|
||||
typedef struct {
|
||||
short cluster; // -1 = opaque cluster (do I still store these?)
|
||||
signed char area;
|
||||
|
||||
short mins[3]; // for frustum culling
|
||||
short maxs[3];
|
||||
|
||||
unsigned short firstLeafSurface;
|
||||
unsigned short numLeafSurfaces;
|
||||
|
||||
unsigned short firstLeafBrush;
|
||||
unsigned short numLeafBrushes;
|
||||
} pdleaf_t;
|
||||
|
||||
typedef struct {
|
||||
float mins[3], maxs[3];
|
||||
int firstSurface;
|
||||
unsigned short numSurfaces;
|
||||
int firstBrush;
|
||||
unsigned short numBrushes;
|
||||
} pdmodel_t;
|
||||
|
||||
typedef struct {
|
||||
byte flags;
|
||||
byte latLong[2];
|
||||
int data;
|
||||
} pdgrid_t;
|
||||
|
||||
typedef struct {
|
||||
char shader[MAX_QPATH];
|
||||
int surfaceFlags;
|
||||
int contentFlags;
|
||||
} pdshader_t;
|
||||
|
||||
typedef struct {
|
||||
float normal[3];
|
||||
float dist;
|
||||
} pdplane_t;
|
||||
|
||||
typedef struct {
|
||||
float lightmap[MAXLIGHTMAPS][2];
|
||||
float st[2];
|
||||
short xyz[3];
|
||||
short normal[3];
|
||||
byte color[MAXLIGHTMAPS][4];
|
||||
} pmapVert_t;
|
||||
|
||||
typedef struct {
|
||||
int code;
|
||||
byte shaderNum;
|
||||
signed char fogNum;
|
||||
|
||||
unsigned int verts; // high 20 bits are first vert, low 12 are num verts
|
||||
|
||||
byte lightmapStyles[MAXLIGHTMAPS];
|
||||
byte lightmapNum[MAXLIGHTMAPS];
|
||||
|
||||
short lightmapVecs[2][3]; // for patches, [0] and [1] are lodbounds
|
||||
|
||||
byte patchWidth;
|
||||
byte patchHeight;
|
||||
} pdpatch_t;
|
||||
|
||||
typedef struct {
|
||||
int code;
|
||||
byte shaderNum;
|
||||
signed char fogNum;
|
||||
|
||||
unsigned int verts; // high 20 bits are first vert, low 12 are num verts
|
||||
unsigned int indexes; // high 20 bits are first index, low 12 are num indices
|
||||
|
||||
byte lightmapStyles[MAXLIGHTMAPS];
|
||||
byte lightmapNum[MAXLIGHTMAPS];
|
||||
|
||||
short lightmapVecs[3];
|
||||
} pdface_t;
|
||||
|
||||
typedef struct {
|
||||
int code;
|
||||
byte shaderNum;
|
||||
signed char fogNum;
|
||||
|
||||
unsigned int verts; // high 20 bits are first vert, low 12 are num verts
|
||||
unsigned int indexes; // high 20 bits are first index, low 12 are num indices
|
||||
|
||||
byte lightmapStyles[MAXLIGHTMAPS];
|
||||
} pdtrisurf_t;
|
||||
|
||||
typedef struct {
|
||||
int code;
|
||||
byte shaderNum;
|
||||
signed char fogNum;
|
||||
|
||||
short origin[3];
|
||||
short normal[3];
|
||||
byte color[3];
|
||||
} pdflare_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
105
code/cgame/FX_ATSTMain.cpp
Normal file
105
code/cgame/FX_ATSTMain.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
// Bowcaster Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ATSTMainProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
void FX_ATSTMainProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 30 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 30.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "atst/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ATSTMainHitWall
|
||||
---------------------------
|
||||
*/
|
||||
void FX_ATSTMainHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "atst/wall_impact", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ATSTMainHitPlayer
|
||||
---------------------------
|
||||
*/
|
||||
void FX_ATSTMainHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
if ( humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "atst/flesh_impact", origin, normal );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( "atst/droid_impact", origin, normal );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ATSTSideAltProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
void FX_ATSTSideAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "atst/side_alt_shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ATSTSideMainProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
void FX_ATSTSideMainProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "atst/side_main_shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
95
code/cgame/FX_Blaster.cpp
Normal file
95
code/cgame/FX_Blaster.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Blaster Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BlasterProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
|
||||
void FX_BlasterProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if (cent->currentState.eFlags & EF_USE_ANGLEDELTA)
|
||||
{
|
||||
AngleVectors(cent->currentState.angles, forward, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
if ( cent->gent && cent->gent->owner && cent->gent->owner->s.number > 0 )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "blaster/NPCshot", cent->lerpOrigin, forward );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.blasterShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BlasterAltFireThink
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BlasterAltFireThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
FX_BlasterProjectileThink( cent, weapon );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BlasterWeaponHitWall
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BlasterWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.blasterWallImpactEffect, origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BlasterWeaponHitPlayer
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BlasterWeaponHitPlayer( gentity_t *hit, vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
//temporary? just testing out the damage skin stuff -rww
|
||||
if ( hit && hit->client && hit->ghoul2.size() )
|
||||
{
|
||||
CG_AddGhoul2Mark(cgs.media.bdecal_burnmark1, flrand(3.5, 4.0), origin, normal, hit->s.number,
|
||||
hit->client->ps.origin, hit->client->renderInfo.legsYaw, hit->ghoul2, hit->s.modelScale, Q_irand(10000, 13000));
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( cgs.effects.blasterFleshImpactEffect, origin, normal );
|
||||
}
|
||||
66
code/cgame/FX_Bowcaster.cpp
Normal file
66
code/cgame/FX_Bowcaster.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Bowcaster Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_BowcasterProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_BowcasterProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( cgs.effects.bowcasterShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_BowcasterHitWall
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_BowcasterHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.bowcasterImpactEffect, origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_BowcasterHitPlayer
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_BowcasterHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.bowcasterImpactEffect, origin, normal );
|
||||
}
|
||||
156
code/cgame/FX_BryarPistol.cpp
Normal file
156
code/cgame/FX_BryarPistol.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
// Bryar Pistol Weapon Effects
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
|
||||
MAIN FIRE
|
||||
|
||||
-------------------------
|
||||
FX_BryarProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BryarProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
if ( cent->gent && cent->gent->owner && cent->gent->owner->s.number > 0 )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "bryar/NPCshot", cent->lerpOrigin, forward );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BryarHitWall
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BryarHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect, origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BryarHitPlayer
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BryarHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarFleshImpactEffect, origin, normal );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
|
||||
ALT FIRE
|
||||
|
||||
-------------------------
|
||||
FX_BryarAltProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BryarAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
// see if we have some sort of extra charge going on
|
||||
for ( int t = 1; t < cent->gent->count; t++ )
|
||||
{
|
||||
// just add ourselves over, and over, and over when we are charged
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarPowerupShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BryarAltHitWall
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BryarAltHitWall( vec3_t origin, vec3_t normal, int power )
|
||||
{
|
||||
switch( power )
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect3, origin, normal );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect2, origin, normal );
|
||||
break;
|
||||
|
||||
default:
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect, origin, normal );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BryarAltHitPlayer
|
||||
-------------------------
|
||||
*/
|
||||
void FX_BryarAltHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.bryarFleshImpactEffect, origin, normal );
|
||||
}
|
||||
98
code/cgame/FX_Concussion.cpp
Normal file
98
code/cgame/FX_Concussion.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Concussion Rifle Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ConcProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_ConcProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "concussion/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ConcHitWall
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_ConcHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "concussion/explosion", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ConcHitPlayer
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_ConcHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "concussion/explosion", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ConcAltShot
|
||||
---------------------------
|
||||
*/
|
||||
static vec3_t WHITE ={1.0f,1.0f,1.0f};
|
||||
|
||||
void FX_ConcAltShot( vec3_t start, vec3_t end )
|
||||
{
|
||||
//"concussion/beam"
|
||||
FX_AddLine( -1, start, end, 0.1f, 10.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
WHITE, WHITE, 0.0f,
|
||||
175, cgi_R_RegisterShader( "gfx/effects/blueLine" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
|
||||
vec3_t BRIGHT={0.75f,0.5f,1.0f};
|
||||
|
||||
// add some beef
|
||||
FX_AddLine( -1, start, end, 0.1f, 7.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
BRIGHT, BRIGHT, 0.0f,
|
||||
150, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_ConcAltMiss
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_ConcAltMiss( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
vec3_t pos, c1, c2;
|
||||
|
||||
VectorMA( origin, 4.0f, normal, c1 );
|
||||
VectorCopy( c1, c2 );
|
||||
c1[2] += 4;
|
||||
c2[2] += 12;
|
||||
|
||||
VectorAdd( origin, normal, pos );
|
||||
pos[2] += 28;
|
||||
|
||||
FX_AddBezier( origin, pos, c1, vec3_origin, c2, vec3_origin, 6.0f, 6.0f, 0.0f, 0.0f, 0.2f, 0.5f, WHITE, WHITE, 0.0f, 4000, cgi_R_RegisterShader( "gfx/effects/smokeTrail" ), FX_ALPHA_WAVE );
|
||||
|
||||
theFxScheduler.PlayEffect( "concussion/alt_miss", origin, normal );
|
||||
}
|
||||
92
code/cgame/FX_DEMP2.cpp
Normal file
92
code/cgame/FX_DEMP2.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// DEMP2 Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
#include "FxUtil.h"
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DEMP2_ProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_DEMP2_ProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
// theFxScheduler.PlayEffect( "demp2/shot", cent->lerpOrigin, forward );
|
||||
// theFxScheduler.PlayEffect( "demp2/shot2", cent->lerpOrigin, forward );
|
||||
theFxScheduler.PlayEffect( "demp2/projectile", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DEMP2_HitWall
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_DEMP2_HitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "demp2/wall_impact", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DEMP2_HitPlayer
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_DEMP2_HitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "demp2/flesh_impact", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DEMP2_AltProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_DEMP2_AltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "demp2/projectile", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
void FX_DEMP2_AltDetonate( vec3_t org, float size )
|
||||
{
|
||||
localEntity_t *ex;
|
||||
|
||||
ex = CG_AllocLocalEntity();
|
||||
ex->leType = LE_FADE_SCALE_MODEL;
|
||||
memset( &ex->refEntity, 0, sizeof( refEntity_t ));
|
||||
|
||||
ex->refEntity.renderfx |= RF_VOLUMETRIC;
|
||||
|
||||
ex->startTime = cg.time;
|
||||
ex->endTime = ex->startTime + 1300;
|
||||
|
||||
ex->radius = size;
|
||||
ex->refEntity.customShader = cgi_R_RegisterShader( "gfx/effects/demp2shell" );
|
||||
|
||||
ex->refEntity.hModel = cgi_R_RegisterModel( "models/items/sphere.md3" );
|
||||
VectorCopy( org, ex->refEntity.origin );
|
||||
|
||||
ex->color[0] = ex->color[1] = ex->color[2] = 255.0f;
|
||||
}
|
||||
98
code/cgame/FX_Disruptor.cpp
Normal file
98
code/cgame/FX_Disruptor.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Disruptor Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DisruptorMainShot
|
||||
---------------------------
|
||||
*/
|
||||
static vec3_t WHITE ={1.0f,1.0f,1.0f};
|
||||
|
||||
void FX_DisruptorMainShot( vec3_t start, vec3_t end )
|
||||
{
|
||||
FX_AddLine( -1, start, end, 0.1f, 4.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
WHITE, WHITE, 0.0f,
|
||||
120, cgi_R_RegisterShader( "gfx/effects/redLine" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DisruptorAltShot
|
||||
---------------------------
|
||||
*/
|
||||
void FX_DisruptorAltShot( vec3_t start, vec3_t end, qboolean fullCharge )
|
||||
{
|
||||
FX_AddLine( -1, start, end, 0.1f, 10.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
WHITE, WHITE, 0.0f,
|
||||
175, cgi_R_RegisterShader( "gfx/effects/redLine" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
|
||||
if ( fullCharge )
|
||||
{
|
||||
vec3_t YELLER={0.8f,0.7f,0.0f};
|
||||
|
||||
// add some beef
|
||||
FX_AddLine( -1, start, end, 0.1f, 7.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
YELLER, YELLER, 0.0f,
|
||||
150, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_DisruptorAltMiss
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_DisruptorAltMiss( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
vec3_t pos, c1, c2;
|
||||
|
||||
VectorMA( origin, 4.0f, normal, c1 );
|
||||
VectorCopy( c1, c2 );
|
||||
c1[2] += 4;
|
||||
c2[2] += 12;
|
||||
|
||||
VectorAdd( origin, normal, pos );
|
||||
pos[2] += 28;
|
||||
|
||||
FX_AddBezier( origin, pos, c1, vec3_origin, c2, vec3_origin, 6.0f, 6.0f, 0.0f, 0.0f, 0.2f, 0.5f, WHITE, WHITE, 0.0f, 4000, cgi_R_RegisterShader( "gfx/effects/smokeTrail" ), FX_ALPHA_WAVE );
|
||||
|
||||
theFxScheduler.PlayEffect( "disruptor/alt_miss", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_KothosBeam
|
||||
---------------------------
|
||||
*/
|
||||
void FX_KothosBeam( vec3_t start, vec3_t end )
|
||||
{
|
||||
FX_AddLine( -1, start, end, 0.1f, 10.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
WHITE, WHITE, 0.0f,
|
||||
175, cgi_R_RegisterShader( "gfx/misc/dr1" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
|
||||
vec3_t YELLER={0.8f,0.7f,0.0f};
|
||||
|
||||
// add some beef
|
||||
FX_AddLine( -1, start, end, 0.1f, 7.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
YELLER, YELLER, 0.0f,
|
||||
150, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
||||
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||
}
|
||||
146
code/cgame/FX_Emplaced.cpp
Normal file
146
code/cgame/FX_Emplaced.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Emplaced Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_EmplacedProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_EmplacedProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
// If tie-fighter missle use green shot.
|
||||
if ( cent->currentState.weapon == WP_TIE_FIGHTER )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "ships/imp_blastershot", cent->lerpOrigin, forward );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( cent->gent && cent->gent->owner && cent->gent->owner->activator && cent->gent->owner->activator->s.number > 0 )
|
||||
{
|
||||
// NPC's do short shot
|
||||
if ( cent->gent->alt_fire )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "eweb/shotNPC", cent->lerpOrigin, forward );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( "emplaced/shotNPC", cent->lerpOrigin, forward );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// players do long shot
|
||||
if ( cent->gent && cent->gent->alt_fire )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "eweb/shotNPC", cent->lerpOrigin, forward );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( "emplaced/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_EmplacedHitWall
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_EmplacedHitWall( vec3_t origin, vec3_t normal, qboolean eweb )
|
||||
{
|
||||
if ( eweb )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "eweb/wall_impact", origin, normal );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( "emplaced/wall_impact", origin, normal );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_EmplacedHitPlayer
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_EmplacedHitPlayer( vec3_t origin, vec3_t normal, qboolean eweb )
|
||||
{
|
||||
if ( eweb )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "eweb/flesh_impact", origin, normal );
|
||||
}
|
||||
else
|
||||
{
|
||||
theFxScheduler.PlayEffect( "emplaced/wall_impact", origin, normal );
|
||||
}
|
||||
}
|
||||
/*
|
||||
---------------------------
|
||||
FX_TurretProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_TurretProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "turret/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
73
code/cgame/FX_Flechette.cpp
Normal file
73
code/cgame/FX_Flechette.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Golan Arms Flechette Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_FlechetteProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
|
||||
void FX_FlechetteProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
EvaluateTrajectoryDelta( ¢->gent->s.pos, cg.time, forward );
|
||||
|
||||
if ( VectorNormalize( forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( cgs.effects.flechetteShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_FlechetteWeaponHitWall
|
||||
-------------------------
|
||||
*/
|
||||
void FX_FlechetteWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( cgs.effects.flechetteShotDeathEffect, origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_BlasterWeaponHitPlayer
|
||||
-------------------------
|
||||
*/
|
||||
void FX_FlechetteWeaponHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
// if ( humanoid )
|
||||
// {
|
||||
theFxScheduler.PlayEffect( cgs.effects.flechetteFleshImpactEffect, origin, normal );
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// theFxScheduler.PlayEffect( "blaster/droid_impact", origin, normal );
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_FlechetteProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
|
||||
void FX_FlechetteAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( cgs.effects.flechetteAltShotEffect, cent->lerpOrigin, forward );
|
||||
}
|
||||
92
code/cgame/FX_HeavyRepeater.cpp
Normal file
92
code/cgame/FX_HeavyRepeater.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Heavy Repeater Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_RepeaterProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_RepeaterProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "repeater/projectile", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------
|
||||
FX_RepeaterHitWall
|
||||
------------------------
|
||||
*/
|
||||
|
||||
void FX_RepeaterHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "repeater/wall_impact", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------
|
||||
FX_RepeaterHitPlayer
|
||||
------------------------
|
||||
*/
|
||||
|
||||
void FX_RepeaterHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "repeater/wall_impact", origin, normal );
|
||||
// theFxScheduler.PlayEffect( "repeater/flesh_impact", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------------
|
||||
FX_RepeaterAltProjectileThink
|
||||
-----------------------------
|
||||
*/
|
||||
|
||||
void FX_RepeaterAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "repeater/alt_projectile", cent->lerpOrigin, forward );
|
||||
// theFxScheduler.PlayEffect( "repeater/alt_projectile", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------
|
||||
FX_RepeaterAltHitWall
|
||||
------------------------
|
||||
*/
|
||||
|
||||
void FX_RepeaterAltHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "repeater/concussion", origin, normal );
|
||||
// theFxScheduler.PlayEffect( "repeater/alt_wall_impact2", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------
|
||||
FX_RepeaterAltHitPlayer
|
||||
------------------------
|
||||
*/
|
||||
|
||||
void FX_RepeaterAltHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "repeater/concussion", origin );
|
||||
// theFxScheduler.PlayEffect( "repeater/alt_wall_impact2", origin, normal );
|
||||
}
|
||||
72
code/cgame/FX_NoghriShot.cpp
Normal file
72
code/cgame/FX_NoghriShot.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Noghri Rifle
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_NoghriShotProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
|
||||
void FX_NoghriShotProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "noghri_stick/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_NoghriShotWeaponHitWall
|
||||
-------------------------
|
||||
*/
|
||||
void FX_NoghriShotWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "noghri_stick/flesh_impact", origin, normal );//no "noghri/wall_impact"?
|
||||
}
|
||||
/*
|
||||
-------------------------
|
||||
FX_NoghriShotWeaponHitPlayer
|
||||
-------------------------
|
||||
*/
|
||||
void FX_NoghriShotWeaponHitPlayer( gentity_t *hit, vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
//temporary? just testing out the damage skin stuff -rww
|
||||
/*
|
||||
if ( hit && hit->client && hit->ghoul2.size() )
|
||||
{
|
||||
CG_AddGhoul2Mark(cgs.media.bdecal_burnmark1, flrand(3.5, 4.0), origin, normal, hit->s.number,
|
||||
hit->client->ps.origin, hit->client->renderInfo.legsYaw, hit->ghoul2, hit->s.modelScale, Q_irand(10000, 13000));
|
||||
}
|
||||
*/
|
||||
|
||||
theFxScheduler.PlayEffect( "noghri_stick/flesh_impact", origin, normal );
|
||||
}
|
||||
66
code/cgame/FX_RocketLauncher.cpp
Normal file
66
code/cgame/FX_RocketLauncher.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Rocket Launcher Weapon
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_RocketProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_RocketProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "rocket/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_RocketHitWall
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_RocketHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "rocket/explosion", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_RocketHitPlayer
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_RocketHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "rocket/explosion", origin, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
---------------------------
|
||||
FX_RocketAltProjectileThink
|
||||
---------------------------
|
||||
*/
|
||||
|
||||
void FX_RocketAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "rocket/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
70
code/cgame/FX_TuskenShot.cpp
Normal file
70
code/cgame/FX_TuskenShot.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Tusken Rifle
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_TuskenShotProjectileThink
|
||||
-------------------------
|
||||
*/
|
||||
|
||||
void FX_TuskenShotProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||
{
|
||||
vec3_t forward;
|
||||
|
||||
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||
{
|
||||
forward[2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||
|
||||
if ( dif < 75 )
|
||||
{
|
||||
if ( dif < 0 )
|
||||
{
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||
|
||||
VectorScale( forward, scale, forward );
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "tusken/shot", cent->lerpOrigin, forward );
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------
|
||||
FX_TuskenShotWeaponHitWall
|
||||
-------------------------
|
||||
*/
|
||||
void FX_TuskenShotWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||
{
|
||||
theFxScheduler.PlayEffect( "tusken/hitwall", origin, normal );
|
||||
}
|
||||
/*
|
||||
-------------------------
|
||||
FX_TuskenShotWeaponHitPlayer
|
||||
-------------------------
|
||||
*/
|
||||
void FX_TuskenShotWeaponHitPlayer( gentity_t *hit, vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||
{
|
||||
//temporary? just testing out the damage skin stuff -rww
|
||||
if ( hit && hit->client && hit->ghoul2.size() )
|
||||
{
|
||||
CG_AddGhoul2Mark(cgs.media.bdecal_burnmark1, flrand(3.5, 4.0), origin, normal, hit->s.number,
|
||||
hit->client->ps.origin, hit->client->renderInfo.legsYaw, hit->ghoul2, hit->s.modelScale, Q_irand(10000, 13000));
|
||||
}
|
||||
|
||||
theFxScheduler.PlayEffect( "tusken/hit", origin, normal );
|
||||
}
|
||||
5
code/cgame/FxParsing.cpp
Normal file
5
code/cgame/FxParsing.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
// this include must remain at the top of every FXxxxx.CPP file
|
||||
#include "common_headers.h"
|
||||
|
||||
|
||||
|
||||
6
code/cgame/FxParsing.h
Normal file
6
code/cgame/FxParsing.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#if !defined(FX_PARSING_H_INC)
|
||||
#define FX_PARSING_H_INC
|
||||
|
||||
|
||||
#endif // FX_PARSING_H
|
||||
2301
code/cgame/FxPrimitives.cpp
Normal file
2301
code/cgame/FxPrimitives.cpp
Normal file
File diff suppressed because it is too large
Load Diff
572
code/cgame/FxPrimitives.h
Normal file
572
code/cgame/FxPrimitives.h
Normal file
@@ -0,0 +1,572 @@
|
||||
|
||||
#if !defined(FX_SYSTEM_H_INC)
|
||||
#include "FxSystem.h"
|
||||
#endif
|
||||
|
||||
#ifndef FX_PRIMITIVES_H_INC
|
||||
#define FX_PRIMITIVES_H_INC
|
||||
|
||||
|
||||
#define MAX_EFFECTS 1200
|
||||
|
||||
|
||||
// Generic group flags, used by parser, then get converted to the appropriate specific flags
|
||||
#define FX_PARM_MASK 0xC // use this to mask off any transition types that use a parm
|
||||
#define FX_GENERIC_MASK 0xF
|
||||
#define FX_LINEAR 0x1
|
||||
#define FX_RAND 0x2
|
||||
#define FX_NONLINEAR 0x4
|
||||
#define FX_WAVE 0x8
|
||||
#define FX_CLAMP 0xC
|
||||
|
||||
// Group flags
|
||||
#define FX_ALPHA_SHIFT 0
|
||||
#define FX_ALPHA_PARM_MASK 0x0000000C
|
||||
#define FX_ALPHA_LINEAR 0x00000001
|
||||
#define FX_ALPHA_RAND 0x00000002
|
||||
#define FX_ALPHA_NONLINEAR 0x00000004
|
||||
#define FX_ALPHA_WAVE 0x00000008
|
||||
#define FX_ALPHA_CLAMP 0x0000000C
|
||||
|
||||
#define FX_RGB_SHIFT 4
|
||||
#define FX_RGB_PARM_MASK 0x000000C0
|
||||
#define FX_RGB_LINEAR 0x00000010
|
||||
#define FX_RGB_RAND 0x00000020
|
||||
#define FX_RGB_NONLINEAR 0x00000040
|
||||
#define FX_RGB_WAVE 0x00000080
|
||||
#define FX_RGB_CLAMP 0x000000C0
|
||||
|
||||
#define FX_SIZE_SHIFT 8
|
||||
#define FX_SIZE_PARM_MASK 0x00000C00
|
||||
#define FX_SIZE_LINEAR 0x00000100
|
||||
#define FX_SIZE_RAND 0x00000200
|
||||
#define FX_SIZE_NONLINEAR 0x00000400
|
||||
#define FX_SIZE_WAVE 0x00000800
|
||||
#define FX_SIZE_CLAMP 0x00000C00
|
||||
|
||||
#define FX_LENGTH_SHIFT 12
|
||||
#define FX_LENGTH_PARM_MASK 0x0000C000
|
||||
#define FX_LENGTH_LINEAR 0x00001000
|
||||
#define FX_LENGTH_RAND 0x00002000
|
||||
#define FX_LENGTH_NONLINEAR 0x00004000
|
||||
#define FX_LENGTH_WAVE 0x00008000
|
||||
#define FX_LENGTH_CLAMP 0x0000C000
|
||||
|
||||
#define FX_SIZE2_SHIFT 16
|
||||
#define FX_SIZE2_PARM_MASK 0x000C0000
|
||||
#define FX_SIZE2_LINEAR 0x00010000
|
||||
#define FX_SIZE2_RAND 0x00020000
|
||||
#define FX_SIZE2_NONLINEAR 0x00040000
|
||||
#define FX_SIZE2_WAVE 0x00080000
|
||||
#define FX_SIZE2_CLAMP 0x000C0000
|
||||
|
||||
// Feature flags
|
||||
#define FX_DEPTH_HACK 0x00100000
|
||||
#define FX_RELATIVE 0x00200000
|
||||
#define FX_SET_SHADER_TIME 0x00400000 // by having the effects system set the shader time, we can make animating textures start at the correct time
|
||||
#define FX_EXPENSIVE_PHYSICS 0x00800000
|
||||
|
||||
//rww - g2-related flags (these can slow things down significantly, use sparingly)
|
||||
//These should be used only with particles/decals as they steal flags used by cylinders.
|
||||
#define FX_GHOUL2_TRACE 0x00020000 //use in conjunction with particles - actually do full ghoul2 traces for physics collision against entities with a ghoul2 instance
|
||||
//shared FX_SIZE2_RAND (used only with cylinders)
|
||||
#define FX_GHOUL2_DECALS 0x00040000 //use in conjunction with decals - can project decal as a ghoul2 gore skin object onto ghoul2 models
|
||||
//shared FX_SIZE2_NONLINEAR (used only with cylinders)
|
||||
|
||||
#define FX_ATTACHED_MODEL 0x01000000
|
||||
|
||||
#define FX_APPLY_PHYSICS 0x02000000
|
||||
#define FX_USE_BBOX 0x04000000 // can make physics more accurate at the expense of speed
|
||||
|
||||
#define FX_USE_ALPHA 0x08000000 // the FX system actually uses RGB to do fades, but this will override that
|
||||
// and cause it to fill in the alpha.
|
||||
|
||||
#define FX_EMIT_FX 0x10000000 // emitters technically don't have to emit stuff, but when they do
|
||||
// this flag needs to be set
|
||||
#define FX_DEATH_RUNS_FX 0x20000000 // Normal death triggers effect, but not kill_on_impact
|
||||
#define FX_KILL_ON_IMPACT 0x40000000 // works just like it says, but only when physics are on.
|
||||
#define FX_IMPACT_RUNS_FX 0x80000000 // an effect can call another effect when it hits something.
|
||||
|
||||
// Lightning flags, duplicates of existing flags, but lightning doesn't use those flags in that context...and nothing will ever use these in this context..so we are safe.
|
||||
#define FX_TAPER 0x01000000 // tapers as it moves towards its endpoint
|
||||
#define FX_BRANCH 0x02000000 // enables lightning branching
|
||||
#define FX_GROW 0x04000000 // lightning grows from start point to end point over the course of its life
|
||||
|
||||
//------------------------------
|
||||
class CEffect
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mOrigin1;
|
||||
|
||||
int mTimeStart;
|
||||
int mTimeEnd;
|
||||
|
||||
unsigned int mFlags;
|
||||
|
||||
// Size of our object, useful for things that have physics
|
||||
vec3_t mMin;
|
||||
vec3_t mMax;
|
||||
|
||||
int mImpactFxID; // if we have an impact event, we may have to call an effect
|
||||
int mDeathFxID; // if we have a death event, we may have to call an effect
|
||||
|
||||
refEntity_t mRefEnt;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CEffect() { memset( &mRefEnt, 0, sizeof( refEntity_t )); }
|
||||
virtual ~CEffect() {}
|
||||
virtual void Die() {}
|
||||
|
||||
virtual bool Update()
|
||||
{ // Game pausing can cause dumb time things to happen, so kill the effect in this instance
|
||||
if ( mTimeStart > theFxHelper.mTime ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void SetSTScale(float s,float t) { mRefEnt.shaderTexCoord[0]=s;mRefEnt.shaderTexCoord[1]=t;}
|
||||
|
||||
inline void SetMin( const vec3_t min ) { if(min){VectorCopy(min,mMin);}else{VectorClear(mMin);} }
|
||||
inline void SetMax( const vec3_t max ) { if(max){VectorCopy(max,mMax);}else{VectorClear(mMax);} }
|
||||
inline void SetFlags( int flags ) { mFlags = flags; }
|
||||
inline void AddFlags( int flags ) { mFlags |= flags; }
|
||||
inline void ClearFlags( int flags ) { mFlags &= ~flags; }
|
||||
inline void SetOrigin1( const vec3_t org ) { if(org){VectorCopy(org,mOrigin1);}else{VectorClear(mOrigin1);} }
|
||||
inline void SetTimeStart( int time ) { mTimeStart = time; if (mFlags&FX_SET_SHADER_TIME) { mRefEnt.shaderTime = cg.time * 0.001f; }}
|
||||
inline void SetTimeEnd( int time ) { mTimeEnd = time; }
|
||||
inline void SetImpactFxID( int id ) { mImpactFxID = id; }
|
||||
inline void SetDeathFxID( int id ) { mDeathFxID = id; }
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------
|
||||
// This class is kind of an exception to the "rule".
|
||||
// For now it exists only for allowing an easy way
|
||||
// to get the saber slash trails rendered.
|
||||
//---------------------------------------------------
|
||||
class CTrail : public CEffect
|
||||
{
|
||||
// This is such a specific case thing, just grant public access to the goods.
|
||||
protected:
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
|
||||
// very specifc case, we can modulate the color and the alpha
|
||||
vec3_t rgb;
|
||||
vec3_t destrgb;
|
||||
vec3_t curRGB;
|
||||
|
||||
float alpha;
|
||||
float destAlpha;
|
||||
float curAlpha;
|
||||
|
||||
// this is a very specific case thing...allow interpolating the st coords so we can map the texture
|
||||
// properly as this segement progresses through it's life
|
||||
float ST[2];
|
||||
float destST[2];
|
||||
float curST[2];
|
||||
|
||||
} TVert;
|
||||
|
||||
TVert mVerts[4];
|
||||
qhandle_t mShader;
|
||||
|
||||
|
||||
CTrail() {};
|
||||
virtual ~CTrail() {};
|
||||
|
||||
virtual bool Update();
|
||||
};
|
||||
|
||||
|
||||
//------------------------------
|
||||
class CLight : public CEffect
|
||||
{
|
||||
protected:
|
||||
|
||||
float mSizeStart;
|
||||
float mSizeEnd;
|
||||
float mSizeParm;
|
||||
|
||||
vec3_t mRGBStart;
|
||||
vec3_t mRGBEnd;
|
||||
float mRGBParm;
|
||||
|
||||
|
||||
void UpdateSize();
|
||||
void UpdateRGB();
|
||||
|
||||
void Draw()
|
||||
{
|
||||
theFxHelper.AddLightToScene( mOrigin1, mRefEnt.radius,
|
||||
mRefEnt.lightingOrigin[0], mRefEnt.lightingOrigin[1], mRefEnt.lightingOrigin[2] );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
CLight() {}
|
||||
virtual ~CLight() {}
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetSizeStart( float sz ) { mSizeStart = sz; }
|
||||
inline void SetSizeEnd( float sz ) { mSizeEnd = sz; }
|
||||
inline void SetSizeParm( float parm ) { mSizeParm = parm; }
|
||||
|
||||
inline void SetRGBStart( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBStart);}else{VectorClear(mRGBStart);} }
|
||||
inline void SetRGBEnd( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBEnd);}else{VectorClear(mRGBEnd);} }
|
||||
inline void SetRGBParm( float parm ) { mRGBParm = parm; }
|
||||
};
|
||||
|
||||
//------------------------------
|
||||
class CFlash : public CLight
|
||||
{
|
||||
protected:
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
CFlash() {}
|
||||
virtual ~CFlash() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetShader( qhandle_t sh )
|
||||
{ assert(sh);
|
||||
mRefEnt.customShader = sh;
|
||||
}
|
||||
void Init( void );
|
||||
};
|
||||
|
||||
//------------------------------
|
||||
class CParticle : public CEffect
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mOrgOffset;
|
||||
|
||||
vec3_t mVel;
|
||||
vec3_t mAccel;
|
||||
float mGravity;
|
||||
|
||||
float mSizeStart;
|
||||
float mSizeEnd;
|
||||
float mSizeParm;
|
||||
|
||||
vec3_t mRGBStart;
|
||||
vec3_t mRGBEnd;
|
||||
float mRGBParm;
|
||||
|
||||
float mAlphaStart;
|
||||
float mAlphaEnd;
|
||||
float mAlphaParm;
|
||||
|
||||
float mRotationDelta;
|
||||
float mElasticity;
|
||||
|
||||
short mClientID;
|
||||
char mModelNum;
|
||||
char mBoltNum;
|
||||
|
||||
bool UpdateOrigin();
|
||||
void UpdateVelocity() {VectorMA( mVel, theFxHelper.mFloatFrameTime, mAccel, mVel ); }
|
||||
|
||||
void UpdateSize();
|
||||
void UpdateRGB();
|
||||
void UpdateAlpha();
|
||||
void UpdateRotation() { mRefEnt.rotation += theFxHelper.mFrameTime * 0.01f * mRotationDelta; }
|
||||
|
||||
bool Cull();
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
inline CParticle() { mRefEnt.reType = RT_SPRITE; mClientID = -1; mModelNum = -1; mBoltNum = -1; }
|
||||
virtual ~CParticle() {}
|
||||
|
||||
virtual void Die();
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetShader( qhandle_t sh ) { mRefEnt.customShader = sh;}
|
||||
|
||||
inline void SetOrgOffset( const vec3_t o ) { if(o){VectorCopy(o,mOrgOffset);}else{VectorClear(mOrgOffset);}}
|
||||
inline void SetVel( const vec3_t vel ) { if(vel){VectorCopy(vel,mVel);}else{VectorClear(mVel);} }
|
||||
inline void SetAccel( const vec3_t ac ) { if(ac){VectorCopy(ac,mAccel);}else{VectorClear(mAccel);} }
|
||||
inline void SetGravity( float grav ) { mGravity = grav; }
|
||||
|
||||
inline void SetSizeStart( float sz ) { mSizeStart = sz; }
|
||||
inline void SetSizeEnd( float sz ) { mSizeEnd = sz; }
|
||||
inline void SetSizeParm( float parm ) { mSizeParm = parm; }
|
||||
|
||||
inline void SetRGBStart( const vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBStart);}else{VectorClear(mRGBStart);} }
|
||||
inline void SetRGBEnd( const vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBEnd);}else{VectorClear(mRGBEnd);} }
|
||||
inline void SetRGBParm( float parm ) { mRGBParm = parm; }
|
||||
|
||||
inline void SetAlphaStart( float al ) { mAlphaStart = al; }
|
||||
inline void SetAlphaEnd( float al ) { mAlphaEnd = al; }
|
||||
inline void SetAlphaParm( float parm ) { mAlphaParm = parm; }
|
||||
|
||||
inline void SetRotation( float rot ) { mRefEnt.rotation = rot; }
|
||||
inline void SetRotationDelta( float rot ) { mRotationDelta = rot; }
|
||||
inline void SetElasticity( float el ) { mElasticity = el; }
|
||||
|
||||
inline void SetClient( int clientID, int modelNum = -1, int boltNum = -1 ) {mClientID = clientID; mModelNum = modelNum; mBoltNum = boltNum; }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------
|
||||
class CLine : public CParticle
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mOrigin2;
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
CLine() { mRefEnt.reType = RT_LINE;}
|
||||
virtual ~CLine() {}
|
||||
virtual void Die() {}
|
||||
virtual bool Update();
|
||||
|
||||
|
||||
inline void SetOrigin2( const vec3_t org2 ) { VectorCopy( org2, mOrigin2 ); }
|
||||
};
|
||||
|
||||
//------------------------------
|
||||
class CBezier : public CLine
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mControl1;
|
||||
vec3_t mControl1Vel;
|
||||
|
||||
vec3_t mControl2;
|
||||
vec3_t mControl2Vel;
|
||||
|
||||
bool mInit;
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
CBezier(){ mInit = false; }
|
||||
virtual ~CBezier() {}
|
||||
virtual void Die() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
void DrawSegment( vec3_t start, vec3_t end, float texcoord1, float texcoord2 );
|
||||
|
||||
inline void SetControlPoints( const vec3_t ctrl1, const vec3_t ctrl2 ) { VectorCopy( ctrl1, mControl1 ); VectorCopy( ctrl2, mControl2 ); }
|
||||
inline void SetControlVel( const vec3_t ctrl1v, const vec3_t ctrl2v ) { VectorCopy( ctrl1v, mControl1Vel ); VectorCopy( ctrl2v, mControl2Vel ); }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------
|
||||
class CElectricity : public CLine
|
||||
{
|
||||
protected:
|
||||
|
||||
float mChaos;
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
CElectricity() { mRefEnt.reType = RT_ELECTRICITY; }
|
||||
virtual ~CElectricity() {}
|
||||
virtual void Die() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
void Initialize();
|
||||
|
||||
inline void SetChaos( float chaos ) { mChaos = chaos; }
|
||||
};
|
||||
|
||||
|
||||
// Oriented quad
|
||||
//------------------------------
|
||||
class COrientedParticle : public CParticle
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mNormal;
|
||||
vec3_t mNormalOffset;
|
||||
|
||||
bool Cull();
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
COrientedParticle() { mRefEnt.reType = RT_ORIENTED_QUAD; }
|
||||
virtual ~COrientedParticle() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetNormal( const vec3_t norm ) { VectorCopy( norm, mNormal ); }
|
||||
inline void SetNormalOffset( const vec3_t norm ) { VectorCopy( norm, mNormalOffset ); }
|
||||
};
|
||||
|
||||
//------------------------------
|
||||
class CTail : public CParticle
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mOldOrigin;
|
||||
|
||||
float mLengthStart;
|
||||
float mLengthEnd;
|
||||
float mLengthParm;
|
||||
|
||||
float mLength;
|
||||
|
||||
void UpdateLength();
|
||||
void CalcNewEndpoint();
|
||||
|
||||
void Draw();
|
||||
bool Cull();
|
||||
|
||||
public:
|
||||
|
||||
CTail() { mRefEnt.reType = RT_LINE; }
|
||||
virtual ~CTail() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetLengthStart( float len ) { mLengthStart = len; }
|
||||
inline void SetLengthEnd( float len ) { mLengthEnd = len; }
|
||||
inline void SetLengthParm( float len ) { mLengthParm = len; }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------
|
||||
class CCylinder : public CTail
|
||||
{
|
||||
protected:
|
||||
|
||||
float mSize2Start;
|
||||
float mSize2End;
|
||||
float mSize2Parm;
|
||||
|
||||
void UpdateSize2();
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
CCylinder() { mRefEnt.reType = RT_CYLINDER; }
|
||||
virtual ~CCylinder() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetSize2Start( float sz ) { mSize2Start = sz; }
|
||||
inline void SetSize2End( float sz ) { mSize2End = sz; }
|
||||
inline void SetSize2Parm( float parm ) { mSize2Parm = parm; }
|
||||
|
||||
inline void SetNormal( const vec3_t norm ) { VectorCopy( norm, mRefEnt.axis[0] ); }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------
|
||||
// Emitters are derived from particles because, although they don't draw, any effect called
|
||||
// from them can borrow an initial or ending value from the emitters current alpha, rgb, etc..
|
||||
class CEmitter : public CParticle
|
||||
{
|
||||
protected:
|
||||
|
||||
vec3_t mOldOrigin; // we use these to do some nice
|
||||
vec3_t mLastOrigin; // tricks...
|
||||
vec3_t mOldVelocity; //
|
||||
int mOldTime;
|
||||
|
||||
vec3_t mAngles; // for a rotating thing, using a delta
|
||||
vec3_t mAngleDelta; // as opposed to an end angle is probably much easier
|
||||
|
||||
int mEmitterFxID; // if we have emitter fx, this is our id
|
||||
|
||||
float mDensity; // controls how often emitter chucks an effect
|
||||
float mVariance; // density sloppiness
|
||||
|
||||
void UpdateAngles();
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
CEmitter() {
|
||||
// There may or may not be a model, but if there isn't one,
|
||||
// we just won't bother adding the refEnt in our Draw func
|
||||
mRefEnt.reType = RT_MODEL;
|
||||
}
|
||||
virtual ~CEmitter() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
inline void SetModel( qhandle_t model ) { mRefEnt.hModel = model; }
|
||||
inline void SetAngles( const vec3_t ang ) { if(ang){VectorCopy(ang,mAngles);}else{VectorClear(mAngles);} }
|
||||
inline void SetAngleDelta( const vec3_t ang){ if(ang){VectorCopy(ang,mAngleDelta);}else{VectorClear(mAngleDelta);} }
|
||||
inline void SetEmitterFxID( int id ) { mEmitterFxID = id; }
|
||||
inline void SetDensity( float density ) { mDensity = density; }
|
||||
inline void SetVariance( float var ) { mVariance = var; }
|
||||
inline void SetOldTime( int time ) { mOldTime = time; }
|
||||
inline void SetLastOrg( const vec3_t org ) { if(org){VectorCopy(org,mLastOrigin);}else{VectorClear(mLastOrigin);} }
|
||||
inline void SetLastVel( const vec3_t vel ) { if(vel){VectorCopy(vel,mOldVelocity);}else{VectorClear(mOldVelocity);}}
|
||||
|
||||
};
|
||||
|
||||
// We're getting pretty low level here, not the kind of thing to abuse considering how much overhead this
|
||||
// adds to a SINGLE triangle or quad....
|
||||
// The editor doesn't need to see or do anything with this
|
||||
//------------------------------
|
||||
#define MAX_CPOLY_VERTS 5
|
||||
|
||||
class CPoly : public CParticle
|
||||
{
|
||||
protected:
|
||||
|
||||
int mCount;
|
||||
vec3_t mRotDelta;
|
||||
int mTimeStamp;
|
||||
|
||||
bool Cull();
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
vec3_t mOrg[MAX_CPOLY_VERTS];
|
||||
vec2_t mST[MAX_CPOLY_VERTS];
|
||||
|
||||
float mRot[3][3];
|
||||
int mLastFrameTime;
|
||||
|
||||
|
||||
CPoly() {}
|
||||
virtual ~CPoly() {}
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
void PolyInit();
|
||||
void CalcRotateMatrix();
|
||||
void Rotate();
|
||||
|
||||
inline void SetNumVerts( int c ) { mCount = c; }
|
||||
inline void SetRot( vec3_t r ) { if(r){VectorCopy(r,mRotDelta);}else{VectorClear(mRotDelta);}}
|
||||
inline void SetMotionTimeStamp( int t ) { mTimeStamp = theFxHelper.mTime + t; }
|
||||
inline int GetMotionTimeStamp() { return mTimeStamp; }
|
||||
};
|
||||
|
||||
|
||||
#endif //FX_PRIMITIVES_H_INC
|
||||
2049
code/cgame/FxScheduler.cpp
Normal file
2049
code/cgame/FxScheduler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
497
code/cgame/FxScheduler.h
Normal file
497
code/cgame/FxScheduler.h
Normal file
@@ -0,0 +1,497 @@
|
||||
|
||||
#if !defined(FX_UTIL_H_INC)
|
||||
#include "FxUtil.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "../qcommon/sstring.h"
|
||||
typedef sstring_t fxString_t;
|
||||
|
||||
#if !defined(FX_PARSING_H_INC)
|
||||
#include "FxParsing.h"
|
||||
#endif
|
||||
|
||||
#ifndef FX_SCHEDULER_H_INC
|
||||
#define FX_SCHEDULER_H_INC
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define FX_FILE_PATH "effects"
|
||||
|
||||
#define FX_MAX_TRACE_DIST WORLD_SIZE
|
||||
#define FX_MAX_EFFECTS 150 // how many effects the system can store
|
||||
#define FX_MAX_EFFECT_COMPONENTS 24 // how many primitives an effect can hold, this should be plenty
|
||||
#define FX_MAX_PRIM_NAME 32
|
||||
|
||||
//-----------------------------------------------
|
||||
// These are spawn flags for primitiveTemplates
|
||||
//-----------------------------------------------
|
||||
|
||||
#define FX_ORG_ON_SPHERE 0x00001 // Pretty dang expensive, calculates a point on a sphere/ellipsoid
|
||||
#define FX_AXIS_FROM_SPHERE 0x00002 // Can be used in conjunction with org_on_sphere to cause particles to move out
|
||||
// from the center of the sphere
|
||||
#define FX_ORG_ON_CYLINDER 0x00004 // calculate point on cylinder/disk
|
||||
|
||||
#define FX_ORG2_FROM_TRACE 0x00010
|
||||
#define FX_TRACE_IMPACT_FX 0x00020 // if trace impacts, we should play one of the specified impact fx files
|
||||
#define FX_ORG2_IS_OFFSET 0x00040 // template specified org2 should be the offset from a trace endpos or
|
||||
// passed in org2. You might use this to lend a random flair to the endpos.
|
||||
// Note: this is done pre-trace, so you may have to specify large numbers for this
|
||||
|
||||
#define FX_CHEAP_ORG_CALC 0x00100 // Origin is calculated relative to passed in axis unless this is on.
|
||||
#define FX_CHEAP_ORG2_CALC 0x00200 // Origin2 is calculated relative to passed in axis unless this is on.
|
||||
#define FX_VEL_IS_ABSOLUTE 0x00400 // Velocity isn't relative to passed in axis with this flag on.
|
||||
#define FX_ACCEL_IS_ABSOLUTE 0x00800 // Acceleration isn't relative to passed in axis with this flag on.
|
||||
|
||||
#define FX_RAND_ROT_AROUND_FWD 0x01000 // Randomly rotates up and right around forward vector
|
||||
#define FX_EVEN_DISTRIBUTION 0x02000 // When you have a delay, it normally picks a random time to play. When
|
||||
// this flag is on, it generates an even time distribution
|
||||
#define FX_RGB_COMPONENT_INTERP 0x04000 // Picks a color on the line defined by RGB min & max, default is to pick color in cube defined by min & max
|
||||
|
||||
#define FX_AFFECTED_BY_WIND 0x10000 // we take into account our wind vector when we spawn in
|
||||
|
||||
#define FX_SND_LESS_ATTENUATION 0x20000 // attenuate sounds less
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//
|
||||
// CMediaHandles
|
||||
//
|
||||
// Primitive templates might want to use a list of sounds, shaders
|
||||
// or models to get a bit more variation in their effects.
|
||||
//
|
||||
//-----------------------------------------------------------------
|
||||
class CMediaHandles
|
||||
{
|
||||
private:
|
||||
|
||||
vector<int> mMediaList;
|
||||
|
||||
public:
|
||||
|
||||
void AddHandle( int item ) { mMediaList.push_back( item ); }
|
||||
int GetHandle() { if (mMediaList.size()==0) {return 0;}
|
||||
else {return mMediaList[irand(0,mMediaList.size()-1)];} }
|
||||
|
||||
void operator=(const CMediaHandles &that );
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//
|
||||
// CFxRange
|
||||
//
|
||||
// Primitive templates typically use this class to define each of
|
||||
// its members. This is done to make it easier to create effects
|
||||
// with a desired range of characteristics.
|
||||
//
|
||||
//-----------------------------------------------------------------
|
||||
class CFxRange
|
||||
{
|
||||
private:
|
||||
|
||||
float mMin;
|
||||
float mMax;
|
||||
|
||||
public:
|
||||
|
||||
CFxRange() {mMin=0; mMax=0;}
|
||||
|
||||
inline void SetRange(float min,float max) {mMin=min; mMax=max;}
|
||||
inline void SetMin(float min) {mMin=min;}
|
||||
inline void SetMax(float max) {mMax=max;}
|
||||
|
||||
inline float GetMax() const {return mMax;}
|
||||
inline float GetMin() const {return mMin;}
|
||||
|
||||
inline float GetVal(float percent) const {if(mMin == mMax){return mMin;}
|
||||
return (mMin + (mMax - mMin) * percent);}
|
||||
inline float GetVal() const {if(mMin == mMax){return mMin;}
|
||||
return flrand(mMin, mMax);}
|
||||
inline int GetRoundedVal() const {if(mMin == mMax){return mMin;}
|
||||
return (int)(flrand(mMin, mMax) + 0.5f);}
|
||||
|
||||
inline void ForceRange(float min,float max) {if(mMin < min){mMin=min;} if(mMin > max){mMin=max;}
|
||||
if(mMax < min){mMax=min;} if(mMax > max){mMax=max;}}
|
||||
inline void Sort() {if(mMin > mMax){float temp = mMin; mMin=mMax;mMax=temp;}}
|
||||
void operator=(const CFxRange &that) {mMin=that.mMin; mMax=that.mMax;}
|
||||
|
||||
bool operator==(const CFxRange &rhs) const { return ((mMin == rhs.mMin) &&
|
||||
(mMax == rhs.mMax)); }
|
||||
};
|
||||
|
||||
|
||||
//----------------------------
|
||||
// Supported primitive types
|
||||
//----------------------------
|
||||
|
||||
enum EPrimType
|
||||
{
|
||||
None = 0,
|
||||
Particle, // sprite
|
||||
Line,
|
||||
Tail, // comet-like tail thing
|
||||
Cylinder,
|
||||
Emitter, // emits effects as it moves, can also attach a chunk
|
||||
Sound,
|
||||
#ifdef _IMMERSION
|
||||
Force,
|
||||
#endif // _IMMERSION
|
||||
Decal, // projected onto architecture
|
||||
OrientedParticle,
|
||||
Electricity,
|
||||
FxRunner,
|
||||
Light,
|
||||
CameraShake,
|
||||
ScreenFlash
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//
|
||||
// CPrimitiveTemplate
|
||||
//
|
||||
// The primitive template is used to spawn 1 or more fx primitives
|
||||
// with the range of characteristics defined by the template.
|
||||
//
|
||||
// As such, I just made this one huge shared class knowing that
|
||||
// there won't be many of them in memory at once, and we won't
|
||||
// be dynamically creating and deleting them mid-game. Also,
|
||||
// note that not every primitive type will use all of these fields.
|
||||
//
|
||||
//-----------------------------------------------------------------
|
||||
class CPrimitiveTemplate
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// These kinds of things should not even be allowed to be accessed publicly
|
||||
bool mCopy;
|
||||
int mRefCount; // For a copy of a primitive...when we figure out how many items we want to spawn,
|
||||
// we'll store that here and then decrement us for each we actually spawn. When we
|
||||
// hit zero, we are no longer used and so we can just free ourselves
|
||||
|
||||
char mName[FX_MAX_PRIM_NAME];
|
||||
|
||||
EPrimType mType;
|
||||
|
||||
CFxRange mSpawnDelay;
|
||||
CFxRange mSpawnCount;
|
||||
CFxRange mLife;
|
||||
int mCullRange;
|
||||
|
||||
CMediaHandles mMediaHandles;
|
||||
CMediaHandles mImpactFxHandles;
|
||||
CMediaHandles mDeathFxHandles;
|
||||
CMediaHandles mEmitterFxHandles;
|
||||
CMediaHandles mPlayFxHandles;
|
||||
|
||||
int mFlags; // These need to get passed on to the primitive
|
||||
int mSpawnFlags; // These are only used to control spawning, but never get passed to prims.
|
||||
|
||||
vec3_t mMin;
|
||||
vec3_t mMax;
|
||||
|
||||
CFxRange mOrigin1X;
|
||||
CFxRange mOrigin1Y;
|
||||
CFxRange mOrigin1Z;
|
||||
|
||||
CFxRange mOrigin2X;
|
||||
CFxRange mOrigin2Y;
|
||||
CFxRange mOrigin2Z;
|
||||
|
||||
CFxRange mRadius; // spawn on sphere/ellipse/disk stuff.
|
||||
CFxRange mHeight;
|
||||
|
||||
CFxRange mRotation;
|
||||
CFxRange mRotationDelta;
|
||||
|
||||
CFxRange mAngle1;
|
||||
CFxRange mAngle2;
|
||||
CFxRange mAngle3;
|
||||
|
||||
CFxRange mAngle1Delta;
|
||||
CFxRange mAngle2Delta;
|
||||
CFxRange mAngle3Delta;
|
||||
|
||||
CFxRange mVelX;
|
||||
CFxRange mVelY;
|
||||
CFxRange mVelZ;
|
||||
|
||||
CFxRange mAccelX;
|
||||
CFxRange mAccelY;
|
||||
CFxRange mAccelZ;
|
||||
|
||||
CFxRange mGravity;
|
||||
|
||||
CFxRange mDensity;
|
||||
CFxRange mVariance;
|
||||
|
||||
CFxRange mRedStart;
|
||||
CFxRange mGreenStart;
|
||||
CFxRange mBlueStart;
|
||||
|
||||
CFxRange mRedEnd;
|
||||
CFxRange mGreenEnd;
|
||||
CFxRange mBlueEnd;
|
||||
|
||||
CFxRange mRGBParm;
|
||||
|
||||
CFxRange mAlphaStart;
|
||||
CFxRange mAlphaEnd;
|
||||
CFxRange mAlphaParm;
|
||||
|
||||
CFxRange mSizeStart;
|
||||
CFxRange mSizeEnd;
|
||||
CFxRange mSizeParm;
|
||||
|
||||
CFxRange mSize2Start;
|
||||
CFxRange mSize2End;
|
||||
CFxRange mSize2Parm;
|
||||
|
||||
CFxRange mLengthStart;
|
||||
CFxRange mLengthEnd;
|
||||
CFxRange mLengthParm;
|
||||
|
||||
CFxRange mTexCoordS;
|
||||
CFxRange mTexCoordT;
|
||||
|
||||
CFxRange mElasticity;
|
||||
|
||||
|
||||
// Lower level parsing utilities
|
||||
bool ParseVector( const char *val, vec3_t min, vec3_t max );
|
||||
bool ParseFloat( const char *val, float *min, float *max );
|
||||
bool ParseGroupFlags( const char *val, int *flags );
|
||||
|
||||
// Base key processing
|
||||
// Note that these all have their own parse functions in case it becomes important to do certain kinds
|
||||
// of validation specific to that type.
|
||||
bool ParseMin( const char *val );
|
||||
bool ParseMax( const char *val );
|
||||
bool ParseDelay( const char *val );
|
||||
bool ParseCount( const char *val );
|
||||
bool ParseLife( const char *val );
|
||||
bool ParseElasticity( const char *val );
|
||||
bool ParseFlags( const char *val );
|
||||
bool ParseSpawnFlags( const char *val );
|
||||
|
||||
bool ParseOrigin1( const char *val );
|
||||
bool ParseOrigin2( const char *val );
|
||||
bool ParseRadius( const char *val );
|
||||
bool ParseHeight( const char *val );
|
||||
bool ParseRotation( const char *val );
|
||||
bool ParseRotationDelta( const char *val );
|
||||
bool ParseAngle( const char *val );
|
||||
bool ParseAngleDelta( const char *val );
|
||||
bool ParseVelocity( const char *val );
|
||||
bool ParseAcceleration( const char *val );
|
||||
bool ParseGravity( const char *val );
|
||||
bool ParseDensity( const char *val );
|
||||
bool ParseVariance( const char *val );
|
||||
|
||||
// Group type processing
|
||||
bool ParseRGB( CGPGroup *grp );
|
||||
bool ParseAlpha( CGPGroup *grp );
|
||||
bool ParseSize( CGPGroup *grp );
|
||||
bool ParseSize2( CGPGroup *grp );
|
||||
bool ParseLength( CGPGroup *grp );
|
||||
|
||||
bool ParseModels( CGPValue *grp );
|
||||
bool ParseShaders( CGPValue *grp );
|
||||
bool ParseSounds( CGPValue *grp );
|
||||
#ifdef _IMMERSION
|
||||
bool ParseForces( CGPValue *grp );
|
||||
#endif // _IMMERSION
|
||||
|
||||
bool ParseImpactFxStrings( CGPValue *grp );
|
||||
bool ParseDeathFxStrings( CGPValue *grp );
|
||||
bool ParseEmitterFxStrings( CGPValue *grp );
|
||||
bool ParsePlayFxStrings( CGPValue *grp );
|
||||
|
||||
// Group keys
|
||||
bool ParseRGBStart( const char *val );
|
||||
bool ParseRGBEnd( const char *val );
|
||||
bool ParseRGBParm( const char *val );
|
||||
bool ParseRGBFlags( const char *val );
|
||||
|
||||
bool ParseAlphaStart( const char *val );
|
||||
bool ParseAlphaEnd( const char *val );
|
||||
bool ParseAlphaParm( const char *val );
|
||||
bool ParseAlphaFlags( const char *val );
|
||||
|
||||
bool ParseSizeStart( const char *val );
|
||||
bool ParseSizeEnd( const char *val );
|
||||
bool ParseSizeParm( const char *val );
|
||||
bool ParseSizeFlags( const char *val );
|
||||
|
||||
bool ParseSize2Start( const char *val );
|
||||
bool ParseSize2End( const char *val );
|
||||
bool ParseSize2Parm( const char *val );
|
||||
bool ParseSize2Flags( const char *val );
|
||||
|
||||
bool ParseLengthStart( const char *val );
|
||||
bool ParseLengthEnd( const char *val );
|
||||
bool ParseLengthParm( const char *val );
|
||||
bool ParseLengthFlags( const char *val );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CPrimitiveTemplate();
|
||||
~CPrimitiveTemplate() {};
|
||||
|
||||
bool ParsePrimitive( CGPGroup *grp );
|
||||
|
||||
void operator=(const CPrimitiveTemplate &that);
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
struct SEffectTemplate;
|
||||
|
||||
// Effects are built of one or more primitives
|
||||
struct SEffectTemplate
|
||||
{
|
||||
bool mInUse;
|
||||
bool mCopy;
|
||||
char mEffectName[MAX_QPATH]; // is this extraneous??
|
||||
int mPrimitiveCount;
|
||||
int mRepeatDelay;
|
||||
CPrimitiveTemplate *mPrimitives[FX_MAX_EFFECT_COMPONENTS];
|
||||
|
||||
bool operator == (const char * name) const
|
||||
{
|
||||
return !stricmp( mEffectName, name );
|
||||
}
|
||||
void operator=(const SEffectTemplate &that);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//
|
||||
// CFxScheduler
|
||||
//
|
||||
// The scheduler not only handles requests to play an effect, it
|
||||
// tracks the request throughout its life if necessary, creating
|
||||
// any of the delayed components as needed.
|
||||
//
|
||||
//-----------------------------------------------------------------
|
||||
// needs to be in global space now (loadsave stuff)
|
||||
|
||||
#define MAX_LOOPED_FX 32
|
||||
// We hold a looped effect here
|
||||
struct SLoopedEffect
|
||||
{
|
||||
int mId; // effect id
|
||||
int mBoltInfo; // used to determine which bolt on the ghoul2 model we should be attaching this effect to
|
||||
int mNextTime; //time to render again
|
||||
int mLoopStopTime; //time to die
|
||||
bool mPortalEffect; // rww - render this before skyportals, and not in the normal world view.
|
||||
bool mIsRelative; // bolt this puppy on keep it updated
|
||||
};
|
||||
|
||||
class CFxScheduler
|
||||
{
|
||||
private:
|
||||
|
||||
// We hold a scheduled effect here
|
||||
struct SScheduledEffect
|
||||
{
|
||||
CPrimitiveTemplate *mpTemplate; // primitive template
|
||||
int mStartTime;
|
||||
char mModelNum; // uset to determine which ghoul2 model we want to bolt this effect to
|
||||
char mBoltNum; // used to determine which bolt on the ghoul2 model we should be attaching this effect to
|
||||
short mEntNum; // used to determine which entity this ghoul model is attached to.
|
||||
short mClientID; // FIXME: redundant. this is used for muzzle bolts, merge into normal bolting
|
||||
bool mPortalEffect; // rww - render this before skyportals, and not in the normal world view.
|
||||
bool mIsRelative; // bolt this puppy on keep it updated
|
||||
vec3_t mOrigin;
|
||||
vec3_t mAxis[3];
|
||||
|
||||
bool operator <= (const int time) const
|
||||
{
|
||||
return mStartTime <= time;
|
||||
}
|
||||
};
|
||||
|
||||
/* Looped Effects get stored and reschedule at mRepeatRate */
|
||||
|
||||
// must be in sync with gLoopedEffectArray[MAX_LOOPED_FX]!
|
||||
//
|
||||
SLoopedEffect mLoopedEffectArray[MAX_LOOPED_FX];
|
||||
|
||||
int ScheduleLoopedEffect( int id, int boltInfo, bool isPortal, int iLoopTime, bool isRelative );
|
||||
void AddLoopedEffects( );
|
||||
|
||||
|
||||
// this makes looking up the index based on the string name much easier
|
||||
typedef map<fxString_t, int> TEffectID;
|
||||
|
||||
typedef list<SScheduledEffect*> TScheduledEffect;
|
||||
|
||||
// Effects
|
||||
SEffectTemplate mEffectTemplates[FX_MAX_EFFECTS];
|
||||
TEffectID mEffectIDs; // if you only have the unique effect name, you'll have to use this to get the ID.
|
||||
|
||||
// List of scheduled effects that will need to be created at the correct time.
|
||||
TScheduledEffect mFxSchedule;
|
||||
|
||||
|
||||
// Private function prototypes
|
||||
SEffectTemplate *GetNewEffectTemplate( int *id, const char *file );
|
||||
|
||||
void AddPrimitiveToEffect( SEffectTemplate *fx, CPrimitiveTemplate *prim );
|
||||
int ParseEffect( const char *file, CGPGroup *base );
|
||||
|
||||
void CreateEffect( CPrimitiveTemplate *fx, const vec3_t origin, vec3_t axis[3], int lateTime, int clientID = -1, int modelNum = -1, int boltNum = -1 );
|
||||
void CreateEffect( CPrimitiveTemplate *fx, int clientID, int lateTime );
|
||||
|
||||
public:
|
||||
|
||||
CFxScheduler();
|
||||
|
||||
void LoadSave_Read();
|
||||
void LoadSave_Write();
|
||||
void FX_CopeWithAnyLoadedSaveGames();
|
||||
|
||||
int RegisterEffect( const char *file, bool bHasCorrectPath = false ); // handles pre-caching
|
||||
|
||||
|
||||
// Nasty overloaded madness
|
||||
void PlayEffect( int id, vec3_t org, bool isPortal = false ); // uses a default up axis
|
||||
void PlayEffect( int id, vec3_t org, vec3_t fwd, bool isPortal = false ); // builds arbitrary perp. right vector, does a cross product to define up
|
||||
void PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int boltInfo=-1, const int entNum=-1, bool isPortal = false, int iLoopTime = false, bool isRelative = false );
|
||||
void PlayEffect( const char *file, vec3_t org, bool isPortal = false ); // uses a default up axis
|
||||
void PlayEffect( const char *file, vec3_t org, vec3_t fwd, bool isPortal = false ); // builds arbitrary perp. right vector, does a cross product to define up
|
||||
void PlayEffect( const char *file, vec3_t origin, vec3_t axis[3], const int boltInfo, const int entNum, bool isPortal = false, int iLoopTime = false, bool isRelative = false );
|
||||
|
||||
//for muzzle
|
||||
void PlayEffect( const char *file, int clientID, bool isPortal = false );
|
||||
|
||||
#ifdef _IMMERSION // for ff-system
|
||||
void PlayEffect( int id, int clientNum, vec3_t org, vec3_t fwd, bool isPortal = false );
|
||||
void PlayEffect( const char *file, int clientNum, vec3_t origin, vec3_t forward, bool isPortal = false );
|
||||
#endif // _IMMERSION
|
||||
|
||||
void StopEffect( const char *file, const int boltInfo, bool isPortal = false ); //find a scheduled Looping effect with these parms and kill it
|
||||
|
||||
void AddScheduledEffects( bool portal ); // call once per CGame frame [rww ammendment - twice now actually, but first only renders portal effects]
|
||||
|
||||
int NumScheduledFx() { return mFxSchedule.size(); }
|
||||
void Clean(bool bRemoveTemplates = true, int idToPreserve = 0); // clean out the system
|
||||
|
||||
// FX Override functions
|
||||
SEffectTemplate *GetEffectCopy( int fxHandle, int *newHandle );
|
||||
SEffectTemplate *GetEffectCopy( const char *file, int *newHandle );
|
||||
|
||||
CPrimitiveTemplate *GetPrimitiveCopy( SEffectTemplate *effectCopy, const char *componentName );
|
||||
};
|
||||
|
||||
//-------------------
|
||||
// The one and only
|
||||
//-------------------
|
||||
extern CFxScheduler theFxScheduler;
|
||||
|
||||
|
||||
#endif // FX_SCHEDULER_H_INC
|
||||
215
code/cgame/FxSystem.cpp
Normal file
215
code/cgame/FxSystem.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
// this include must remain at the top of every FXxxxx.CPP file
|
||||
#include "common_headers.h"
|
||||
|
||||
#if !defined(FX_SCHEDULER_H_INC)
|
||||
#include "FxScheduler.h"
|
||||
#endif
|
||||
|
||||
#include "cg_media.h" //for cgs.model_draw for G2
|
||||
|
||||
extern vmCvar_t fx_debug;
|
||||
extern vmCvar_t fx_freeze;
|
||||
|
||||
extern void CG_ExplosionEffects( vec3_t origin, float intensity, int radius, int time );
|
||||
|
||||
// Stuff for the FxHelper
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::Init()
|
||||
{
|
||||
mTime = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::Print( const char *msg, ... )
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start( argptr, msg );
|
||||
vsprintf( text, msg, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
gi.Printf( text );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::AdjustTime( int frameTime )
|
||||
{
|
||||
if ( fx_freeze.integer || ( frameTime <= 0 ))
|
||||
{
|
||||
// Allow no time progression when we are paused.
|
||||
mFrameTime = 0;
|
||||
mFloatFrameTime = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !cg_paused.integer )
|
||||
{
|
||||
if ( frameTime > 300 ) // hack for returning from paused and time bursts
|
||||
{
|
||||
frameTime = 300;
|
||||
}
|
||||
|
||||
mFrameTime = frameTime;
|
||||
mFloatFrameTime = mFrameTime * 0.001f;
|
||||
mTime += mFrameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
int SFxHelper::OpenFile( const char *file, fileHandle_t *fh, int mode )
|
||||
{
|
||||
// char path[256];
|
||||
|
||||
// sprintf( path, "%s/%s", FX_FILE_PATH, file );
|
||||
return cgi_FS_FOpenFile( file, fh, FS_READ );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
int SFxHelper::ReadFile( void *data, int len, fileHandle_t fh )
|
||||
{
|
||||
return cgi_FS_Read( data, len, fh );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::CloseFile( fileHandle_t fh )
|
||||
{
|
||||
cgi_FS_FCloseFile( fh );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::PlaySound( const vec3_t org, int entityNum, int entchannel, int sfxHandle )
|
||||
{
|
||||
cgi_S_StartSound( org, entityNum, entchannel, sfxHandle );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::PlayLocalSound( int sfxHandle, int channelNum )
|
||||
{
|
||||
cgi_S_StartLocalSound(sfxHandle, channelNum);
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max,
|
||||
vec3_t end, int skipEntNum, int flags )
|
||||
{
|
||||
CG_Trace( tr, start, min, max, end, skipEntNum, flags );
|
||||
}
|
||||
|
||||
void SFxHelper::G2Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max,
|
||||
vec3_t end, int skipEntNum, int flags )
|
||||
{
|
||||
//CG_Trace( tr, start, min, max, end, skipEntNum, flags, G2_COLLIDE );
|
||||
gi.trace(tr, start, NULL, NULL, end, skipEntNum, flags, G2_COLLIDE);
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::AddFxToScene( refEntity_t *ent )
|
||||
{
|
||||
cgi_R_AddRefEntityToScene( ent );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
int SFxHelper::RegisterShader( const char *shader )
|
||||
{
|
||||
return cgi_R_RegisterShader( shader );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
int SFxHelper::RegisterSound( const char *sound )
|
||||
{
|
||||
return cgi_S_RegisterSound( sound );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
int SFxHelper::RegisterModel( const char *model )
|
||||
{
|
||||
return cgi_R_RegisterModel( model );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::AddLightToScene( vec3_t org, float radius, float red, float green, float blue )
|
||||
{
|
||||
cgi_R_AddLightToScene( org, radius, red, green, blue );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::AddPolyToScene( int shader, int count, polyVert_t *verts )
|
||||
{
|
||||
cgi_R_AddPolyToScene( shader, count, verts );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::CameraShake( vec3_t origin, float intensity, int radius, int time )
|
||||
{
|
||||
CG_ExplosionEffects( origin, intensity, radius, time );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
int SFxHelper::GetOriginAxisFromBolt(const centity_t ¢, int modelNum, int boltNum, vec3_t /*out*/origin, vec3_t /*out*/axis[3])
|
||||
{
|
||||
if ((cg.time-cent.snapShotTime) > 200)
|
||||
{ //you were added more than 200ms ago, so I say you are no longer valid/in our snapshot.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int doesBoltExist;
|
||||
mdxaBone_t boltMatrix;
|
||||
vec3_t G2Angles = {cent.lerpAngles[0] , cent.lerpAngles[1], cent.lerpAngles[2]};
|
||||
if ( cent.currentState.eType == ET_PLAYER )
|
||||
{//players use cent.renderAngles
|
||||
VectorCopy( cent.renderAngles, G2Angles );
|
||||
|
||||
if ( cent.gent //has a game entity
|
||||
&& cent.gent->s.m_iVehicleNum != 0 //in a vehicle
|
||||
&& cent.gent->m_pVehicle //have a valid vehicle pointer
|
||||
&& cent.gent->m_pVehicle->m_pVehicleInfo->type != VH_FIGHTER //it's not a fighter
|
||||
&& cent.gent->m_pVehicle->m_pVehicleInfo->type != VH_SPEEDER //not a speeder
|
||||
)
|
||||
{
|
||||
G2Angles[PITCH]=0;
|
||||
G2Angles[ROLL] =0;
|
||||
}
|
||||
}
|
||||
|
||||
// go away and get me the bolt position for this frame please
|
||||
doesBoltExist = gi.G2API_GetBoltMatrix(cent.gent->ghoul2, modelNum,
|
||||
boltNum, &boltMatrix, G2Angles,
|
||||
cent.lerpOrigin, cg.time, cgs.model_draw,
|
||||
cent.currentState.modelScale);
|
||||
// set up the axis and origin we need for the actual effect spawning
|
||||
origin[0] = boltMatrix.matrix[0][3];
|
||||
origin[1] = boltMatrix.matrix[1][3];
|
||||
origin[2] = boltMatrix.matrix[2][3];
|
||||
|
||||
axis[1][0] = boltMatrix.matrix[0][0];
|
||||
axis[1][1] = boltMatrix.matrix[1][0];
|
||||
axis[1][2] = boltMatrix.matrix[2][0];
|
||||
|
||||
axis[0][0] = boltMatrix.matrix[0][1];
|
||||
axis[0][1] = boltMatrix.matrix[1][1];
|
||||
axis[0][2] = boltMatrix.matrix[2][1];
|
||||
|
||||
axis[2][0] = boltMatrix.matrix[0][2];
|
||||
axis[2][1] = boltMatrix.matrix[1][2];
|
||||
axis[2][2] = boltMatrix.matrix[2][2];
|
||||
return doesBoltExist;
|
||||
}
|
||||
#ifdef _IMMERSION
|
||||
//------------------------------------------------------
|
||||
ffHandle_t SFxHelper::RegisterForce( const char *force, int channel )
|
||||
{
|
||||
return cgi_FF_Register( force, channel );
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
void SFxHelper::PlayForce( int entityNum, ffHandle_t ff )
|
||||
{
|
||||
cgi_FF_Start( ff, entityNum );
|
||||
}
|
||||
#endif // _IMMERSION
|
||||
84
code/cgame/FxSystem.h
Normal file
84
code/cgame/FxSystem.h
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
#if !defined(CG_LOCAL_H_INC)
|
||||
#include "cg_local.h"
|
||||
#endif
|
||||
|
||||
#ifndef FX_SYSTEM_H_INC
|
||||
#define FX_SYSTEM_H_INC
|
||||
|
||||
|
||||
#define irand Q_irand
|
||||
#define flrand Q_flrand
|
||||
|
||||
extern vmCvar_t fx_debug;
|
||||
extern vmCvar_t fx_freeze;
|
||||
|
||||
inline void Vector2Clear(vec2_t a)
|
||||
{
|
||||
a[0] = 0.0f;
|
||||
a[1] = 0.0f;
|
||||
}
|
||||
|
||||
inline void Vector2Set(vec2_t a,float b,float c)
|
||||
{
|
||||
a[0] = b;
|
||||
a[1] = c;
|
||||
}
|
||||
|
||||
inline void Vector2Copy(vec2_t src,vec2_t dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
}
|
||||
|
||||
|
||||
extern void CG_CalcEntityLerpPositions( centity_t * );
|
||||
|
||||
|
||||
struct SFxHelper
|
||||
{
|
||||
int mTime;
|
||||
int mFrameTime;
|
||||
float mFloatFrameTime;
|
||||
|
||||
void Init();
|
||||
void AdjustTime( int time );
|
||||
|
||||
// These functions are wrapped and used by the fx system in case it makes things a bit more portable
|
||||
void Print( const char *msg, ... );
|
||||
|
||||
// File handling
|
||||
int OpenFile( const char *path, fileHandle_t *fh, int mode );
|
||||
int ReadFile( void *data, int len, fileHandle_t fh );
|
||||
void CloseFile( fileHandle_t fh );
|
||||
|
||||
// Sound
|
||||
void PlaySound( const vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
|
||||
void PlayLocalSound( sfxHandle_t sfx, int channelNum );
|
||||
int RegisterSound( const char *sound );
|
||||
|
||||
#ifdef _IMMERSION
|
||||
void PlayForce( int entityNum, ffHandle_t ff );
|
||||
ffHandle_t RegisterForce( const char *force, int channel );
|
||||
#endif // _IMMERSION
|
||||
//G2
|
||||
int GetOriginAxisFromBolt(const centity_t ¢, int modelNum, int boltNum, vec3_t /*out*/origin, vec3_t /*out*/*axis);
|
||||
|
||||
// Physics/collision
|
||||
void Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags );
|
||||
void G2Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags );
|
||||
|
||||
void AddFxToScene( refEntity_t *ent );
|
||||
void AddLightToScene( vec3_t org, float radius, float red, float green, float blue );
|
||||
|
||||
int RegisterShader( const char *shader );
|
||||
int RegisterModel( const char *model );
|
||||
|
||||
void AddPolyToScene( int shader, int count, polyVert_t *verts );
|
||||
|
||||
void CameraShake( vec3_t origin, float intensity, int radius, int time );
|
||||
};
|
||||
|
||||
extern SFxHelper theFxHelper;
|
||||
|
||||
#endif // FX_SYSTEM_H_INC
|
||||
2370
code/cgame/FxTemplate.cpp
Normal file
2370
code/cgame/FxTemplate.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1400
code/cgame/FxUtil.cpp
Normal file
1400
code/cgame/FxUtil.cpp
Normal file
File diff suppressed because it is too large
Load Diff
130
code/cgame/FxUtil.h
Normal file
130
code/cgame/FxUtil.h
Normal file
@@ -0,0 +1,130 @@
|
||||
|
||||
#if !defined(FX_PRIMITIVES_H_INC)
|
||||
#include "FxPrimitives.h"
|
||||
#endif
|
||||
|
||||
#ifndef FX_UTIL_H_INC
|
||||
#define FX_UTIL_H_INC
|
||||
|
||||
|
||||
bool FX_Free( void ); // ditches all active effects;
|
||||
int FX_Init( void ); // called in CG_Init to purge the fx system.
|
||||
void FX_Add( bool portal ); // called every cgame frame to add all fx into the scene.
|
||||
void FX_Stop( void ); // ditches all active effects without touching the templates.
|
||||
|
||||
bool FX_ActiveFx(void); // returns whether there are any active or scheduled effects
|
||||
|
||||
|
||||
CParticle *FX_AddParticle( int clientID, const vec3_t org, const vec3_t vel, const vec3_t accel, float gravity,
|
||||
float size1, float size2, float sizeParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
const vec3_t rgb1, const vec3_t rgb2, float rgbParm,
|
||||
float rotation, float rotationDelta,
|
||||
const vec3_t min, const vec3_t max, float elasticity,
|
||||
int deathID, int impactID,
|
||||
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||
|
||||
CLine *FX_AddLine( int clientID, vec3_t start, vec3_t end,
|
||||
float size1, float size2, float sizeParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
int killTime, qhandle_t shader, int impactFX_id, int flags, int modelNum = -1, int boltNum = -1 );
|
||||
|
||||
CElectricity *FX_AddElectricity( int clientID, vec3_t start, vec3_t end, float size1, float size2, float sizeParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t sRGB, vec3_t eRGB, float rgbParm,
|
||||
float chaos, int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||
|
||||
CTail *FX_AddTail( int clientID, vec3_t org, vec3_t vel, vec3_t accel,
|
||||
float size1, float size2, float sizeParm,
|
||||
float length1, float length2, float lengthParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
vec3_t min, vec3_t max, float elasticity,
|
||||
int deathID, int impactID,
|
||||
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||
|
||||
CCylinder *FX_AddCylinder( int clientID, vec3_t start, vec3_t normal,
|
||||
float size1s, float size1e, float size1Parm,
|
||||
float size2s, float size2e, float size2Parm,
|
||||
float length1, float length2, float lengthParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||
|
||||
CEmitter *FX_AddEmitter( vec3_t org, vec3_t vel, vec3_t accel,
|
||||
float size1, float size2, float sizeParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
vec3_t angs, vec3_t deltaAngs,
|
||||
vec3_t min, vec3_t max, float elasticity,
|
||||
int deathID, int impactID, int emitterID,
|
||||
float density, float variance,
|
||||
int killTime, qhandle_t model, int flags );
|
||||
|
||||
CLight *FX_AddLight( vec3_t org, float size1, float size2, float sizeParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
int killTime, int flags );
|
||||
|
||||
COrientedParticle *FX_AddOrientedParticle( int clientID, vec3_t org, vec3_t norm, vec3_t vel, vec3_t accel,
|
||||
float size1, float size2, float sizeParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
float rotation, float rotationDelta,
|
||||
vec3_t min, vec3_t max, float bounce,
|
||||
int deathID, int impactID,
|
||||
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||
|
||||
CPoly *FX_AddPoly( vec3_t *verts, vec2_t *st, int numVerts,
|
||||
vec3_t vel, vec3_t accel,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||
vec3_t rotationDelta, float bounce, int motionDelay,
|
||||
int killTime, qhandle_t shader, int flags );
|
||||
|
||||
CFlash *FX_AddFlash( vec3_t origin, vec3_t sRGB, vec3_t eRGB, float rgbParm,
|
||||
int life, qhandle_t shader, int flags );
|
||||
|
||||
|
||||
// Included for backwards compatibility with CHC and for doing quick programmatic effects.
|
||||
void FX_AddSprite( vec3_t origin, vec3_t vel, vec3_t accel,
|
||||
float scale, float dscale,
|
||||
float sAlpha, float eAlpha,
|
||||
float rotation, float bounce,
|
||||
int life, qhandle_t shader, int flags = 0 );
|
||||
|
||||
void FX_AddSprite( vec3_t origin, vec3_t vel, vec3_t accel,
|
||||
float scale, float dscale,
|
||||
float sAlpha, float eAlpha,
|
||||
vec3_t sRGB, vec3_t eRGB,
|
||||
float rotation, float bounce,
|
||||
int life, qhandle_t shader, int flags = 0 );
|
||||
|
||||
void FX_AddLine( vec3_t start, vec3_t end, float stScale,
|
||||
float width, float dwidth,
|
||||
float sAlpha, float eAlpha,
|
||||
int life, qhandle_t shader, int flags = 0 );
|
||||
|
||||
void FX_AddLine( vec3_t start, vec3_t end, float stScale,
|
||||
float width, float dwidth,
|
||||
float sAlpha, float eAlpha,
|
||||
vec3_t sRGB, vec3_t eRGB,
|
||||
int life, qhandle_t shader, int flags = 0 );
|
||||
|
||||
void FX_AddQuad( vec3_t origin, vec3_t normal,
|
||||
vec3_t vel, vec3_t accel,
|
||||
float sradius, float eradius,
|
||||
float salpha, float ealpha,
|
||||
vec3_t sRGB, vec3_t eRGB,
|
||||
float rotation, int life, qhandle_t shader, int flags = 0 );
|
||||
|
||||
CBezier *FX_AddBezier( const vec3_t start, const vec3_t end,
|
||||
const vec3_t control1, const vec3_t control1Vel,
|
||||
const vec3_t control2, const vec3_t control2Vel,
|
||||
float size1, float size2, float sizeParm,
|
||||
float alpha1, float alpha2, float alphaParm,
|
||||
const vec3_t sRGB, const vec3_t eRGB, const float rgbParm,
|
||||
int killTime, qhandle_t shader, int flags = 0 );
|
||||
|
||||
|
||||
#endif //FX_UTIL_H_INC
|
||||
1792
code/cgame/animtable.h
Normal file
1792
code/cgame/animtable.h
Normal file
File diff suppressed because it is too large
Load Diff
2003
code/cgame/cg_camera.cpp
Normal file
2003
code/cgame/cg_camera.cpp
Normal file
File diff suppressed because it is too large
Load Diff
165
code/cgame/cg_camera.h
Normal file
165
code/cgame/cg_camera.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef __CG_CAMERA__
|
||||
#define __CG_CAMERA__
|
||||
|
||||
//
|
||||
// cg_camera.cpp
|
||||
|
||||
#define MAX_CAMERA_GROUP_SUBJECTS 16
|
||||
#define MAX_ACCEL_PER_FRAME 10.0f
|
||||
#define MAX_SHAKE_INTENSITY 16.0f
|
||||
#define CAMERA_DEFAULT_FOV 90.0f
|
||||
#define CAMERA_WIDESCREEN_FOV 120.0f
|
||||
#define BAR_DURATION 1000.0f
|
||||
#define BAR_RATIO 48.0f
|
||||
|
||||
#define CAMERA_MOVING 0x00000001
|
||||
#define CAMERA_PANNING 0x00000002
|
||||
#define CAMERA_ZOOMING 0x00000004
|
||||
#define CAMERA_BAR_FADING 0x00000008
|
||||
#define CAMERA_FADING 0x00000010
|
||||
#define CAMERA_FOLLOWING 0x00000020
|
||||
#define CAMERA_TRACKING 0x00000040
|
||||
#define CAMERA_ROFFING 0x00000080
|
||||
#define CAMERA_SMOOTHING 0x00000100
|
||||
#define CAMERA_CUT 0x00000200
|
||||
#define CAMERA_ACCEL 0x00000400
|
||||
|
||||
// NOTE!! This structure is now saved out as part of the load/save game, so tell me if you put any pointers or
|
||||
// other goofy crap in... -Ste
|
||||
//
|
||||
typedef struct camera_s
|
||||
{
|
||||
//Position / Facing information
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
|
||||
vec3_t origin2;
|
||||
vec3_t angles2;
|
||||
|
||||
//Movement information
|
||||
float move_duration;
|
||||
float move_time;
|
||||
int move_type; //CMOVE_LINEAR, CMOVE_BEZIER
|
||||
|
||||
//FOV information
|
||||
float FOV;
|
||||
float FOV2;
|
||||
float FOV_duration;
|
||||
float FOV_time;
|
||||
float FOV_vel;
|
||||
float FOV_acc;
|
||||
|
||||
//Pan information
|
||||
float pan_time;
|
||||
float pan_duration;
|
||||
|
||||
//Following information
|
||||
char cameraGroup[MAX_QPATH];
|
||||
float cameraGroupZOfs;
|
||||
char cameraGroupTag[MAX_QPATH];
|
||||
vec3_t subjectPos;
|
||||
float subjectSpeed;
|
||||
float followSpeed;
|
||||
qboolean followInitLerp;
|
||||
float distance;
|
||||
qboolean distanceInitLerp;
|
||||
//int aimEntNum;//FIXME: remove
|
||||
|
||||
//Tracking information
|
||||
int trackEntNum;
|
||||
vec3_t trackToOrg;
|
||||
vec3_t moveDir;
|
||||
float speed;
|
||||
float initSpeed;
|
||||
float trackInitLerp;
|
||||
int nextTrackEntUpdateTime;
|
||||
|
||||
//Cine-bar information
|
||||
float bar_alpha;
|
||||
float bar_alpha_source;
|
||||
float bar_alpha_dest;
|
||||
float bar_time;
|
||||
|
||||
float bar_height_source;
|
||||
float bar_height_dest;
|
||||
float bar_height;
|
||||
|
||||
vec4_t fade_color;
|
||||
vec4_t fade_source;
|
||||
vec4_t fade_dest;
|
||||
float fade_time;
|
||||
float fade_duration;
|
||||
|
||||
//State information
|
||||
int info_state;
|
||||
|
||||
//Shake information
|
||||
float shake_intensity;
|
||||
int shake_duration;
|
||||
int shake_start;
|
||||
|
||||
//Smooth information
|
||||
float smooth_intensity;
|
||||
int smooth_duration;
|
||||
int smooth_start;
|
||||
vec3_t smooth_origin;
|
||||
bool smooth_active; // means smooth_origin and angles are valid
|
||||
|
||||
|
||||
// ROFF information
|
||||
char sRoff[MAX_QPATH]; // name of a cached roff
|
||||
int roff_frame; // current frame in the roff data
|
||||
int next_roff_time; // time when it's ok to apply the next roff frame
|
||||
|
||||
#ifdef _XBOX
|
||||
qboolean widescreen;
|
||||
#endif
|
||||
|
||||
} camera_t;
|
||||
|
||||
extern bool in_camera;
|
||||
extern camera_t client_camera;
|
||||
|
||||
void CGCam_Init( void );
|
||||
|
||||
void CGCam_Enable( void );
|
||||
void CGCam_Disable( void );
|
||||
|
||||
#ifdef _XBOX
|
||||
void CGCam_SetWidescreen( qboolean widescreen );
|
||||
#endif
|
||||
|
||||
void CGCam_SetPosition( vec3_t org );
|
||||
void CGCam_SetAngles( vec3_t ang );
|
||||
void CGCam_SetFOV( float FOV );
|
||||
#ifdef _XBOX
|
||||
void CGCam_SetFOV2( float FOV2 );
|
||||
#endif
|
||||
|
||||
void CGCam_Zoom( float FOV, float duration );
|
||||
//void CGCam_Pan( vec3_t dest, float duration );
|
||||
void CGCam_Pan( vec3_t dest, vec3_t panDirection, float duration );
|
||||
void CGCam_Move( vec3_t dest, float duration );
|
||||
void CGCam_Fade( vec4_t source, vec4_t dest, float duration );
|
||||
|
||||
void CGCam_UpdateFade( void );
|
||||
|
||||
void CGCam_Update( void );
|
||||
void CGCam_RenderScene( void );
|
||||
void CGCam_DrawWideScreen( void );
|
||||
|
||||
void CGCam_Shake( float intensity, int duration );
|
||||
void CGCam_Shake( float intensity, int duration, bool rumble );
|
||||
void CGCam_UpdateShake( vec3_t origin, vec3_t angles );
|
||||
|
||||
void CGCam_Follow( const char *cameraGroup, float speed, float initLerp );
|
||||
void CGCam_Track( const char *trackName, float speed, float initLerp );
|
||||
void CGCam_Distance( float distance, float initLerp );
|
||||
void CGCam_Roll( float dest, float duration );
|
||||
|
||||
void CGCam_StartRoff( char *roff );
|
||||
|
||||
void CGCam_Smooth( float intensity, int duration );
|
||||
void CGCam_UpdateSmooth( vec3_t origin, vec3_t angles );
|
||||
|
||||
#endif //__CG_CAMERA__
|
||||
324
code/cgame/cg_consolecmds.cpp
Normal file
324
code/cgame/cg_consolecmds.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
// cg_consolecmds.c -- text commands typed in at the local console, or
|
||||
// executed by a key binding
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h" //just for cgs....
|
||||
|
||||
void CG_TargetCommand_f( void );
|
||||
extern qboolean player_locked;
|
||||
extern void CMD_CGCam_Disable( void );
|
||||
void CG_NextInventory_f( void );
|
||||
void CG_PrevInventory_f( void );
|
||||
void CG_NextForcePower_f( void );
|
||||
void CG_PrevForcePower_f( void );
|
||||
void CG_LoadHud_f( void );
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_ColorFromString
|
||||
====================
|
||||
*/
|
||||
/*
|
||||
static void CG_SetColor_f( void) {
|
||||
|
||||
if (cgi_Argc()==4)
|
||||
{
|
||||
g_entities[0].client->renderInfo.customRGBA[0] = atoi( CG_Argv(1) );
|
||||
g_entities[0].client->renderInfo.customRGBA[1] = atoi( CG_Argv(2) );
|
||||
g_entities[0].client->renderInfo.customRGBA[2] = atoi( CG_Argv(3) );
|
||||
}
|
||||
if (cgi_Argc()==2)
|
||||
{
|
||||
int val = atoi( CG_Argv(1) );
|
||||
|
||||
if ( val < 1 || val > 7 ) {
|
||||
g_entities[0].client->renderInfo.customRGBA[0] = 255;
|
||||
g_entities[0].client->renderInfo.customRGBA[1] = 255;
|
||||
g_entities[0].client->renderInfo.customRGBA[2] = 255;
|
||||
return;
|
||||
}
|
||||
g_entities[0].client->renderInfo.customRGBA[0]=0;
|
||||
g_entities[0].client->renderInfo.customRGBA[1]=0;
|
||||
g_entities[0].client->renderInfo.customRGBA[2]=0;
|
||||
|
||||
if ( val & 1 ) {
|
||||
g_entities[0].client->renderInfo.customRGBA[2] = 255;
|
||||
}
|
||||
if ( val & 2 ) {
|
||||
g_entities[0].client->renderInfo.customRGBA[1] = 255;
|
||||
}
|
||||
if ( val & 4 ) {
|
||||
g_entities[0].client->renderInfo.customRGBA[0] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
=============
|
||||
CG_Viewpos_f
|
||||
|
||||
Debugging command to print the current position
|
||||
=============
|
||||
*/
|
||||
static void CG_Viewpos_f (void) {
|
||||
CG_Printf ("%s (%i %i %i) : %i\n", cgs.mapname, (int)cg.refdef.vieworg[0],
|
||||
(int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
|
||||
(int)cg.refdefViewAngles[YAW]);
|
||||
}
|
||||
|
||||
void CG_WriteCam_f (void)
|
||||
{
|
||||
char text[1024];
|
||||
char *targetname;
|
||||
static int numCams;
|
||||
|
||||
numCams++;
|
||||
|
||||
targetname = (char *)CG_Argv(1);
|
||||
|
||||
if( !targetname || !targetname[0] )
|
||||
{
|
||||
targetname = "nameme!";
|
||||
}
|
||||
|
||||
CG_Printf( "Camera #%d ('%s') written to: ", numCams, targetname );
|
||||
sprintf( text, "//entity %d\n{\n\"classname\" \"ref_tag\"\n\"targetname\" \"%s\"\n\"origin\" \"%i %i %i\"\n\"angles\" \"%i %i %i\"\n\"fov\" \"%i\"\n}\n", numCams, targetname, (int)cg.refdef.vieworg[0], (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2], (int)cg.refdefViewAngles[0], (int)cg.refdefViewAngles[1], (int)cg.refdefViewAngles[2], cg_fov.integer );
|
||||
gi.WriteCam( text );
|
||||
}
|
||||
|
||||
void Lock_Disable ( void )
|
||||
{
|
||||
player_locked = qfalse;
|
||||
}
|
||||
|
||||
extern float cg_zoomFov; //from cg_view.cpp
|
||||
|
||||
void CG_ToggleBinoculars( void )
|
||||
{
|
||||
if ( in_camera || !cg.snap )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cg.zoomMode == 0 || cg.zoomMode >= 2 ) // not zoomed or currently zoomed with the disruptor or LA goggles
|
||||
{
|
||||
if ( (cg.snap->ps.saber[0].Active() && cg.snap->ps.saberInFlight) || cg.snap->ps.stats[STAT_HEALTH] <= 0)
|
||||
{//can't select binoculars when throwing saber
|
||||
//FIXME: indicate this to the player
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cg.snap->ps.viewEntity || ( cg_entities[cg.snap->ps.clientNum].currentState.eFlags & ( EF_LOCKED_TO_WEAPON | EF_IN_ATST )))
|
||||
{
|
||||
// can't zoom when you have a viewEntity or driving an atst or in an emplaced gun
|
||||
return;
|
||||
}
|
||||
|
||||
cg.zoomMode = 1;
|
||||
cg.zoomLocked = qfalse;
|
||||
|
||||
if ( cg.snap->ps.batteryCharge )
|
||||
{
|
||||
// when you have batteries, you can actually zoom in
|
||||
cg_zoomFov = 40.0f;
|
||||
}
|
||||
else if ( cg.overrides.active & CG_OVERRIDE_FOV )
|
||||
{
|
||||
cg_zoomFov = cg.overrides.fov;
|
||||
}
|
||||
else
|
||||
{
|
||||
cg_zoomFov = cg_fov.value;
|
||||
}
|
||||
|
||||
cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomStart );
|
||||
#ifdef _IMMERSION
|
||||
cgi_FF_Start( cgs.media.zoomStartForce, cg.snap->ps.clientNum );
|
||||
#endif // _IMMERSION
|
||||
}
|
||||
else
|
||||
{
|
||||
cg.zoomMode = 0;
|
||||
cg.zoomTime = cg.time;
|
||||
cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomEnd );
|
||||
#ifdef _IMMERSION
|
||||
cgi_FF_Start( cgs.media.zoomEndForce, cg.snap->ps.clientNum );
|
||||
#endif // _IMMERSION
|
||||
}
|
||||
}
|
||||
|
||||
void CG_ToggleLAGoggles( void )
|
||||
{
|
||||
if ( in_camera || !cg.snap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cg.zoomMode == 0 || cg.zoomMode < 3 ) // not zoomed or currently zoomed with the disruptor or regular binoculars
|
||||
{
|
||||
if ( (cg.snap->ps.saber[0].Active() && cg.snap->ps.saberInFlight) || cg.snap->ps.stats[STAT_HEALTH] <= 0 )
|
||||
{//can't select binoculars when throwing saber
|
||||
//FIXME: indicate this to the player
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cg.snap->ps.viewEntity || ( cg_entities[cg.snap->ps.clientNum].currentState.eFlags & ( EF_LOCKED_TO_WEAPON | EF_IN_ATST )))
|
||||
{
|
||||
// can't zoom when you have a viewEntity or driving an atst or in an emplaced gun
|
||||
return;
|
||||
}
|
||||
|
||||
cg.zoomMode = 3;
|
||||
cg.zoomLocked = qfalse;
|
||||
if ( cg.overrides.active & CG_OVERRIDE_FOV )
|
||||
{
|
||||
cg_zoomFov = cg.overrides.fov;
|
||||
}
|
||||
else
|
||||
{
|
||||
cg_zoomFov = cg_fov.value; // does not zoom!!
|
||||
}
|
||||
|
||||
cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomStart );
|
||||
#ifdef _IMMERSION
|
||||
cgi_FF_Start( cgs.media.zoomStartForce, cg.snap->ps.clientNum );
|
||||
#endif // _IMMERSION
|
||||
}
|
||||
else
|
||||
{
|
||||
cg.zoomMode = 0;
|
||||
cg.zoomTime = cg.time;
|
||||
cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomEnd );
|
||||
#ifdef _IMMERSION
|
||||
cgi_FF_Start( cgs.media.zoomEndForce, cg.snap->ps.clientNum );
|
||||
#endif // _IMMERSION
|
||||
}
|
||||
}
|
||||
|
||||
static void CG_InfoDown_f( void ) {
|
||||
// cg.showInformation = qtrue;
|
||||
}
|
||||
|
||||
static void CG_InfoUp_f( void )
|
||||
{
|
||||
// cg.showInformation = qfalse;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
void (*function)(void);
|
||||
} consoleCommand_t;
|
||||
|
||||
|
||||
static consoleCommand_t commands[] = {
|
||||
{ "testmodel", CG_TestModel_f },
|
||||
{ "nextframe", CG_TestModelNextFrame_f },
|
||||
{ "prevframe", CG_TestModelPrevFrame_f },
|
||||
{ "nextskin", CG_TestModelNextSkin_f },
|
||||
{ "prevskin", CG_TestModelPrevSkin_f },
|
||||
/*
|
||||
Ghoul2 Insert Start
|
||||
*/
|
||||
{ "testG2Model", CG_TestG2Model_f},
|
||||
{ "testsurface", CG_TestModelSurfaceOnOff_f },
|
||||
{ "testanglespre", CG_TestModelSetAnglespre_f},
|
||||
{ "testanglespost", CG_TestModelSetAnglespost_f},
|
||||
{ "testanimate", CG_TestModelAnimate_f},
|
||||
{ "testlistbones", CG_ListModelBones_f},
|
||||
{ "testlistsurfaces", CG_ListModelSurfaces_f},
|
||||
/*
|
||||
Ghoul2 Insert End
|
||||
*/
|
||||
{ "viewpos", CG_Viewpos_f },
|
||||
{ "writecam", CG_WriteCam_f },
|
||||
{ "+info", CG_InfoDown_f },
|
||||
{ "-info", CG_InfoUp_f },
|
||||
{ "weapnext", CG_NextWeapon_f },
|
||||
{ "weapprev", CG_PrevWeapon_f },
|
||||
{ "weapon", CG_Weapon_f },
|
||||
{ "tcmd", CG_TargetCommand_f },
|
||||
{ "cam_disable", CMD_CGCam_Disable }, //gets out of camera mode for debuggin
|
||||
{ "cam_enable", CGCam_Enable }, //gets into camera mode for precise camera placement
|
||||
{ "lock_disable", Lock_Disable }, //player can move now
|
||||
{ "zoom", CG_ToggleBinoculars },
|
||||
{ "la_zoom", CG_ToggleLAGoggles },
|
||||
{ "invnext", CG_NextInventory_f },
|
||||
{ "invprev", CG_PrevInventory_f },
|
||||
{ "forcenext", CG_NextForcePower_f },
|
||||
{ "forceprev", CG_PrevForcePower_f },
|
||||
{ "loadhud", CG_LoadHud_f },
|
||||
{ "dpweapnext", CG_DPNextWeapon_f },
|
||||
{ "dpweapprev", CG_DPPrevWeapon_f },
|
||||
{ "dpinvnext", CG_DPNextInventory_f },
|
||||
{ "dpinvprev", CG_DPPrevInventory_f },
|
||||
{ "dpforcenext", CG_DPNextForcePower_f },
|
||||
{ "dpforceprev", CG_DPPrevForcePower_f },
|
||||
// { "color", CG_SetColor_f },
|
||||
};
|
||||
|
||||
|
||||
//extern menuDef_t *menuScoreboard;
|
||||
void Menu_Reset();
|
||||
|
||||
void CG_LoadHud_f( void)
|
||||
{
|
||||
const char *hudSet;
|
||||
|
||||
// cgi_UI_String_Init();
|
||||
|
||||
// cgi_UI_Menu_Reset();
|
||||
|
||||
hudSet = cg_hudFiles.string;
|
||||
if (hudSet[0] == '\0')
|
||||
{
|
||||
hudSet = "ui/jahud.txt";
|
||||
}
|
||||
|
||||
CG_LoadMenus(hudSet);
|
||||
// menuScoreboard = NULL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_ConsoleCommand
|
||||
|
||||
The string has been tokenized and can be retrieved with
|
||||
Cmd_Argc() / Cmd_Argv()
|
||||
=================
|
||||
*/
|
||||
qboolean CG_ConsoleCommand( void ) {
|
||||
const char *cmd;
|
||||
int i;
|
||||
|
||||
cmd = CG_Argv(0);
|
||||
|
||||
for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
|
||||
if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
|
||||
commands[i].function();
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_InitConsoleCommands
|
||||
|
||||
Let the client system know about all of our commands
|
||||
so it can perform tab completion
|
||||
=================
|
||||
*/
|
||||
void CG_InitConsoleCommands( void ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
|
||||
cgi_AddCommand( commands[i].cmd );
|
||||
}
|
||||
}
|
||||
654
code/cgame/cg_credits.cpp
Normal file
654
code/cgame/cg_credits.cpp
Normal file
@@ -0,0 +1,654 @@
|
||||
// Filename:- cg_credits.cpp
|
||||
//
|
||||
// module for end credits code
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
//
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#define fCARD_FADESECONDS 1.0f // fade up time, also fade down time
|
||||
#define fCARD_SUSTAINSECONDS 2.0f // hold time before fade down
|
||||
#define fLINE_SECONDTOSCROLLUP 15.0f // how long one line takes to scroll up the screen
|
||||
|
||||
|
||||
#define MAX_LINE_BYTES 2048
|
||||
|
||||
qhandle_t ghFontHandle = 0;
|
||||
float gfFontScale = 1.00f;
|
||||
vec4_t gv4Color = {0};
|
||||
|
||||
struct StringAndSize_t
|
||||
{
|
||||
int iStrLenPixels;
|
||||
string str;
|
||||
|
||||
StringAndSize_t()
|
||||
{
|
||||
iStrLenPixels = -1;
|
||||
str = "";
|
||||
}
|
||||
StringAndSize_t(const char *psString)
|
||||
{
|
||||
iStrLenPixels = -1;
|
||||
str = psString;
|
||||
}
|
||||
StringAndSize_t & operator = (const char *psString)
|
||||
{
|
||||
iStrLenPixels = -1;
|
||||
str = psString;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char *c_str(void)
|
||||
{
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
int GetPixelLength(void)
|
||||
{
|
||||
if (iStrLenPixels == -1)
|
||||
{
|
||||
iStrLenPixels = cgi_R_Font_StrLenPixels(str.c_str(), ghFontHandle, gfFontScale);
|
||||
}
|
||||
|
||||
return iStrLenPixels;
|
||||
}
|
||||
|
||||
bool IsEmpty(void)
|
||||
{
|
||||
return str.empty();
|
||||
}
|
||||
};
|
||||
|
||||
struct CreditCard_t
|
||||
{
|
||||
int iTime;
|
||||
StringAndSize_t strTitle;
|
||||
vector<StringAndSize_t> vstrText;
|
||||
|
||||
CreditCard_t()
|
||||
{
|
||||
iTime = -1; // flag "not set yet"
|
||||
}
|
||||
};
|
||||
|
||||
struct CreditLine_t
|
||||
{
|
||||
int iLine;
|
||||
StringAndSize_t strText;
|
||||
vector<StringAndSize_t> vstrText;
|
||||
bool bDotted;
|
||||
};
|
||||
|
||||
typedef list <CreditLine_t> CreditLines_t;
|
||||
typedef list <CreditCard_t> CreditCards_t;
|
||||
|
||||
struct CreditData_t
|
||||
{
|
||||
int iStartTime;
|
||||
|
||||
CreditCards_t CreditCards;
|
||||
CreditLines_t CreditLines;
|
||||
|
||||
bool Running(void)
|
||||
{
|
||||
return !!( CreditCards.size() || CreditLines.size() );
|
||||
}
|
||||
};
|
||||
|
||||
CreditData_t CreditData;
|
||||
|
||||
|
||||
static LPCSTR Capitalize(LPCSTR psTest)
|
||||
{
|
||||
static char sTemp[MAX_LINE_BYTES];
|
||||
|
||||
Q_strncpyz(sTemp, psTest, sizeof(sTemp));
|
||||
|
||||
// if (!cgi_Language_IsAsian()) // we don't have asian credits, so this is ok to do now
|
||||
{
|
||||
strupr(sTemp); // capitalise titles (if not asian!!!!)
|
||||
}
|
||||
|
||||
return sTemp;
|
||||
}
|
||||
|
||||
// cope with hyphenated names and initials (awkward gits)...
|
||||
//
|
||||
static bool CountsAsWhiteSpaceForCaps( unsigned /* avoid euro-char sign-extend assert within isspace()*/char c )
|
||||
{
|
||||
return !!(isspace(c) || c == '-' || c == '.' || c == '(' || c == ')' || c=='\'');
|
||||
}
|
||||
static LPCSTR UpperCaseFirstLettersOnly(LPCSTR psTest)
|
||||
{
|
||||
static char sTemp[MAX_LINE_BYTES];
|
||||
|
||||
Q_strncpyz(sTemp, psTest, sizeof(sTemp));
|
||||
|
||||
// if (!cgi_Language_IsAsian()) // we don't have asian credits, so this is ok to do now
|
||||
{
|
||||
strlwr(sTemp);
|
||||
|
||||
char *p = sTemp;
|
||||
while (*p)
|
||||
{
|
||||
while (*p && CountsAsWhiteSpaceForCaps(*p)) p++;
|
||||
if (*p)
|
||||
{
|
||||
*p = toupper(*p);
|
||||
while (*p && !CountsAsWhiteSpaceForCaps(*p)) p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now restore any weird stuff...
|
||||
//
|
||||
char *p = strstr(sTemp," Mc"); // eg "Mcfarrell" should be "McFarrell"
|
||||
if (p && isalpha(p[3]))
|
||||
{
|
||||
p[3] = toupper(p[3]);
|
||||
}
|
||||
p = strstr(sTemp," O'"); // eg "O'flaherty" should be "O'Flaherty" (this is probably done automatically now, but wtf.
|
||||
if (p && isalpha(p[3]))
|
||||
{
|
||||
p[3] = toupper(p[3]);
|
||||
}
|
||||
p = strstr(sTemp,"Lucasarts");
|
||||
if (p)
|
||||
{
|
||||
p[5] = 'A'; // capitalise the 'A' in LucasArts (jeez...)
|
||||
}
|
||||
|
||||
return sTemp;
|
||||
}
|
||||
|
||||
static const char *GetSubString(string &strResult)
|
||||
{
|
||||
static char sTemp[MAX_LINE_BYTES];
|
||||
|
||||
if (!strlen(strResult.c_str()))
|
||||
return NULL;
|
||||
|
||||
strncpy(sTemp,strResult.c_str(),sizeof(sTemp)-1);
|
||||
sTemp[sizeof(sTemp)-1]='\0';
|
||||
|
||||
char *psSemiColon = strchr(sTemp,';');
|
||||
if ( psSemiColon)
|
||||
{
|
||||
*psSemiColon = '\0';
|
||||
|
||||
strResult.erase(0,(psSemiColon-sTemp)+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no semicolon found, probably last entry? (though i think even those have them on, oh well)
|
||||
//
|
||||
strResult.erase();
|
||||
}
|
||||
|
||||
return sTemp;
|
||||
}
|
||||
|
||||
// sort entries by their last name (starts at back of string and moves forward until start or just before whitespace)
|
||||
// ...
|
||||
static int SortBySurname(const void *elem1, const void *elem2)
|
||||
{
|
||||
StringAndSize_t *p1 = (StringAndSize_t *) elem1;
|
||||
StringAndSize_t *p2 = (StringAndSize_t *) elem2;
|
||||
|
||||
LPCSTR psSurName1 = p1->c_str() + (strlen(p1->c_str())-1);
|
||||
LPCSTR psSurName2 = p2->c_str() + (strlen(p2->c_str())-1);
|
||||
|
||||
while (psSurName1 > p1->c_str() && !isspace(*psSurName1)) psSurName1--;
|
||||
while (psSurName2 > p2->c_str() && !isspace(*psSurName2)) psSurName2--;
|
||||
if (isspace(*psSurName1)) psSurName1++;
|
||||
if (isspace(*psSurName2)) psSurName2++;
|
||||
|
||||
return stricmp(psSurName1, psSurName2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CG_Credits_Init( LPCSTR psStripReference, vec4_t *pv4Color)
|
||||
{
|
||||
// Play the light side end credits music.
|
||||
if ( g_entities[0].client->sess.mission_objectives[0].status != 2 )
|
||||
{
|
||||
cgi_S_StartBackgroundTrack( "music/endcredits.mp3", NULL, false );
|
||||
}
|
||||
// Play the dark side end credits music.
|
||||
else
|
||||
{
|
||||
cgi_S_StartBackgroundTrack( "music/vjun3/vjun3_explore.mp3", NULL, false );
|
||||
}
|
||||
|
||||
// could make these into parameters later, but for now...
|
||||
//
|
||||
ghFontHandle = cgs.media.qhFontMedium;
|
||||
gfFontScale = 1.0f;
|
||||
|
||||
memcpy(gv4Color,pv4Color,sizeof(gv4Color)); // memcpy so we can poke into alpha channel
|
||||
|
||||
// first, ask the strlen of the final string...
|
||||
//
|
||||
int iStrLen = cgi_SP_GetStringTextString( psStripReference, NULL, 0 );
|
||||
if (!iStrLen)
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf("WARNING: CG_Credits_Init(): invalid text key :'%s'\n", psStripReference);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
//
|
||||
// malloc space to hold it...
|
||||
//
|
||||
char *psMallocText = (char *) cgi_Z_Malloc( iStrLen+1, TAG_TEMP_WORKSPACE );
|
||||
//
|
||||
// now get the string...
|
||||
//
|
||||
iStrLen = cgi_SP_GetStringTextString( psStripReference, psMallocText, iStrLen+1 );
|
||||
//ensure we found a match
|
||||
if (!iStrLen)
|
||||
{
|
||||
assert(0); // should never get here now, but wtf?
|
||||
cgi_Z_Free(psMallocText);
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf("WARNING: CG_Credits_Init(): invalid text key :'%s'\n", psStripReference);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// read whole string in and process as cards, lines etc...
|
||||
//
|
||||
typedef enum
|
||||
{
|
||||
eNothing = 0,
|
||||
eLine,
|
||||
eDotEntry,
|
||||
eTitle,
|
||||
eCard,
|
||||
eFinished,
|
||||
} Mode_e;
|
||||
Mode_e eMode = eNothing;
|
||||
|
||||
qboolean bCardsFinished = qfalse;
|
||||
int iLineNumber = 0;
|
||||
const char *psTextParse = psMallocText;
|
||||
while (*psTextParse != NULL)
|
||||
{
|
||||
// read a line...
|
||||
//
|
||||
char sLine[MAX_LINE_BYTES];
|
||||
sLine[0]='\0';
|
||||
qboolean bWasCommand = qtrue;
|
||||
while (1)
|
||||
{
|
||||
qboolean bIsTrailingPunctuation;
|
||||
int iAdvanceCount;
|
||||
unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(psTextParse, &iAdvanceCount, &bIsTrailingPunctuation);
|
||||
psTextParse += iAdvanceCount;
|
||||
|
||||
// concat onto string so far...
|
||||
//
|
||||
if (uiLetter == 32 && sLine[0] == '\0')
|
||||
{
|
||||
continue; // unless it's a space at the start of a line, in which case ignore it.
|
||||
}
|
||||
|
||||
if (uiLetter == '\n' || uiLetter == '\0' )
|
||||
{
|
||||
// have we got a command word?...
|
||||
//
|
||||
if (!strnicmp(sLine,"(#",2))
|
||||
{
|
||||
// yep...
|
||||
//
|
||||
if (!stricmp(sLine, "(#CARD)"))
|
||||
{
|
||||
if (!bCardsFinished)
|
||||
{
|
||||
eMode = eCard;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf( S_COLOR_YELLOW "CG_Credits_Init(): No current support for cards after scroll!\n" );
|
||||
#endif
|
||||
eMode = eNothing;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
if (!stricmp(sLine, "(#TITLE)"))
|
||||
{
|
||||
eMode = eTitle;
|
||||
bCardsFinished = qtrue;
|
||||
break;
|
||||
}
|
||||
else
|
||||
if (!stricmp(sLine, "(#LINE)"))
|
||||
{
|
||||
eMode = eLine;
|
||||
bCardsFinished = qtrue;
|
||||
break;
|
||||
}
|
||||
else
|
||||
if (!stricmp(sLine, "(#DOTENTRY)"))
|
||||
{
|
||||
eMode = eDotEntry;
|
||||
bCardsFinished = qtrue;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf( S_COLOR_YELLOW "CG_Credits_Init(): bad keyword \"%s\"!\n", sLine );
|
||||
#endif
|
||||
eMode = eNothing;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// I guess not...
|
||||
//
|
||||
bWasCommand = qfalse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// must be a letter...
|
||||
//
|
||||
if (uiLetter > 255)
|
||||
{
|
||||
assert(0); // this means we're attempting to display asian credits, and we don't
|
||||
// support these now because the auto-capitalisation rules etc would have to
|
||||
// be inhibited.
|
||||
Q_strcat(sLine, sizeof(sLine), va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcat(sLine, sizeof(sLine), va("%c",uiLetter & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// command?...
|
||||
//
|
||||
if (bWasCommand)
|
||||
{
|
||||
// this'll just be a mode change, so ignore...
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
// else we've got some text to display...
|
||||
//
|
||||
switch (eMode)
|
||||
{
|
||||
case eNothing: break;
|
||||
case eLine:
|
||||
{
|
||||
CreditLine_t CreditLine;
|
||||
CreditLine.iLine = iLineNumber++;
|
||||
CreditLine.strText = sLine;
|
||||
|
||||
CreditData.CreditLines.push_back( CreditLine );
|
||||
}
|
||||
break;
|
||||
|
||||
case eDotEntry:
|
||||
{
|
||||
CreditLine_t CreditLine;
|
||||
CreditLine.iLine = iLineNumber;
|
||||
CreditLine.bDotted = true;
|
||||
|
||||
string strResult(sLine);
|
||||
const char *p;
|
||||
while ((p=GetSubString(strResult)) != NULL)
|
||||
{
|
||||
if (CreditLine.strText.IsEmpty())
|
||||
{
|
||||
CreditLine.strText = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreditLine.vstrText.push_back( UpperCaseFirstLettersOnly(p) );
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreditLine.strText.IsEmpty() && CreditLine.vstrText.size())
|
||||
{
|
||||
// sort entries RHS dotted entries by alpha...
|
||||
//
|
||||
qsort(&CreditLine.vstrText[0], CreditLine.vstrText.size(), sizeof(CreditLine.vstrText[0]), SortBySurname);
|
||||
|
||||
CreditData.CreditLines.push_back( CreditLine );
|
||||
iLineNumber += CreditLine.vstrText.size();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case eTitle:
|
||||
{
|
||||
iLineNumber++; // leading blank line
|
||||
|
||||
CreditLine_t CreditLine;
|
||||
CreditLine.iLine = iLineNumber++;
|
||||
CreditLine.strText = Capitalize(sLine);
|
||||
|
||||
CreditData.CreditLines.push_back( CreditLine );
|
||||
|
||||
iLineNumber++; // trailing blank line
|
||||
break;
|
||||
}
|
||||
case eCard:
|
||||
{
|
||||
CreditCard_t CreditCard;
|
||||
|
||||
string strResult(sLine);
|
||||
const char *p;
|
||||
while ((p=GetSubString(strResult)) != NULL)
|
||||
{
|
||||
if (CreditCard.strTitle.IsEmpty())
|
||||
{
|
||||
CreditCard.strTitle = Capitalize( p );
|
||||
}
|
||||
else
|
||||
{
|
||||
CreditCard.vstrText.push_back( UpperCaseFirstLettersOnly( p ) );
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreditCard.strTitle.IsEmpty())
|
||||
{
|
||||
// sort entries by alpha...
|
||||
//
|
||||
qsort(&CreditCard.vstrText[0], CreditCard.vstrText.size(), sizeof(CreditCard.vstrText[0]), SortBySurname);
|
||||
|
||||
CreditData.CreditCards.push_back(CreditCard);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cgi_Z_Free(psMallocText);
|
||||
CreditData.iStartTime = cg.time;
|
||||
}
|
||||
|
||||
qboolean CG_Credits_Running( void )
|
||||
{
|
||||
return CreditData.Running();
|
||||
}
|
||||
|
||||
// returns qtrue if still drawing...
|
||||
//
|
||||
qboolean CG_Credits_Draw( void )
|
||||
{
|
||||
if ( CG_Credits_Running() )
|
||||
{
|
||||
const int iFontHeight = (int) (1.5f * (float) cgi_R_Font_HeightPixels(ghFontHandle, gfFontScale)); // taiwanese & japanese need 1.5 fontheight spacing
|
||||
|
||||
// cgi_R_SetColor( *gpv4Color );
|
||||
|
||||
// display cards first...
|
||||
//
|
||||
if (CreditData.CreditCards.size())
|
||||
{
|
||||
// grab first card off the list (we know there's at least one here, so...)
|
||||
//
|
||||
CreditCard_t &CreditCard = (*CreditData.CreditCards.begin());
|
||||
|
||||
if (CreditCard.iTime == -1)
|
||||
{
|
||||
// onceonly time init...
|
||||
//
|
||||
CreditCard.iTime = cg.time;
|
||||
}
|
||||
|
||||
// play with the alpha channel for fade up/down...
|
||||
//
|
||||
const float fMilliSecondsElapsed = cg.time - CreditCard.iTime;
|
||||
const float fSecondsElapsed = fMilliSecondsElapsed / 1000.0f;
|
||||
if (fSecondsElapsed < fCARD_FADESECONDS)
|
||||
{
|
||||
// fading up...
|
||||
//
|
||||
gv4Color[3] = fSecondsElapsed / fCARD_FADESECONDS;
|
||||
// OutputDebugString(va("fade up: %f\n",gv4Color[3]));
|
||||
}
|
||||
else
|
||||
if (fSecondsElapsed > fCARD_FADESECONDS + fCARD_SUSTAINSECONDS)
|
||||
{
|
||||
// fading down...
|
||||
//
|
||||
const float fFadeDownSeconds = fSecondsElapsed - (fCARD_FADESECONDS + fCARD_SUSTAINSECONDS);
|
||||
gv4Color[3] = 1.0f - (fFadeDownSeconds / fCARD_FADESECONDS);
|
||||
// OutputDebugString(va("fade dw: %f\n",gv4Color[3]));
|
||||
}
|
||||
else
|
||||
{
|
||||
gv4Color[3] = 1.0f;
|
||||
// OutputDebugString(va("normal: %f\n",gv4Color[3]));
|
||||
}
|
||||
if (gv4Color[3] < 0.0f)
|
||||
gv4Color[3] = 0.0f; // ... otherwise numbers that have dipped slightly -ve flash up fullbright after fade down
|
||||
|
||||
//
|
||||
// how many lines is it?
|
||||
//
|
||||
int iLines = CreditCard.vstrText.size() + 2; // +2 for title itself & one seperator line
|
||||
//
|
||||
int iYpos = (SCREEN_HEIGHT - (iLines * iFontHeight))/2;
|
||||
//
|
||||
// draw it, title first...
|
||||
//
|
||||
int iWidth = CreditCard.strTitle.GetPixelLength();
|
||||
int iXpos = (SCREEN_WIDTH - iWidth)/2;
|
||||
cgi_R_Font_DrawString(iXpos, iYpos, CreditCard.strTitle.c_str(), gv4Color, ghFontHandle, -1, gfFontScale);
|
||||
//
|
||||
iYpos += iFontHeight*2; // skip blank line then move to main pos
|
||||
//
|
||||
for (int i=0; i<CreditCard.vstrText.size(); i++)
|
||||
{
|
||||
StringAndSize_t &StringAndSize = CreditCard.vstrText[i];
|
||||
iWidth = StringAndSize.GetPixelLength();
|
||||
iXpos = (SCREEN_WIDTH - iWidth)/2;
|
||||
cgi_R_Font_DrawString(iXpos, iYpos, StringAndSize.c_str(), gv4Color, ghFontHandle, -1, gfFontScale);
|
||||
iYpos += iFontHeight;
|
||||
}
|
||||
|
||||
// next card?...
|
||||
//
|
||||
if (fSecondsElapsed > fCARD_FADESECONDS + fCARD_SUSTAINSECONDS + fCARD_FADESECONDS)
|
||||
{
|
||||
// yep, so erase the first entry (which will trigger the next one to be initialised on re-entry)...
|
||||
//
|
||||
CreditData.CreditCards.erase( CreditData.CreditCards.begin() );
|
||||
|
||||
if (!CreditData.CreditCards.size())
|
||||
{
|
||||
// all cards gone, so re-init timer for lines...
|
||||
//
|
||||
CreditData.iStartTime = cg.time;
|
||||
}
|
||||
}
|
||||
//
|
||||
return qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// doing scroll text...
|
||||
//
|
||||
if (CreditData.CreditLines.size())
|
||||
{
|
||||
// process all lines...
|
||||
//
|
||||
const float fMilliSecondsElapsed = cg.time - CreditData.iStartTime;
|
||||
const float fSecondsElapsed = fMilliSecondsElapsed / 1000.0f;
|
||||
|
||||
bool bEraseOccured = false;
|
||||
for (CreditLines_t::iterator it = CreditData.CreditLines.begin(); it != CreditData.CreditLines.end(); bEraseOccured ? it : ++it)
|
||||
{
|
||||
CreditLine_t &CreditLine = (*it);
|
||||
bEraseOccured = false;
|
||||
|
||||
static const float fPixelsPerSecond = ((float)SCREEN_HEIGHT / fLINE_SECONDTOSCROLLUP);
|
||||
|
||||
int iYpos = SCREEN_HEIGHT + (CreditLine.iLine * iFontHeight);
|
||||
iYpos-= (int) (fPixelsPerSecond * fSecondsElapsed);
|
||||
|
||||
int iTextLinesThisItem = max(CreditLine.vstrText.size(),1);
|
||||
if (iYpos + (iTextLinesThisItem * iFontHeight) < 0)
|
||||
{
|
||||
// scrolled off top of screen, so erase it...
|
||||
//
|
||||
it = CreditData.CreditLines.erase( it );
|
||||
bEraseOccured = true;
|
||||
}
|
||||
else
|
||||
if (iYpos < SCREEN_HEIGHT)
|
||||
{
|
||||
// onscreen, so print it...
|
||||
//
|
||||
bool bIsDotted = !!CreditLine.vstrText.size(); // eg "STUNTS ...................... MR ED"
|
||||
|
||||
int iWidth = CreditLine.strText.GetPixelLength();
|
||||
int iXpos = bIsDotted ? 54 : (SCREEN_WIDTH - iWidth)/2;
|
||||
|
||||
gv4Color[3] = 1.0f;
|
||||
|
||||
cgi_R_Font_DrawString(iXpos, iYpos, CreditLine.strText.c_str(), gv4Color, ghFontHandle, -1, gfFontScale);
|
||||
|
||||
// now print any dotted members...
|
||||
//
|
||||
for (int i=0; i<CreditLine.vstrText.size(); i++)
|
||||
{
|
||||
StringAndSize_t &StringAndSize = CreditLine.vstrText[i];
|
||||
iWidth = StringAndSize.GetPixelLength();
|
||||
iXpos = (SCREEN_WIDTH-4 - iWidth) - 50;
|
||||
cgi_R_Font_DrawString(iXpos, iYpos, StringAndSize.c_str(), gv4Color, ghFontHandle, -1, gfFontScale);
|
||||
iYpos += iFontHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////// eof /////////////////////
|
||||
|
||||
4418
code/cgame/cg_draw.cpp
Normal file
4418
code/cgame/cg_draw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
491
code/cgame/cg_drawtools.cpp
Normal file
491
code/cgame/cg_drawtools.cpp
Normal file
@@ -0,0 +1,491 @@
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawSides
|
||||
|
||||
Coords are virtual 640x480
|
||||
================
|
||||
*/
|
||||
void CG_DrawSides(float x, float y, float w, float h, float size) {
|
||||
//size *= cgs.screenXScale;
|
||||
cgi_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
cgi_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
}
|
||||
|
||||
void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
|
||||
//size *= cgs.screenYScale;
|
||||
cgi_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
cgi_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawRect
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
=================
|
||||
*/
|
||||
void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
|
||||
cgi_R_SetColor( color );
|
||||
|
||||
CG_DrawTopBottom(x, y, width, height, size);
|
||||
CG_DrawSides(x, y, width, height, size);
|
||||
|
||||
cgi_R_SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FillRect
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
=================
|
||||
*/
|
||||
void CG_FillRect( float x, float y, float width, float height, const float *color ) {
|
||||
cgi_R_SetColor( color );
|
||||
cgi_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader);
|
||||
cgi_R_SetColor( NULL );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_Scissor
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
=================
|
||||
*/
|
||||
void CG_Scissor( float x, float y, float width, float height)
|
||||
{
|
||||
|
||||
cgi_R_Scissor( x, y, width, height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawPic
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
A width of 0 will draw with the original image width
|
||||
=================
|
||||
*/
|
||||
void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
|
||||
cgi_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawPic2
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
A width of 0 will draw with the original image width
|
||||
Can also specify the exact texture coordinates
|
||||
=================
|
||||
*/
|
||||
void CG_DrawPic2( float x, float y, float width, float height, float s1, float t1, float s2, float t2, qhandle_t hShader )
|
||||
{
|
||||
cgi_R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, hShader );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawRotatePic
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
A width of 0 will draw with the original image width
|
||||
rotates around the upper right corner of the passed in point
|
||||
=================
|
||||
*/
|
||||
void CG_DrawRotatePic( float x, float y, float width, float height,float angle, qhandle_t hShader ) {
|
||||
cgi_R_DrawRotatePic( x, y, width, height, 0, 0, 1, 1, angle, hShader );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawRotatePic2
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
A width of 0 will draw with the original image width
|
||||
Actually rotates around the center point of the passed in coordinates
|
||||
=================
|
||||
*/
|
||||
void CG_DrawRotatePic2( float x, float y, float width, float height,float angle, qhandle_t hShader ) {
|
||||
cgi_R_DrawRotatePic2( x, y, width, height, 0, 0, 1, 1, angle, hShader );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_DrawChar
|
||||
|
||||
Coordinates and size in 640*480 virtual screen size
|
||||
===============
|
||||
*/
|
||||
void CG_DrawChar( int x, int y, int width, int height, int ch ) {
|
||||
int row, col;
|
||||
float frow, fcol;
|
||||
float size;
|
||||
float ax, ay, aw, ah;
|
||||
|
||||
ch &= 255;
|
||||
|
||||
if ( ch == ' ' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ax = x;
|
||||
ay = y;
|
||||
aw = width;
|
||||
ah = height;
|
||||
|
||||
row = ch>>4;
|
||||
col = ch&15;
|
||||
/*
|
||||
frow = row*0.0625;
|
||||
fcol = col*0.0625;
|
||||
size = 0.0625;
|
||||
|
||||
cgi_R_DrawStretchPic( ax, ay, aw, ah,
|
||||
fcol, frow,
|
||||
fcol + size, frow + size,
|
||||
cgs.media.charsetShader );
|
||||
*/
|
||||
|
||||
float size2;
|
||||
|
||||
frow = row*0.0625;
|
||||
fcol = col*0.0625;
|
||||
size = 0.03125;
|
||||
size2 = 0.0625;
|
||||
|
||||
cgi_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + size, frow + size2,
|
||||
cgs.media.charsetShader );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_DrawStringExt
|
||||
|
||||
Draws a multi-colored string with a drop shadow, optionally forcing
|
||||
to a fixed color.
|
||||
|
||||
Coordinates are at 640 by 480 virtual resolution
|
||||
==================
|
||||
*/
|
||||
void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
|
||||
qboolean forceColor, qboolean shadow, int charWidth, int charHeight ) {
|
||||
vec4_t color;
|
||||
const char *s;
|
||||
int xx;
|
||||
|
||||
// draw the drop shadow
|
||||
if (shadow) {
|
||||
color[0] = color[1] = color[2] = 0;
|
||||
color[3] = setColor[3];
|
||||
cgi_R_SetColor( color );
|
||||
s = string;
|
||||
xx = x;
|
||||
while ( *s ) {
|
||||
if ( Q_IsColorString( s ) ) {
|
||||
s += 2;
|
||||
continue;
|
||||
}
|
||||
CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s );
|
||||
xx += charWidth;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
// draw the colored text
|
||||
s = string;
|
||||
xx = x;
|
||||
cgi_R_SetColor( setColor );
|
||||
while ( *s ) {
|
||||
if ( Q_IsColorString( s ) ) {
|
||||
if ( !forceColor ) {
|
||||
memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
|
||||
color[3] = setColor[3];
|
||||
cgi_R_SetColor( color );
|
||||
}
|
||||
s += 2;
|
||||
continue;
|
||||
}
|
||||
CG_DrawChar( xx, y, charWidth, charHeight, *s );
|
||||
xx += charWidth;
|
||||
s++;
|
||||
}
|
||||
cgi_R_SetColor( NULL );
|
||||
}
|
||||
|
||||
|
||||
void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ) {
|
||||
CG_DrawStringExt( x, y, s, color, qtrue, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_DrawStrlen
|
||||
|
||||
Returns character count, skiping color escape codes
|
||||
=================
|
||||
*/
|
||||
int CG_DrawStrlen( const char *str ) {
|
||||
const char *s = str;
|
||||
int count = 0;
|
||||
|
||||
while ( *s ) {
|
||||
if ( Q_IsColorString( s ) ) {
|
||||
s += 2;
|
||||
} else {
|
||||
count++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
CG_TileClearBox
|
||||
|
||||
This repeats a 64*64 tile graphic to fill the screen around a sized down
|
||||
refresh window.
|
||||
=============
|
||||
*/
|
||||
static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
|
||||
float s1, t1, s2, t2;
|
||||
|
||||
s1 = x/64.0;
|
||||
t1 = y/64.0;
|
||||
s2 = (x+w)/64.0;
|
||||
t2 = (y+h)/64.0;
|
||||
cgi_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_TileClear
|
||||
|
||||
Clear around a sized down screen
|
||||
==============
|
||||
*/
|
||||
void CG_TileClear( void ) {
|
||||
int top, bottom, left, right;
|
||||
int w, h;
|
||||
|
||||
w = cgs.glconfig.vidWidth;
|
||||
h = cgs.glconfig.vidHeight;
|
||||
|
||||
if ( cg.refdef.x == 0 && cg.refdef.y == 0 &&
|
||||
cg.refdef.width == w && cg.refdef.height == h ) {
|
||||
return; // full screen rendering
|
||||
}
|
||||
|
||||
top = cg.refdef.y;
|
||||
bottom = top + cg.refdef.height-1;
|
||||
left = cg.refdef.x;
|
||||
right = left + cg.refdef.width-1;
|
||||
|
||||
// clear above view screen
|
||||
CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
|
||||
|
||||
// clear below view screen
|
||||
CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
|
||||
|
||||
// clear left of view screen
|
||||
CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
|
||||
|
||||
// clear right of view screen
|
||||
CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FadeColor
|
||||
================
|
||||
*/
|
||||
float *CG_FadeColor( int startMsec, int totalMsec ) {
|
||||
static vec4_t color;
|
||||
int t;
|
||||
|
||||
if ( startMsec == 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = cg.time - startMsec;
|
||||
|
||||
if ( t >= totalMsec ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fade out
|
||||
if ( totalMsec - t < FADE_TIME ) {
|
||||
color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
|
||||
} else {
|
||||
color[3] = 1.0;
|
||||
}
|
||||
color[0] = color[1] = color[2] = 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_DrawNumField
|
||||
|
||||
Take x,y positions as if 640 x 480 and scales them to the proper resolution
|
||||
|
||||
==============
|
||||
*/
|
||||
void CG_DrawNumField (int x, int y, int width, int value,int charWidth,int charHeight,int style,qboolean zeroFill)
|
||||
{
|
||||
char num[16], *ptr;
|
||||
int l;
|
||||
int frame;
|
||||
int xWidth;
|
||||
|
||||
if (width < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// draw number string
|
||||
if (width > 5) {
|
||||
width = 5;
|
||||
}
|
||||
|
||||
switch ( width ) {
|
||||
case 1:
|
||||
value = value > 9 ? 9 : value;
|
||||
value = value < 0 ? 0 : value;
|
||||
break;
|
||||
case 2:
|
||||
value = value > 99 ? 99 : value;
|
||||
value = value < -9 ? -9 : value;
|
||||
break;
|
||||
case 3:
|
||||
value = value > 999 ? 999 : value;
|
||||
value = value < -99 ? -99 : value;
|
||||
break;
|
||||
case 4:
|
||||
value = value > 9999 ? 9999 : value;
|
||||
value = value < -999 ? -999 : value;
|
||||
break;
|
||||
}
|
||||
|
||||
Com_sprintf (num, sizeof(num), "%i", value);
|
||||
l = strlen(num);
|
||||
if (l > width)
|
||||
l = width;
|
||||
|
||||
// FIXME: Might need to do something different for the chunky font??
|
||||
switch(style)
|
||||
{
|
||||
default:
|
||||
case NUM_FONT_SMALL:
|
||||
xWidth = charWidth;
|
||||
break;
|
||||
/*
|
||||
case NUM_FONT_CHUNKY:
|
||||
xWidth = (charWidth/1.2f) + 2;
|
||||
break;
|
||||
case NUM_FONT_BIG:
|
||||
xWidth = (charWidth/2) + 7;//(charWidth/6);
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef _XBOX
|
||||
if ( zeroFill )
|
||||
{
|
||||
for (int i = 0; i < (width - l); i++ )
|
||||
{
|
||||
switch(style)
|
||||
{
|
||||
default:
|
||||
case NUM_FONT_SMALL:
|
||||
CG_DrawPic( x,y, charWidth, charHeight, cgs.media.smallnumberShaders[0] );
|
||||
break;
|
||||
/*
|
||||
case NUM_FONT_CHUNKY:
|
||||
CG_DrawPic( x,y, charWidth, charHeight, cgs.media.chunkyNumberShaders[0] );
|
||||
break;
|
||||
case NUM_FONT_BIG:
|
||||
CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[0] );
|
||||
break;
|
||||
*/
|
||||
}
|
||||
x += 2 + (xWidth);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
x += 2 + (xWidth)*(width - l);
|
||||
}
|
||||
|
||||
ptr = num;
|
||||
while (*ptr && l)
|
||||
{
|
||||
if (*ptr == '-')
|
||||
frame = STAT_MINUS;
|
||||
else
|
||||
frame = *ptr -'0';
|
||||
|
||||
switch(style)
|
||||
{
|
||||
default:
|
||||
case NUM_FONT_SMALL:
|
||||
if(zeroFill)
|
||||
{
|
||||
CG_DrawPic( x-2,y, charWidth, charHeight, cgs.media.smallnumberShaders[frame] );
|
||||
CG_DrawPic( x+2,y, charWidth, charHeight, cgs.media.smallnumberShaders[frame] );
|
||||
CG_DrawPic( x,y-2, charWidth, charHeight, cgs.media.smallnumberShaders[frame] );
|
||||
CG_DrawPic( x,y+2, charWidth, charHeight, cgs.media.smallnumberShaders[frame] );
|
||||
x++; // For a one line gap
|
||||
}
|
||||
else {
|
||||
CG_DrawPic( x,y, charWidth, charHeight, cgs.media.smallnumberShaders[frame] );
|
||||
x++; // For a one line gap
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case NUM_FONT_CHUNKY:
|
||||
CG_DrawPic( x,y, charWidth, charHeight, cgs.media.chunkyNumberShaders[frame] );
|
||||
break;
|
||||
case NUM_FONT_BIG:
|
||||
CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[frame] );
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
x += (xWidth);
|
||||
ptr++;
|
||||
l--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_DrawProportionalString
|
||||
=================
|
||||
*/
|
||||
void CG_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color )
|
||||
{
|
||||
//assert(!style);//call this directly if you need style (OR it into the font handle)
|
||||
cgi_R_Font_DrawString (x, y, str, color, cgs.media.qhFontMedium, -1, 1.0f);
|
||||
}
|
||||
1087
code/cgame/cg_effects.cpp
Normal file
1087
code/cgame/cg_effects.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2673
code/cgame/cg_ents.cpp
Normal file
2673
code/cgame/cg_ents.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1281
code/cgame/cg_event.cpp
Normal file
1281
code/cgame/cg_event.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
code/cgame/cg_headers.cpp
Normal file
3
code/cgame/cg_headers.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
20
code/cgame/cg_headers.h
Normal file
20
code/cgame/cg_headers.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// Precompiled header file for the client game
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
// No PCH at all on Xbox build, we just include everything. Does this slow
|
||||
// down builds? Somewhat. But then again, if I do change headers, I have to
|
||||
// tolerate VS.net's piss poor dependency system that requires my to manually
|
||||
// delete the .pch for the PC version to work at all. So, I'll live.
|
||||
#ifdef _XBOX
|
||||
#include "../game/g_local.h"
|
||||
#include "../game/g_functions.h"
|
||||
#include "../game/b_local.h"
|
||||
#endif
|
||||
|
||||
//#include "CGEntity.h"
|
||||
//#include "../game/SpawnSystem.h"
|
||||
//#include "../game/EntitySystem.h"
|
||||
//#include "../game/CScheduleSystem.h"
|
||||
|
||||
// end
|
||||
648
code/cgame/cg_info.cpp
Normal file
648
code/cgame/cg_info.cpp
Normal file
@@ -0,0 +1,648 @@
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "..\game\objectives.h"
|
||||
|
||||
|
||||
// For printing objectives
|
||||
#ifdef _XBOX
|
||||
static const short objectiveStartingYpos = 100; // Y starting position for objective text
|
||||
static const short objectiveStartingXpos = 130; // X starting position for objective text
|
||||
static const int objectiveTextBoxWidth = 400; // Width (in pixels) of text box
|
||||
static const int objectiveTextBoxHeight = 310; // Height (in pixels) of text box
|
||||
#else
|
||||
static const short objectiveStartingYpos = 75; // Y starting position for objective text
|
||||
static const short objectiveStartingXpos = 60; // X starting position for objective text
|
||||
static const int objectiveTextBoxWidth = 500; // Width (in pixels) of text box
|
||||
static const int objectiveTextBoxHeight = 300; // Height (in pixels) of text box
|
||||
#endif // _XBOX
|
||||
|
||||
const char *showLoadPowersName[] =
|
||||
{
|
||||
"SP_INGAME_HEAL2",
|
||||
"SP_INGAME_JUMP2",
|
||||
"SP_INGAME_SPEED2",
|
||||
"SP_INGAME_PUSH2",
|
||||
"SP_INGAME_PULL2",
|
||||
"SP_INGAME_MINDTRICK2",
|
||||
"SP_INGAME_GRIP2",
|
||||
"SP_INGAME_LIGHTNING2",
|
||||
"SP_INGAME_SABER_THROW2",
|
||||
"SP_INGAME_SABER_OFFENSE2",
|
||||
"SP_INGAME_SABER_DEFENSE2",
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define MAX_OBJ_GRAPHICS 4
|
||||
#define OBJ_GRAPHIC_SIZE 240
|
||||
int obj_graphics[MAX_OBJ_GRAPHICS];
|
||||
|
||||
qboolean CG_ForcePower_Valid(int forceKnownBits, int index);
|
||||
|
||||
/*
|
||||
====================
|
||||
ObjectivePrint_Line
|
||||
|
||||
Print a single mission objective
|
||||
====================
|
||||
*/
|
||||
static void ObjectivePrint_Line(const int color, const int objectIndex, int &missionYcnt)
|
||||
{
|
||||
char *str,*strBegin;
|
||||
int y,pixelLen,charLen,i;
|
||||
const int maxHoldText = 1024;
|
||||
char holdText[maxHoldText];
|
||||
char finalText[2048];
|
||||
qhandle_t graphic;
|
||||
|
||||
int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f);
|
||||
|
||||
cgi_SP_GetStringTextString( va("OBJECTIVES_%s",objectiveTable[objectIndex].name) , finalText, sizeof(finalText) );
|
||||
|
||||
// A hack to be able to count prisoners
|
||||
if (objectIndex==T2_RANCOR_OBJ5)
|
||||
{
|
||||
char value[64];
|
||||
int currTotal, minTotal;
|
||||
|
||||
gi.Cvar_VariableStringBuffer("ui_prisonerobj_currtotal",value,sizeof(value));
|
||||
currTotal = atoi(value);
|
||||
gi.Cvar_VariableStringBuffer("ui_prisonerobj_maxtotal",value,sizeof(value));
|
||||
minTotal = atoi(value);
|
||||
|
||||
sprintf(finalText,va(finalText,currTotal,minTotal));
|
||||
}
|
||||
|
||||
pixelLen = cgi_R_Font_StrLenPixels(finalText, cgs.media.qhFontMedium, 1.0f);
|
||||
|
||||
str = finalText;
|
||||
|
||||
if (cgi_Language_IsAsian())
|
||||
{
|
||||
// this is execrable, and should NOT have had to've been done now, but...
|
||||
//
|
||||
extern const char *CG_DisplayBoxedText( int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight,
|
||||
const char *psText, int iFontHandle, float fScale,
|
||||
const vec4_t v4Color);
|
||||
extern int giLinesOutput;
|
||||
extern float gfAdvanceHack;
|
||||
|
||||
gfAdvanceHack = 1.0f; // override internal vertical advance
|
||||
y = objectiveStartingYpos + (iYPixelsPerLine * missionYcnt);
|
||||
|
||||
// Advance line if a graphic has printed
|
||||
for (i=0;i<MAX_OBJ_GRAPHICS;i++)
|
||||
{
|
||||
if (obj_graphics[i])
|
||||
{
|
||||
y += OBJ_GRAPHIC_SIZE + 4;
|
||||
}
|
||||
}
|
||||
|
||||
CG_DisplayBoxedText(
|
||||
objectiveStartingXpos,
|
||||
y,
|
||||
objectiveTextBoxWidth,
|
||||
objectiveTextBoxHeight,
|
||||
finalText, // int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight, const char *psText
|
||||
cgs.media.qhFontMedium, // int iFontHandle,
|
||||
1.0f, // float fScale,
|
||||
colorTable[color] // const vec4_t v4Color
|
||||
);
|
||||
|
||||
gfAdvanceHack = 0.0f; // restore
|
||||
missionYcnt += giLinesOutput;
|
||||
}
|
||||
else
|
||||
{
|
||||
// western...
|
||||
//
|
||||
if (pixelLen < objectiveTextBoxWidth) // One shot - small enough to print entirely on one line
|
||||
{
|
||||
y =objectiveStartingYpos + (iYPixelsPerLine * (missionYcnt));
|
||||
|
||||
cgi_R_Font_DrawString (
|
||||
objectiveStartingXpos,
|
||||
y,
|
||||
str,
|
||||
colorTable[color],
|
||||
cgs.media.qhFontMedium,
|
||||
-1,
|
||||
1.0f);
|
||||
|
||||
++missionYcnt;
|
||||
}
|
||||
// Text is too long, break into lines.
|
||||
else
|
||||
{
|
||||
char holdText2[2];
|
||||
pixelLen = 0;
|
||||
charLen = 0;
|
||||
holdText2[1] = NULL;
|
||||
strBegin = str;
|
||||
|
||||
while( *str )
|
||||
{
|
||||
holdText2[0] = *str;
|
||||
pixelLen += cgi_R_Font_StrLenPixels(holdText2, cgs.media.qhFontMedium, 1.0f);
|
||||
|
||||
pixelLen += 2; // For kerning
|
||||
++charLen;
|
||||
|
||||
if (pixelLen > objectiveTextBoxWidth )
|
||||
{ //Reached max length of this line
|
||||
//step back until we find a space
|
||||
while ((charLen>10) && (*str != ' ' ))
|
||||
{
|
||||
--str;
|
||||
--charLen;
|
||||
}
|
||||
|
||||
if (*str==' ')
|
||||
{
|
||||
++str; // To get past space
|
||||
}
|
||||
|
||||
assert( charLen<maxHoldText ); // Too big?
|
||||
|
||||
Q_strncpyz( holdText, strBegin, charLen);
|
||||
holdText[charLen] = NULL;
|
||||
strBegin = str;
|
||||
pixelLen = 0;
|
||||
charLen = 1;
|
||||
|
||||
y = objectiveStartingYpos + (iYPixelsPerLine * missionYcnt);
|
||||
|
||||
CG_DrawProportionalString(
|
||||
objectiveStartingXpos,
|
||||
y,
|
||||
holdText,
|
||||
CG_SMALLFONT,
|
||||
colorTable[color] );
|
||||
|
||||
++missionYcnt;
|
||||
}
|
||||
else if (*(str+1) == NULL)
|
||||
{
|
||||
++charLen;
|
||||
|
||||
assert( charLen<maxHoldText ); // Too big?
|
||||
|
||||
y = objectiveStartingYpos + (iYPixelsPerLine * missionYcnt);
|
||||
|
||||
Q_strncpyz( holdText, strBegin, charLen);
|
||||
CG_DrawProportionalString(
|
||||
objectiveStartingXpos,
|
||||
y, holdText,
|
||||
CG_SMALLFONT,
|
||||
colorTable[color] );
|
||||
|
||||
++missionYcnt;
|
||||
break;
|
||||
}
|
||||
++str;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (objectIndex == T3_BOUNTY_OBJ1)
|
||||
{
|
||||
y =objectiveStartingYpos + (iYPixelsPerLine * missionYcnt);
|
||||
if (obj_graphics[1])
|
||||
{
|
||||
y += OBJ_GRAPHIC_SIZE + 4;
|
||||
}
|
||||
if (obj_graphics[2])
|
||||
{
|
||||
y += OBJ_GRAPHIC_SIZE + 4;
|
||||
}
|
||||
graphic = cgi_R_RegisterShaderNoMip("textures/system/viewscreen1");
|
||||
CG_DrawPic( 105, 155, OBJ_GRAPHIC_SIZE * 0.90, OBJ_GRAPHIC_SIZE * 0.90, graphic );
|
||||
obj_graphics[3] = qtrue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_DrawDataPadObjectives
|
||||
|
||||
Draw routine for the objective info screen of the data pad.
|
||||
====================
|
||||
*/
|
||||
void CG_DrawDataPadObjectives(const centity_t *cent )
|
||||
{
|
||||
int i,totalY;
|
||||
int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f);
|
||||
|
||||
const short titleXPos = objectiveStartingXpos - 22; // X starting position for title text
|
||||
const short titleYPos = objectiveStartingYpos - 23; // Y starting position for title text
|
||||
const short graphic_size = 16; // Size (width and height) of graphic used to show status of objective
|
||||
const short graphicXpos = objectiveStartingXpos - graphic_size - 8; // Amount of X to backup from text starting position
|
||||
const short graphicYOffset = (iYPixelsPerLine - graphic_size)/2; // Amount of Y to raise graphic so it's in the center of the text line
|
||||
|
||||
missionInfo_Updated = qfalse; // This will stop the text from flashing
|
||||
cg.missionInfoFlashTime = 0;
|
||||
|
||||
// zero out objective graphics
|
||||
for (i=0;i<MAX_OBJ_GRAPHICS;i++)
|
||||
{
|
||||
obj_graphics[i] = qfalse;
|
||||
}
|
||||
|
||||
// Title Text at the top
|
||||
char text[1024]={0};
|
||||
cgi_SP_GetStringTextString( "SP_INGAME_OBJECTIVES", text, sizeof(text) );
|
||||
cgi_R_Font_DrawString (titleXPos, titleYPos, text, colorTable[CT_TITLE], cgs.media.qhFontMedium, -1, 1.0f);
|
||||
|
||||
int missionYcnt = 0;
|
||||
|
||||
// Print all active objectives
|
||||
for (i=0;i<MAX_OBJECTIVES;i++)
|
||||
{
|
||||
// Is there an objective to see?
|
||||
if (cent->gent->client->sess.mission_objectives[i].display)
|
||||
{
|
||||
// Calculate the Y position
|
||||
totalY = objectiveStartingYpos + (iYPixelsPerLine * (missionYcnt))+(iYPixelsPerLine/2);
|
||||
|
||||
// Draw graphics that show if mission has been accomplished or not
|
||||
cgi_R_SetColor(colorTable[CT_BLUE3]);
|
||||
CG_DrawPic( (graphicXpos), (totalY-graphicYOffset), graphic_size, graphic_size, cgs.media.messageObjCircle); // Circle in front
|
||||
if (cent->gent->client->sess.mission_objectives[i].status == OBJECTIVE_STAT_SUCCEEDED)
|
||||
{
|
||||
CG_DrawPic( (graphicXpos), (totalY-graphicYOffset), graphic_size, graphic_size, cgs.media.messageLitOn); // Center Dot
|
||||
}
|
||||
|
||||
// Print current objective text
|
||||
ObjectivePrint_Line(CT_WHITE, i, missionYcnt );
|
||||
}
|
||||
}
|
||||
|
||||
// No mission text?
|
||||
if (!missionYcnt)
|
||||
{
|
||||
// Set the message a quarter of the way down and in the center of the text box
|
||||
int messageYPosition = objectiveStartingYpos + (objectiveTextBoxHeight / 4);
|
||||
|
||||
cgi_SP_GetStringTextString( "SP_INGAME_OBJNONE", text, sizeof(text) );
|
||||
int messageXPosition = objectiveStartingXpos + (objectiveTextBoxWidth/2) - (cgi_R_Font_StrLenPixels(text, cgs.media.qhFontMedium, 1.0f) /2);
|
||||
|
||||
cgi_R_Font_DrawString (
|
||||
messageXPosition,
|
||||
messageYPosition,
|
||||
text,
|
||||
colorTable[CT_WHITE],
|
||||
cgs.media.qhFontMedium,
|
||||
-1,
|
||||
1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
//-------------------------------------------------------
|
||||
static void CG_DrawForceCount( const int force, int x, float *y, const int pad,qboolean *hasForcePowers )
|
||||
{
|
||||
char s[MAX_STRING_CHARS];
|
||||
int val, textColor;
|
||||
char text[1024]={0};
|
||||
|
||||
gi.Cvar_VariableStringBuffer( va("playerfplvl%d", force ),s, sizeof(s) );
|
||||
|
||||
sscanf( s, "%d",&val );
|
||||
|
||||
if ((val<1) || (val> NUM_FORCE_POWERS))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
textColor = CT_ICON_BLUE;
|
||||
|
||||
// Draw title
|
||||
cgi_SP_GetStringTextString( showLoadPowersName[force], text, sizeof(text) );
|
||||
CG_DrawProportionalString( x, *y, text, CG_BIGFONT, colorTable[textColor] );
|
||||
|
||||
|
||||
// Draw icons
|
||||
cgi_R_SetColor( colorTable[CT_WHITE]);
|
||||
const int iconSize = 30;
|
||||
if ( val >= 0 )
|
||||
{
|
||||
x -= 10; // Back up from title a little
|
||||
|
||||
for ( int i = 0; i < val; i++ )
|
||||
{
|
||||
CG_DrawPic( x - iconSize - i * (iconSize + 10) , *y, iconSize, iconSize, force_icons[force] );
|
||||
}
|
||||
}
|
||||
|
||||
*y += pad;
|
||||
|
||||
*hasForcePowers = qtrue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_LoadScreen_PersonalInfo
|
||||
====================
|
||||
*/
|
||||
/*
|
||||
static void CG_LoadScreen_PersonalInfo(void)
|
||||
{
|
||||
float x, y;
|
||||
int pad = 25;
|
||||
char text[1024]={0};
|
||||
qboolean hasForcePowers;
|
||||
|
||||
y = 65 + 30;
|
||||
|
||||
pad = 28;
|
||||
x = 300;
|
||||
hasForcePowers=qfalse;
|
||||
|
||||
CG_DrawForceCount( FP_HEAL, x, &y, pad,&hasForcePowers);
|
||||
CG_DrawForceCount( FP_LEVITATION, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_SPEED, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_PUSH, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_PULL, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_TELEPATHY, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_GRIP, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_LIGHTNING, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_SABERTHROW, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_SABER_OFFENSE, x, &y, pad,&hasForcePowers );
|
||||
CG_DrawForceCount( FP_SABER_DEFENSE, x, &y, pad,&hasForcePowers );
|
||||
|
||||
if (hasForcePowers)
|
||||
{
|
||||
cgi_SP_GetStringTextString( "SP_INGAME_CURRENTFORCEPOWERS", text, sizeof(text) );
|
||||
CG_DrawProportionalString( 200, 65, text, CG_CENTER | CG_BIGFONT, colorTable[CT_WHITE] );
|
||||
}
|
||||
else
|
||||
{ //you are only totally empty on the very first map?
|
||||
// cgi_SP_GetStringTextString( "SP_INGAME_NONE", text, sizeof(text) );
|
||||
// CG_DrawProportionalString( 320, y+30, text, CG_CENTER | CG_BIGFONT, colorTable[CT_ICON_BLUE] );
|
||||
cgi_SP_GetStringTextString( "SP_INGAME_ALONGTIME", text, sizeof(text) );
|
||||
int w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.5f);
|
||||
cgi_R_Font_DrawString((320)-(w/2), y+40, text, colorTable[CT_ICON_BLUE], cgs.media.qhFontMedium, -1, 1.5f);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
static void CG_LoadBar(void)
|
||||
{
|
||||
cgi_R_SetColor( colorTable[CT_WHITE]);
|
||||
|
||||
int glowHeight = (cg.loadLCARSStage / 9.0f) * 147;
|
||||
int glowTop = (280 + 147) - glowHeight;
|
||||
|
||||
// Draw glow:
|
||||
CG_DrawPic(280, glowTop, 73, glowHeight, cgs.media.loadTick);
|
||||
|
||||
// Draw saber:
|
||||
CG_DrawPic(280, 265, 73, 147, cgs.media.levelLoad);
|
||||
}
|
||||
|
||||
int CG_WeaponCheck( int weaponIndex );
|
||||
|
||||
|
||||
int loadForcePowerLevel[NUM_FORCE_POWERS];
|
||||
|
||||
/*
|
||||
===============
|
||||
ForcePowerDataPad_Valid
|
||||
===============
|
||||
*/
|
||||
qboolean CG_ForcePower_Valid(int forceKnownBits, int index)
|
||||
{
|
||||
if ((forceKnownBits & (1 << showPowers[index])) &&
|
||||
loadForcePowerLevel[showPowers[index]]) // Does he have the force power?
|
||||
{
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// Get the player weapons and force power info
|
||||
static void CG_GetLoadScreenInfo(int *weaponBits,int *forceBits)
|
||||
{
|
||||
char s[MAX_STRING_CHARS];
|
||||
int iDummy,i;
|
||||
float fDummy;
|
||||
const char *var;
|
||||
|
||||
gi.Cvar_VariableStringBuffer( sCVARNAME_PLAYERSAVE, s, sizeof(s) );
|
||||
|
||||
// Get player weapons and force powers known
|
||||
if (s[0])
|
||||
{
|
||||
// |general info |-force powers
|
||||
sscanf( s, "%i %i %i %i %i %i %i %f %f %f %i %i",
|
||||
&iDummy, // &client->ps.stats[STAT_HEALTH],
|
||||
&iDummy, // &client->ps.stats[STAT_ARMOR],
|
||||
&*weaponBits,// &client->ps.stats[STAT_WEAPONS],
|
||||
&iDummy, // &client->ps.stats[STAT_ITEMS],
|
||||
&iDummy, // &client->ps.weapon,
|
||||
&iDummy, // &client->ps.weaponstate,
|
||||
&iDummy, // &client->ps.batteryCharge,
|
||||
&fDummy, // &client->ps.viewangles[0],
|
||||
&fDummy, // &client->ps.viewangles[1],
|
||||
&fDummy, // &client->ps.viewangles[2],
|
||||
//force power data
|
||||
&*forceBits, // &client->ps.forcePowersKnown,
|
||||
&iDummy // &client->ps.forcePower,
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
// the new JK2 stuff - force powers, etc...
|
||||
//
|
||||
gi.Cvar_VariableStringBuffer( "playerfplvl", s, sizeof(s) );
|
||||
i=0;
|
||||
var = strtok( s, " " );
|
||||
while( var != NULL )
|
||||
{
|
||||
/* While there are tokens in "s" */
|
||||
loadForcePowerLevel[i++] = atoi(var);
|
||||
/* Get next token: */
|
||||
var = strtok( NULL, " " );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_DrawLoadingScreen
|
||||
|
||||
Load screen displays the map pic, the mission briefing and weapons/force powers
|
||||
====================
|
||||
*/
|
||||
static void CG_DrawLoadingScreen( qhandle_t levelshot, qhandle_t levelshot2, const char *mapName)
|
||||
{
|
||||
int xPos,yPos,width,height;
|
||||
vec4_t color;
|
||||
qhandle_t background;
|
||||
int weapons=0, forcepowers=0;
|
||||
|
||||
// Get mission briefing for load screen
|
||||
if (cgi_SP_GetStringTextString( va("BRIEFINGS_%s",mapName), NULL, 0 ) == 0)
|
||||
{
|
||||
cgi_Cvar_Set( "ui_missionbriefing", "@BRIEFINGS_NONE" );
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi_Cvar_Set( "ui_missionbriefing", va("@BRIEFINGS_%s",mapName) );
|
||||
}
|
||||
|
||||
// Print background
|
||||
if (cgi_UI_GetMenuItemInfo(
|
||||
"loadScreen",
|
||||
"background",
|
||||
&xPos,
|
||||
&yPos,
|
||||
&width,
|
||||
&height,
|
||||
color,
|
||||
&background))
|
||||
{
|
||||
cgi_R_SetColor( color );
|
||||
CG_DrawPic( xPos, yPos, width, height, background );
|
||||
}
|
||||
|
||||
// Print level pic
|
||||
if (cgi_UI_GetMenuItemInfo(
|
||||
"loadScreen",
|
||||
"mappic",
|
||||
&xPos,
|
||||
&yPos,
|
||||
&width,
|
||||
&height,
|
||||
color,
|
||||
&background))
|
||||
{
|
||||
cgi_R_SetColor( color );
|
||||
CG_DrawPic( xPos, yPos, width, height, levelshot );
|
||||
}
|
||||
|
||||
// Print second level pic
|
||||
if (cgi_UI_GetMenuItemInfo(
|
||||
"loadScreen",
|
||||
"mappic2",
|
||||
&xPos,
|
||||
&yPos,
|
||||
&width,
|
||||
&height,
|
||||
color,
|
||||
&background))
|
||||
{
|
||||
cgi_R_SetColor( color );
|
||||
CG_DrawPic( xPos, yPos, width, height, levelshot2 );
|
||||
}
|
||||
|
||||
// Removed by BTO - No more icons on the loading screen
|
||||
/*
|
||||
// Get player weapons and force power info
|
||||
CG_GetLoadScreenInfo(&weapons,&forcepowers);
|
||||
|
||||
// Print weapon icons
|
||||
if (weapons)
|
||||
{
|
||||
CG_DrawLoadWeapons(weapons);
|
||||
}
|
||||
|
||||
// Print force power icons
|
||||
if (forcepowers)
|
||||
{
|
||||
CG_DrawLoadForcePowers(forcepowers);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_DrawInformation
|
||||
|
||||
Draw all the status / pacifier stuff during level loading
|
||||
====================
|
||||
*/
|
||||
void CG_DrawInformation( void ) {
|
||||
int y;
|
||||
|
||||
// draw the dialog background
|
||||
const char *info = CG_ConfigString( CS_SERVERINFO );
|
||||
const char *s = Info_ValueForKey( info, "mapname" );
|
||||
|
||||
extern SavedGameJustLoaded_e g_eSavedGameJustLoaded; // hack! (hey, it's the last week of coding, ok?
|
||||
|
||||
if ( g_eSavedGameJustLoaded != eFULL && (!strcmp(s,"yavin1") || !strcmp(s,"demo")) )//special case for first map!
|
||||
{
|
||||
char text[1024]={0};
|
||||
|
||||
//
|
||||
cgi_R_SetColor( colorTable[CT_BLACK] );
|
||||
CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.whiteShader );
|
||||
|
||||
cgi_SP_GetStringTextString( "SP_INGAME_ALONGTIME", text, sizeof(text) );
|
||||
|
||||
int w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.0f);
|
||||
cgi_R_Font_DrawString((320)-(w/2), 140, text, colorTable[CT_ICON_BLUE], cgs.media.qhFontMedium, -1, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
qhandle_t levelshot = cgi_R_RegisterShaderNoMip( va( "levelshots/%s", s ) );
|
||||
if (!levelshot) {
|
||||
levelshot = cgi_R_RegisterShaderNoMip( "menu/art/unknownmap" );
|
||||
}
|
||||
|
||||
qhandle_t levelshot2 = cgi_R_RegisterShaderNoMip( va( "levelshots/%s2", s ) );
|
||||
if (!levelshot2) {
|
||||
levelshot2 = levelshot;
|
||||
}
|
||||
|
||||
CG_DrawLoadingScreen(levelshot, levelshot2, s);
|
||||
cgi_UI_MenuPaintAll();
|
||||
}
|
||||
|
||||
CG_LoadBar();
|
||||
|
||||
|
||||
// the first 150 rows are reserved for the client connection
|
||||
// screen to write into
|
||||
// if ( cg.processedSnapshotNum == 0 )
|
||||
{
|
||||
// still loading
|
||||
// print the current item being loaded
|
||||
|
||||
#ifdef _DEBUG
|
||||
cgi_R_Font_DrawString( 40, 416, va("LOADING ... %s",cg.infoScreenText),colorTable[CT_LTGOLD1], cgs.media.qhFontSmall, -1, 1.0f );
|
||||
#endif
|
||||
}
|
||||
|
||||
// draw info string information
|
||||
|
||||
y = 20;
|
||||
// map-specific message (long map name)
|
||||
s = CG_ConfigString( CS_MESSAGE );
|
||||
|
||||
if ( s[0] )
|
||||
{
|
||||
if (s[0] == '@')
|
||||
{
|
||||
char text[1024]={0};
|
||||
cgi_SP_GetStringTextString( s+1, text, sizeof(text) );
|
||||
cgi_R_Font_DrawString( 15, y, va("\"%s\"",text),colorTable[CT_WHITE],cgs.media.qhFontMedium, -1, 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi_R_Font_DrawString( 15, y, va("\"%s\"",s),colorTable[CT_WHITE],cgs.media.qhFontMedium, -1, 1.0f );
|
||||
}
|
||||
y += 20;
|
||||
}
|
||||
}
|
||||
87
code/cgame/cg_lights.cpp
Normal file
87
code/cgame/cg_lights.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
//#include "cg_local.h"
|
||||
|
||||
#if !defined(CG_LIGHTS_H_INC)
|
||||
#include "cg_lights.h"
|
||||
#endif
|
||||
|
||||
static clightstyle_t cl_lightstyle[MAX_LIGHT_STYLES];
|
||||
static int lastofs;
|
||||
|
||||
/*
|
||||
================
|
||||
FX_ClearLightStyles
|
||||
================
|
||||
*/
|
||||
void CG_ClearLightStyles (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
|
||||
lastofs = -1;
|
||||
|
||||
for(i=0;i<MAX_LIGHT_STYLES*3;i++)
|
||||
{
|
||||
CG_SetLightstyle (i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FX_RunLightStyles
|
||||
================
|
||||
*/
|
||||
void CG_RunLightStyles (void)
|
||||
{
|
||||
int ofs;
|
||||
int i;
|
||||
clightstyle_t *ls;
|
||||
|
||||
ofs = cg.time / 50;
|
||||
// if (ofs == lastofs)
|
||||
// return;
|
||||
lastofs = ofs;
|
||||
|
||||
for (i=0,ls=cl_lightstyle ; i<MAX_LIGHT_STYLES ; i++, ls++)
|
||||
{
|
||||
if (!ls->length)
|
||||
{
|
||||
ls->value[0] = ls->value[1] = ls->value[2] = ls->value[3] = 255;
|
||||
}
|
||||
else if (ls->length == 1)
|
||||
{
|
||||
ls->value[0] = ls->map[0][0];
|
||||
ls->value[1] = ls->map[0][1];
|
||||
ls->value[2] = ls->map[0][2];
|
||||
ls->value[3] = 255; //ls->map[0][3];
|
||||
}
|
||||
else
|
||||
{
|
||||
ls->value[0] = ls->map[ofs%ls->length][0];
|
||||
ls->value[1] = ls->map[ofs%ls->length][1];
|
||||
ls->value[2] = ls->map[ofs%ls->length][2];
|
||||
ls->value[3] = 255; //ls->map[ofs%ls->length][3];
|
||||
}
|
||||
trap_R_SetLightStyle(i, *(int*)ls->value);
|
||||
}
|
||||
}
|
||||
|
||||
void CG_SetLightstyle (int i)
|
||||
{
|
||||
const char *s;
|
||||
int j, k;
|
||||
|
||||
s = CG_ConfigString( i+CS_LIGHT_STYLES );
|
||||
j = strlen (s);
|
||||
if (j >= MAX_QPATH)
|
||||
{
|
||||
Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
|
||||
}
|
||||
|
||||
cl_lightstyle[(i/3)].length = j;
|
||||
for (k=0 ; k<j ; k++)
|
||||
{
|
||||
cl_lightstyle[(i/3)].map[k][(i%3)] = (float)(s[k]-'a')/(float)('z'-'a') * 255.0;
|
||||
}
|
||||
}
|
||||
16
code/cgame/cg_lights.h
Normal file
16
code/cgame/cg_lights.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#if !defined(CG_LIGHTS_H_INC)
|
||||
#define CG_LIGHTS_H_INC
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int length;
|
||||
color4ub_t value;
|
||||
color4ub_t map[MAX_QPATH];
|
||||
} clightstyle_t;
|
||||
|
||||
void CG_ClearLightStyles (void);
|
||||
void CG_RunLightStyles (void);
|
||||
void CG_SetLightstyle (int i);
|
||||
|
||||
#endif // CG_LIGHTS_H_INC
|
||||
1233
code/cgame/cg_local.h
Normal file
1233
code/cgame/cg_local.h
Normal file
File diff suppressed because it is too large
Load Diff
599
code/cgame/cg_localents.cpp
Normal file
599
code/cgame/cg_localents.cpp
Normal file
@@ -0,0 +1,599 @@
|
||||
// cg_localents.c -- every frame, generate renderer commands for locally
|
||||
// processed entities, like smoke puffs, gibs, shells, etc.
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
|
||||
#include "cg_media.h"
|
||||
|
||||
#ifdef _XBOX
|
||||
#define MAX_LOCAL_ENTITIES 128
|
||||
#else
|
||||
#define MAX_LOCAL_ENTITIES 512
|
||||
#endif
|
||||
localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
|
||||
localEntity_t cg_activeLocalEntities; // double linked list
|
||||
localEntity_t *cg_freeLocalEntities; // single linked list
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_InitLocalEntities
|
||||
|
||||
This is called at startup and for tournement restarts
|
||||
===================
|
||||
*/
|
||||
|
||||
void CG_InitLocalEntities( void ) {
|
||||
int i;
|
||||
|
||||
memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
|
||||
cg_activeLocalEntities.next = &cg_activeLocalEntities;
|
||||
cg_activeLocalEntities.prev = &cg_activeLocalEntities;
|
||||
cg_freeLocalEntities = cg_localEntities;
|
||||
for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
|
||||
cg_localEntities[i].next = &cg_localEntities[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_FreeLocalEntity
|
||||
==================
|
||||
*/
|
||||
void CG_FreeLocalEntity( localEntity_t *le ) {
|
||||
if ( !le->prev ) {
|
||||
CG_Error( "CG_FreeLocalEntity: not active" );
|
||||
}
|
||||
|
||||
// remove from the doubly linked active list
|
||||
le->prev->next = le->next;
|
||||
le->next->prev = le->prev;
|
||||
|
||||
// the free list is only singly linked
|
||||
le->next = cg_freeLocalEntities;
|
||||
cg_freeLocalEntities = le;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AllocLocalEntity
|
||||
|
||||
Will allways succeed, even if it requires freeing an old active entity
|
||||
===================
|
||||
*/
|
||||
localEntity_t *CG_AllocLocalEntity( void ) {
|
||||
localEntity_t *le;
|
||||
|
||||
if ( !cg_freeLocalEntities ) {
|
||||
// no free entities, so free the one at the end of the chain
|
||||
// remove the oldest active entity
|
||||
CG_FreeLocalEntity( cg_activeLocalEntities.prev );
|
||||
}
|
||||
|
||||
le = cg_freeLocalEntities;
|
||||
cg_freeLocalEntities = cg_freeLocalEntities->next;
|
||||
|
||||
memset( le, 0, sizeof( *le ) );
|
||||
|
||||
// link into the active list
|
||||
le->next = cg_activeLocalEntities.next;
|
||||
le->prev = &cg_activeLocalEntities;
|
||||
cg_activeLocalEntities.next->prev = le;
|
||||
cg_activeLocalEntities.next = le;
|
||||
le->ownerGentNum = -1;
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================================================================================
|
||||
|
||||
FRAGMENT PROCESSING
|
||||
|
||||
A fragment localentity interacts with the environment in some way (hitting walls),
|
||||
or generates more localentities along a trail.
|
||||
|
||||
====================================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FragmentBounceSound
|
||||
================
|
||||
*/
|
||||
void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace )
|
||||
{
|
||||
// half the fragments will make a bounce sounds
|
||||
if ( rand() & 1 )
|
||||
{
|
||||
sfxHandle_t s = 0;
|
||||
|
||||
switch( le->leBounceSoundType )
|
||||
{
|
||||
case LEBS_ROCK:
|
||||
s = cgs.media.rockBounceSound[Q_irand(0,1)];
|
||||
break;
|
||||
case LEBS_METAL:
|
||||
s = cgs.media.metalBounceSound[Q_irand(0,1)];// FIXME: make sure that this sound is registered properly...might still be rock bounce sound....
|
||||
break;
|
||||
}
|
||||
|
||||
if ( s )
|
||||
{
|
||||
cgi_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
|
||||
}
|
||||
|
||||
// bouncers only make the sound once...
|
||||
// FIXME: arbitrary...change if it bugs you
|
||||
le->leBounceSoundType = LEBS_NONE;
|
||||
}
|
||||
else if ( rand() & 1 )
|
||||
{
|
||||
// we may end up bouncing again, but each bounce reduces the chance of playing the sound again or they may make a lot of noise when they settle
|
||||
// FIXME: maybe just always do this??
|
||||
le->leBounceSoundType = LEBS_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_ReflectVelocity
|
||||
================
|
||||
*/
|
||||
void CG_ReflectVelocity( localEntity_t *le, trace_t *trace )
|
||||
{
|
||||
vec3_t velocity;
|
||||
float dot;
|
||||
int hitTime;
|
||||
|
||||
// reflect the velocity on the trace plane
|
||||
hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
|
||||
EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
|
||||
dot = DotProduct( velocity, trace->plane.normal );
|
||||
VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
|
||||
|
||||
VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
|
||||
|
||||
VectorCopy( trace->endpos, le->pos.trBase );
|
||||
le->pos.trTime = cg.time;
|
||||
|
||||
// check for stop, making sure that even on low FPS systems it doesn't bobble
|
||||
if ( trace->allsolid ||
|
||||
( trace->plane.normal[2] > 0 &&
|
||||
( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) )
|
||||
{
|
||||
le->pos.trType = TR_STATIONARY;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_AddFragment
|
||||
================
|
||||
*/
|
||||
void CG_AddFragment( localEntity_t *le )
|
||||
{
|
||||
vec3_t newOrigin;
|
||||
trace_t trace;
|
||||
// used to sink into the ground, but it looks better to maybe just fade them out
|
||||
int t;
|
||||
|
||||
t = le->endTime - cg.time;
|
||||
|
||||
if ( t < FRAG_FADE_TIME )
|
||||
{
|
||||
le->refEntity.renderfx |= RF_ALPHA_FADE;
|
||||
le->refEntity.shaderRGBA[0] = le->refEntity.shaderRGBA[1] = le->refEntity.shaderRGBA[2] = 255;
|
||||
le->refEntity.shaderRGBA[3] = ((float)t / FRAG_FADE_TIME) * 255.0f;
|
||||
}
|
||||
|
||||
if ( le->pos.trType == TR_STATIONARY )
|
||||
{
|
||||
if ( !(cgi_CM_PointContents( le->refEntity.origin, 0 ) & CONTENTS_SOLID ))
|
||||
{
|
||||
// thing is no longer in solid, so let gravity take it back
|
||||
VectorCopy( le->refEntity.origin, le->pos.trBase );
|
||||
VectorClear( le->pos.trDelta );
|
||||
le->pos.trTime = cg.time;
|
||||
le->pos.trType = TR_GRAVITY;
|
||||
}
|
||||
|
||||
cgi_R_AddRefEntityToScene( &le->refEntity );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate new position
|
||||
EvaluateTrajectory( &le->pos, cg.time, newOrigin );
|
||||
|
||||
le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
|
||||
VectorCopy( newOrigin, le->refEntity.lightingOrigin );
|
||||
|
||||
// trace a line from previous position to new position
|
||||
CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, le->ownerGentNum, CONTENTS_SOLID );
|
||||
if ( trace.fraction == 1.0 ) {
|
||||
// still in free fall
|
||||
VectorCopy( newOrigin, le->refEntity.origin );
|
||||
|
||||
if ( le->leFlags & LEF_TUMBLE ) {
|
||||
vec3_t angles;
|
||||
|
||||
EvaluateTrajectory( &le->angles, cg.time, angles );
|
||||
AnglesToAxis( angles, le->refEntity.axis );
|
||||
for(int k = 0; k < 3; k++)
|
||||
{
|
||||
VectorScale(le->refEntity.axis[k], le->radius, le->refEntity.axis[k]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cgi_R_AddRefEntityToScene( &le->refEntity );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// if it is in a nodrop zone, remove it
|
||||
// this keeps gibs from waiting at the bottom of pits of death
|
||||
// and floating levels
|
||||
if ( cgi_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP )
|
||||
{
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
// do a bouncy sound
|
||||
CG_FragmentBounceSound( le, &trace );
|
||||
|
||||
// reflect the velocity on the trace plane
|
||||
CG_ReflectVelocity( le, &trace );
|
||||
//FIXME: if LEF_TUMBLE, change avelocity too?
|
||||
|
||||
cgi_R_AddRefEntityToScene( &le->refEntity );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
|
||||
TRIVIAL LOCAL ENTITIES
|
||||
|
||||
These only do simple scaling or modulation before passing to the renderer
|
||||
=====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** CG_AddTeleporterEffect
|
||||
*/
|
||||
void CG_AddTeleporterEffect( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
|
||||
|
||||
re->shaderRGBA[0] =
|
||||
re->shaderRGBA[1] =
|
||||
re->shaderRGBA[2] =
|
||||
re->shaderRGBA[3] = 0xff * c;
|
||||
|
||||
cgi_R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
/*
|
||||
** CG_AddFadeRGB
|
||||
*/
|
||||
void CG_AddFadeRGB( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
c = ( le->endTime - cg.time ) * le->lifeRate;
|
||||
c *= 0xff;
|
||||
|
||||
re->shaderRGBA[0] = le->color[0] * c;
|
||||
re->shaderRGBA[1] = le->color[1] * c;
|
||||
re->shaderRGBA[2] = le->color[2] * c;
|
||||
re->shaderRGBA[3] = le->color[3] * c;
|
||||
|
||||
cgi_R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_AddPuff
|
||||
==================
|
||||
*/
|
||||
static void CG_AddPuff( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
vec3_t delta;
|
||||
float len;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
// fade / grow time
|
||||
c = ( le->endTime - cg.time ) / (float)( le->endTime - le->startTime );
|
||||
|
||||
re->shaderRGBA[0] = le->color[0] * c;
|
||||
re->shaderRGBA[1] = le->color[1] * c;
|
||||
re->shaderRGBA[2] = le->color[2] * c;
|
||||
|
||||
if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
|
||||
re->radius = le->radius * ( 1.0 - c ) + 8;
|
||||
}
|
||||
|
||||
EvaluateTrajectory( &le->pos, cg.time, re->origin );
|
||||
|
||||
// if the view would be "inside" the sprite, kill the sprite
|
||||
// so it doesn't add too much overdraw
|
||||
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
|
||||
len = VectorLength( delta );
|
||||
if ( len < le->radius ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
cgi_R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_AddLocalLight
|
||||
================
|
||||
*/
|
||||
static void CG_AddLocalLight( localEntity_t *le )
|
||||
{
|
||||
// There should be a light if this is being used, but hey...
|
||||
if ( le->light )
|
||||
{
|
||||
float light;
|
||||
|
||||
light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
|
||||
|
||||
if ( light < 0.5 )
|
||||
{
|
||||
light = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
light = 1.0 - ( light - 0.5 ) * 2;
|
||||
}
|
||||
|
||||
light = le->light * light;
|
||||
|
||||
cgi_R_AddLightToScene( le->refEntity.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
static void CG_AddFadeModel( localEntity_t *le )
|
||||
{
|
||||
refEntity_t *ent = &le->refEntity;
|
||||
|
||||
if ( cg.time < le->startTime )
|
||||
{
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
float frac = 1.0f - ((float)( cg.time - le->startTime )/(float)( le->endTime - le->startTime ));
|
||||
|
||||
ent->shaderRGBA[0] = le->color[0] * frac;
|
||||
ent->shaderRGBA[1] = le->color[1] * frac;
|
||||
ent->shaderRGBA[2] = le->color[2] * frac;
|
||||
ent->shaderRGBA[3] = le->color[3] * frac;
|
||||
|
||||
EvaluateTrajectory( &le->pos, cg.time, ent->origin );
|
||||
|
||||
// add the entity
|
||||
cgi_R_AddRefEntityToScene( ent );
|
||||
}
|
||||
|
||||
// NOTE: this is 100% for the demp2 alt-fire effect, so changes to the visual effect will affect game side demp2 code
|
||||
//---------------------------------------------------
|
||||
static void CG_AddFadeScaleModel( localEntity_t *le )
|
||||
{
|
||||
refEntity_t *ent = &le->refEntity;
|
||||
|
||||
float frac = ( cg.time - le->startTime )/((float)( le->endTime - le->startTime ));
|
||||
|
||||
frac *= frac * frac; // yes, this is completely ridiculous...but it causes the shell to grow slowly then "explode" at the end
|
||||
|
||||
ent->nonNormalizedAxes = qtrue;
|
||||
|
||||
AxisCopy( axisDefault, ent->axis );
|
||||
|
||||
VectorScale( ent->axis[0], le->radius * frac, ent->axis[0] );
|
||||
VectorScale( ent->axis[1], le->radius * frac, ent->axis[1] );
|
||||
VectorScale( ent->axis[2], le->radius * 0.5f * frac, ent->axis[2] );
|
||||
|
||||
frac = 1.0f - frac;
|
||||
|
||||
ent->shaderRGBA[0] = le->color[0] * frac;
|
||||
ent->shaderRGBA[1] = le->color[1] * frac;
|
||||
ent->shaderRGBA[2] = le->color[2] * frac;
|
||||
ent->shaderRGBA[3] = le->color[3] * frac;
|
||||
|
||||
// add the entity
|
||||
cgi_R_AddRefEntityToScene( ent );
|
||||
}
|
||||
|
||||
// create a quad that doesn't use a refEnt. Currently only for use with the DebugNav drawing so it doesn't have to use fx
|
||||
//------------------------------------------
|
||||
static void CG_AddQuad( localEntity_t *le )
|
||||
{
|
||||
polyVert_t verts[4];
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[0].xyz );
|
||||
verts[0].xyz[0] -= le->radius;
|
||||
verts[0].xyz[1] -= le->radius;
|
||||
verts[0].st[0] = 0;
|
||||
verts[0].st[1] = 0;
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
verts[i].modulate[0] = le->color[0];
|
||||
verts[i].modulate[1] = le->color[1];
|
||||
verts[i].modulate[2] = le->color[2];
|
||||
verts[i].modulate[3] = le->color[3];
|
||||
}
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[1].xyz );
|
||||
verts[1].xyz[0] -= le->radius;
|
||||
verts[1].xyz[1] += le->radius;
|
||||
verts[1].st[0] = 0;
|
||||
verts[1].st[1] = 1;
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[2].xyz );
|
||||
verts[2].xyz[0] += le->radius;
|
||||
verts[2].xyz[1] += le->radius;
|
||||
verts[2].st[0] = 1;
|
||||
verts[2].st[1] = 1;
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[3].xyz );
|
||||
verts[3].xyz[0] += le->radius;
|
||||
verts[3].xyz[1] -= le->radius;
|
||||
verts[3].st[0] = 1;
|
||||
verts[3].st[1] = 0;
|
||||
|
||||
cgi_R_AddPolyToScene( le->refEntity.customShader, 4, verts );
|
||||
}
|
||||
|
||||
// create a sprite that doesn't use a refEnt. Currently only for use with the DebugNav drawing so it doesn't have to use fx
|
||||
//------------------------------------------
|
||||
static void CG_AddSprite( localEntity_t *le )
|
||||
{
|
||||
polyVert_t verts[4];
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[0].xyz );
|
||||
VectorMA( verts[0].xyz, -le->radius, cg.refdef.viewaxis[2], verts[0].xyz );
|
||||
VectorMA( verts[0].xyz, -le->radius, cg.refdef.viewaxis[1], verts[0].xyz );
|
||||
verts[0].st[0] = 0;
|
||||
verts[0].st[1] = 0;
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
verts[i].modulate[0] = le->color[0];
|
||||
verts[i].modulate[1] = le->color[1];
|
||||
verts[i].modulate[2] = le->color[2];
|
||||
verts[i].modulate[3] = le->color[3];
|
||||
}
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[1].xyz );
|
||||
VectorMA( verts[1].xyz, -le->radius, cg.refdef.viewaxis[2], verts[1].xyz );
|
||||
VectorMA( verts[1].xyz, le->radius, cg.refdef.viewaxis[1], verts[1].xyz );
|
||||
verts[1].st[0] = 0;
|
||||
verts[1].st[1] = 1;
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[2].xyz );
|
||||
VectorMA( verts[2].xyz, le->radius, cg.refdef.viewaxis[2], verts[2].xyz );
|
||||
VectorMA( verts[2].xyz, le->radius, cg.refdef.viewaxis[1], verts[2].xyz );
|
||||
verts[2].st[0] = 1;
|
||||
verts[2].st[1] = 1;
|
||||
|
||||
VectorCopy( le->refEntity.origin, verts[3].xyz );
|
||||
VectorMA( verts[3].xyz, le->radius, cg.refdef.viewaxis[2], verts[3].xyz );
|
||||
VectorMA( verts[3].xyz, -le->radius, cg.refdef.viewaxis[1], verts[3].xyz );
|
||||
verts[3].st[0] = 1;
|
||||
verts[3].st[1] = 0;
|
||||
|
||||
cgi_R_AddPolyToScene( le->refEntity.customShader, 4, verts );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AddLine
|
||||
|
||||
for beams and the like.
|
||||
===================
|
||||
*/
|
||||
void CG_AddLine( localEntity_t *le )
|
||||
{
|
||||
refEntity_t *re;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
re->reType = RT_LINE;
|
||||
|
||||
cgi_R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AddLocalEntities
|
||||
|
||||
===================
|
||||
*/
|
||||
void CG_AddLocalEntities( void )
|
||||
{
|
||||
localEntity_t *le, *next;
|
||||
|
||||
// walk the list backwards, so any new local entities generated
|
||||
// (trails, marks, etc) will be present this frame
|
||||
le = cg_activeLocalEntities.prev;
|
||||
for ( ; le != &cg_activeLocalEntities ; le = next ) {
|
||||
// grab next now, so if the local entity is freed we
|
||||
// still have it
|
||||
next = le->prev;
|
||||
|
||||
if ( cg.time >= le->endTime ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
continue;
|
||||
}
|
||||
switch ( le->leType ) {
|
||||
default:
|
||||
CG_Error( "Bad leType: %i", le->leType );
|
||||
break;
|
||||
|
||||
case LE_MARK:
|
||||
break;
|
||||
|
||||
case LE_FADE_MODEL:
|
||||
CG_AddFadeModel( le );
|
||||
break;
|
||||
|
||||
case LE_FADE_SCALE_MODEL:
|
||||
CG_AddFadeScaleModel( le );
|
||||
break;
|
||||
|
||||
case LE_FRAGMENT:
|
||||
CG_AddFragment( le );
|
||||
break;
|
||||
|
||||
case LE_PUFF:
|
||||
CG_AddPuff( le );
|
||||
break;
|
||||
|
||||
case LE_FADE_RGB: // teleporters, railtrails
|
||||
CG_AddFadeRGB( le );
|
||||
break;
|
||||
|
||||
case LE_LIGHT:
|
||||
CG_AddLocalLight( le );
|
||||
break;
|
||||
|
||||
case LE_LINE: // oriented lines for FX
|
||||
CG_AddLine( le );
|
||||
break;
|
||||
|
||||
// Use for debug only
|
||||
case LE_QUAD:
|
||||
CG_AddQuad( le );
|
||||
break;
|
||||
|
||||
case LE_SPRITE:
|
||||
CG_AddSprite( le );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
4442
code/cgame/cg_main.cpp
Normal file
4442
code/cgame/cg_main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
264
code/cgame/cg_marks.cpp
Normal file
264
code/cgame/cg_marks.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
// cg_marks.c -- wall marks
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
MARK POLYS
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
|
||||
markPoly_t cg_activeMarkPolys; // double linked list
|
||||
markPoly_t *cg_freeMarkPolys; // single linked list
|
||||
markPoly_t cg_markPolys[MAX_MARK_POLYS];
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_InitMarkPolys
|
||||
|
||||
This is called at startup and for tournement restarts
|
||||
===================
|
||||
*/
|
||||
void CG_InitMarkPolys( void ) {
|
||||
int i;
|
||||
|
||||
memset( cg_markPolys, 0, sizeof(cg_markPolys) );
|
||||
|
||||
cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
|
||||
cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
|
||||
cg_freeMarkPolys = cg_markPolys;
|
||||
for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
|
||||
cg_markPolys[i].nextMark = &cg_markPolys[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_FreeMarkPoly
|
||||
==================
|
||||
*/
|
||||
void CG_FreeMarkPoly( markPoly_t *le ) {
|
||||
if ( !le->prevMark ) {
|
||||
CG_Error( "CG_FreeLocalEntity: not active" );
|
||||
}
|
||||
|
||||
// remove from the doubly linked active list
|
||||
le->prevMark->nextMark = le->nextMark;
|
||||
le->nextMark->prevMark = le->prevMark;
|
||||
|
||||
// the free list is only singly linked
|
||||
le->nextMark = cg_freeMarkPolys;
|
||||
cg_freeMarkPolys = le;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AllocMark
|
||||
|
||||
Will allways succeed, even if it requires freeing an old active mark
|
||||
===================
|
||||
*/
|
||||
markPoly_t *CG_AllocMark( void ) {
|
||||
markPoly_t *le;
|
||||
int time;
|
||||
|
||||
if ( !cg_freeMarkPolys ) {
|
||||
// no free entities, so free the one at the end of the chain
|
||||
// remove the oldest active entity
|
||||
time = cg_activeMarkPolys.prevMark->time;
|
||||
while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
|
||||
CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
|
||||
}
|
||||
}
|
||||
|
||||
le = cg_freeMarkPolys;
|
||||
cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
|
||||
|
||||
memset( le, 0, sizeof( *le ) );
|
||||
|
||||
// link into the active list
|
||||
le->nextMark = cg_activeMarkPolys.nextMark;
|
||||
le->prevMark = &cg_activeMarkPolys;
|
||||
cg_activeMarkPolys.nextMark->prevMark = le;
|
||||
cg_activeMarkPolys.nextMark = le;
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_ImpactMark
|
||||
|
||||
origin should be a point within a unit of the plane
|
||||
dir should be the plane normal
|
||||
|
||||
temporary marks will not be stored or randomly oriented, but immediately
|
||||
passed to the renderer.
|
||||
=================
|
||||
*/
|
||||
#define MAX_MARK_FRAGMENTS 128
|
||||
#define MAX_MARK_POINTS 384
|
||||
|
||||
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
|
||||
float orientation, float red, float green, float blue, float alpha,
|
||||
qboolean alphaFade, float radius, qboolean temporary ) {
|
||||
vec3_t axis[3];
|
||||
float texCoordScale;
|
||||
vec3_t originalPoints[4];
|
||||
byte colors[4];
|
||||
int i, j;
|
||||
int numFragments;
|
||||
markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
|
||||
vec3_t markPoints[MAX_MARK_POINTS];
|
||||
vec3_t projection;
|
||||
|
||||
if ( !cg_addMarks.integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( radius <= 0 ) {
|
||||
CG_Error( "CG_ImpactMark called with <= 0 radius" );
|
||||
}
|
||||
|
||||
// create the texture axis
|
||||
VectorNormalize2( dir, axis[0] );
|
||||
PerpendicularVector( axis[1], axis[0] );
|
||||
RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
|
||||
CrossProduct( axis[0], axis[2], axis[1] );
|
||||
|
||||
texCoordScale = 0.5 * 1.0 / radius;
|
||||
|
||||
// create the full polygon
|
||||
for ( i = 0 ; i < 3 ; i++ ) {
|
||||
originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
|
||||
originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
|
||||
originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
|
||||
originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
|
||||
}
|
||||
|
||||
// get the fragments
|
||||
VectorScale( dir, -20, projection );
|
||||
numFragments = cgi_CM_MarkFragments( 4, (const float (*)[3])originalPoints,
|
||||
projection, MAX_MARK_POINTS, markPoints[0],
|
||||
MAX_MARK_FRAGMENTS, markFragments );
|
||||
|
||||
colors[0] = red * 255;
|
||||
colors[1] = green * 255;
|
||||
colors[2] = blue * 255;
|
||||
colors[3] = alpha * 255;
|
||||
|
||||
for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
|
||||
polyVert_t *v;
|
||||
polyVert_t verts[MAX_VERTS_ON_POLY];
|
||||
markPoly_t *mark;
|
||||
|
||||
// we have an upper limit on the complexity of polygons
|
||||
// that we store persistantly
|
||||
if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
|
||||
mf->numPoints = MAX_VERTS_ON_POLY;
|
||||
}
|
||||
for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
|
||||
vec3_t delta;
|
||||
|
||||
VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
|
||||
|
||||
VectorSubtract( v->xyz, origin, delta );
|
||||
v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
|
||||
v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
|
||||
*(int *)v->modulate = *(int *)colors;
|
||||
}
|
||||
|
||||
// if it is a temporary (shadow) mark, add it immediately and forget about it
|
||||
if ( temporary ) {
|
||||
cgi_R_AddPolyToScene( markShader, mf->numPoints, verts );
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise save it persistantly
|
||||
mark = CG_AllocMark();
|
||||
mark->time = cg.time;
|
||||
mark->alphaFade = alphaFade;
|
||||
mark->markShader = markShader;
|
||||
mark->poly.numVerts = mf->numPoints;
|
||||
mark->color[0] = colors[0];//red;
|
||||
mark->color[1] = colors[1];//green;
|
||||
mark->color[2] = colors[2];//blue;
|
||||
mark->color[3] = colors[3];//alpha;
|
||||
memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_AddMarks
|
||||
===============
|
||||
*/
|
||||
#define MARK_TOTAL_TIME 10000
|
||||
#define MARK_FADE_TIME 1000
|
||||
|
||||
void CG_AddMarks( void ) {
|
||||
int j;
|
||||
markPoly_t *mp, *next;
|
||||
int t;
|
||||
int fade;
|
||||
|
||||
if ( !cg_addMarks.integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp = cg_activeMarkPolys.nextMark;
|
||||
for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
|
||||
// grab next now, so if the local entity is freed we
|
||||
// still have it
|
||||
next = mp->nextMark;
|
||||
|
||||
// see if it is time to completely remove it
|
||||
if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
|
||||
CG_FreeMarkPoly( mp );
|
||||
continue;
|
||||
}
|
||||
|
||||
// fade all marks out with time
|
||||
t = mp->time + MARK_TOTAL_TIME - cg.time;
|
||||
if ( t < MARK_FADE_TIME ) {
|
||||
fade = 255 * t / MARK_FADE_TIME;
|
||||
if ( mp->alphaFade ) {
|
||||
for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
|
||||
mp->verts[j].modulate[3] = fade;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = (float)t / MARK_FADE_TIME;
|
||||
for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
|
||||
mp->verts[j].modulate[0] = mp->color[0] * f;
|
||||
mp->verts[j].modulate[1] = mp->color[1] * f;
|
||||
mp->verts[j].modulate[2] = mp->color[2] * f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
|
||||
mp->verts[j].modulate[0] = mp->color[0];
|
||||
mp->verts[j].modulate[1] = mp->color[1];
|
||||
mp->verts[j].modulate[2] = mp->color[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cgi_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
|
||||
}
|
||||
}
|
||||
|
||||
417
code/cgame/cg_media.h
Normal file
417
code/cgame/cg_media.h
Normal file
@@ -0,0 +1,417 @@
|
||||
#ifndef __CG_MEDIA_H_
|
||||
#define __CG_MEDIA_H_
|
||||
|
||||
//#define NUM_CROSSHAIRS 9
|
||||
#define NUM_CROSSHAIRS 1
|
||||
|
||||
typedef enum {
|
||||
FOOTSTEP_STONEWALK,
|
||||
FOOTSTEP_STONERUN,
|
||||
FOOTSTEP_METALWALK,
|
||||
FOOTSTEP_METALRUN,
|
||||
FOOTSTEP_PIPEWALK,
|
||||
FOOTSTEP_PIPERUN,
|
||||
FOOTSTEP_SPLASH,
|
||||
FOOTSTEP_WADE,
|
||||
FOOTSTEP_SWIM,
|
||||
FOOTSTEP_SNOWWALK,
|
||||
FOOTSTEP_SNOWRUN,
|
||||
FOOTSTEP_SANDWALK,
|
||||
FOOTSTEP_SANDRUN,
|
||||
FOOTSTEP_GRASSWALK,
|
||||
FOOTSTEP_GRASSRUN,
|
||||
FOOTSTEP_DIRTWALK,
|
||||
FOOTSTEP_DIRTRUN,
|
||||
FOOTSTEP_MUDWALK,
|
||||
FOOTSTEP_MUDRUN,
|
||||
FOOTSTEP_GRAVELWALK,
|
||||
FOOTSTEP_GRAVELRUN,
|
||||
FOOTSTEP_RUGWALK,
|
||||
FOOTSTEP_RUGRUN,
|
||||
FOOTSTEP_WOODWALK,
|
||||
FOOTSTEP_WOODRUN,
|
||||
|
||||
FOOTSTEP_TOTAL
|
||||
} footstep_t;
|
||||
|
||||
#define ICON_WEAPONS 0
|
||||
#define ICON_FORCE 1
|
||||
#define ICON_INVENTORY 2
|
||||
|
||||
#define MAX_HUD_TICS 4
|
||||
|
||||
|
||||
typedef struct HUDMenuItem_s
|
||||
{
|
||||
char *menuName;
|
||||
char *itemName;
|
||||
int xPos;
|
||||
int yPos;
|
||||
int width;
|
||||
int height;
|
||||
vec4_t color;
|
||||
qhandle_t background;
|
||||
} HUDMenuItem_t;
|
||||
extern HUDMenuItem_t healthTics[];
|
||||
extern HUDMenuItem_t armorTics[];
|
||||
extern HUDMenuItem_t ammoTics[];
|
||||
extern HUDMenuItem_t forceTics[];
|
||||
extern HUDMenuItem_t otherHUDBits[];
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OHB_HEALTHAMOUNT = 0,
|
||||
OHB_ARMORAMOUNT,
|
||||
OHB_FORCEAMOUNT,
|
||||
OHB_AMMOAMOUNT,
|
||||
OHB_SABERSTYLE_STRONG,
|
||||
OHB_SABERSTYLE_MEDIUM,
|
||||
OHB_SABERSTYLE_FAST,
|
||||
OHB_SCANLINE_LEFT,
|
||||
OHB_SCANLINE_RIGHT,
|
||||
OHB_FRAME_LEFT,
|
||||
OHB_FRAME_RIGHT,
|
||||
OHB_MAX
|
||||
} otherhudbits_t;
|
||||
|
||||
#define NUM_CHUNK_MODELS 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CHUNK_METAL1 = 0,
|
||||
CHUNK_METAL2,
|
||||
CHUNK_ROCK1,
|
||||
CHUNK_ROCK2,
|
||||
CHUNK_ROCK3,
|
||||
CHUNK_CRATE1,
|
||||
CHUNK_CRATE2,
|
||||
CHUNK_WHITE_METAL,
|
||||
NUM_CHUNK_TYPES
|
||||
};
|
||||
|
||||
// all of the model, shader, and sound references that are
|
||||
// loaded at gamestate time are stored in cgMedia_t
|
||||
// Other media that can be tied to clients, weapons, or items are
|
||||
// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
|
||||
typedef struct {
|
||||
qhandle_t charsetShader;
|
||||
qhandle_t whiteShader;
|
||||
|
||||
qhandle_t crosshairShader[NUM_CROSSHAIRS];
|
||||
qhandle_t backTileShader;
|
||||
// qhandle_t noammoShader;
|
||||
|
||||
// qhandle_t numberShaders[11];
|
||||
qhandle_t smallnumberShaders[11];
|
||||
// qhandle_t chunkyNumberShaders[11];
|
||||
|
||||
qhandle_t loadTick;
|
||||
// qhandle_t loadTickCap;
|
||||
|
||||
// HUD artwork
|
||||
// int currentBackground;
|
||||
// qhandle_t weaponbox;
|
||||
// qhandle_t weaponIconBackground;
|
||||
// qhandle_t forceIconBackground;
|
||||
// qhandle_t inventoryIconBackground;
|
||||
qhandle_t turretComputerOverlayShader;
|
||||
qhandle_t turretCrossHairShader;
|
||||
|
||||
//Chunks
|
||||
qhandle_t chunkModels[NUM_CHUNK_TYPES][4];
|
||||
sfxHandle_t chunkSound;
|
||||
sfxHandle_t grateSound;
|
||||
sfxHandle_t rockBreakSound;
|
||||
sfxHandle_t rockBounceSound[2];
|
||||
sfxHandle_t metalBounceSound[2];
|
||||
sfxHandle_t glassChunkSound;
|
||||
sfxHandle_t crateBreakSound[2];
|
||||
|
||||
// Saber shaders
|
||||
//-----------------------------
|
||||
qhandle_t forceCoronaShader;
|
||||
qhandle_t saberBlurShader;
|
||||
qhandle_t swordTrailShader;
|
||||
qhandle_t yellowDroppedSaberShader; // glow
|
||||
|
||||
qhandle_t redSaberGlowShader;
|
||||
qhandle_t redSaberCoreShader;
|
||||
qhandle_t orangeSaberGlowShader;
|
||||
qhandle_t orangeSaberCoreShader;
|
||||
qhandle_t yellowSaberGlowShader;
|
||||
qhandle_t yellowSaberCoreShader;
|
||||
qhandle_t greenSaberGlowShader;
|
||||
qhandle_t greenSaberCoreShader;
|
||||
qhandle_t blueSaberGlowShader;
|
||||
qhandle_t blueSaberCoreShader;
|
||||
qhandle_t purpleSaberGlowShader;
|
||||
qhandle_t purpleSaberCoreShader;
|
||||
|
||||
qhandle_t explosionModel;
|
||||
qhandle_t surfaceExplosionShader;
|
||||
|
||||
qhandle_t halfShieldModel;
|
||||
|
||||
qhandle_t solidWhiteShader;
|
||||
qhandle_t electricBodyShader;
|
||||
qhandle_t electricBody2Shader;
|
||||
qhandle_t refractShader;
|
||||
qhandle_t boltShader;
|
||||
|
||||
// Disruptor zoom graphics
|
||||
qhandle_t disruptorMask;
|
||||
qhandle_t disruptorInsert;
|
||||
qhandle_t disruptorLight;
|
||||
qhandle_t disruptorInsertTick;
|
||||
|
||||
// Binocular graphics
|
||||
/*
|
||||
qhandle_t binocularCircle;
|
||||
qhandle_t binocularMask;
|
||||
qhandle_t binocularArrow;
|
||||
qhandle_t binocularTri;
|
||||
qhandle_t binocularStatic;
|
||||
qhandle_t binocularOverlay;
|
||||
*/
|
||||
|
||||
// LA Goggles graphics
|
||||
/*
|
||||
qhandle_t laGogglesStatic;
|
||||
qhandle_t laGogglesMask;
|
||||
qhandle_t laGogglesSideBit;
|
||||
qhandle_t laGogglesBracket;
|
||||
qhandle_t laGogglesArrow;
|
||||
*/
|
||||
|
||||
// wall mark shaders
|
||||
qhandle_t scavMarkShader;
|
||||
qhandle_t rivetMarkShader;
|
||||
|
||||
qhandle_t shadowMarkShader;
|
||||
qhandle_t wakeMarkShader;
|
||||
qhandle_t fsrMarkShader;
|
||||
qhandle_t fslMarkShader;
|
||||
qhandle_t fshrMarkShader;
|
||||
qhandle_t fshlMarkShader;
|
||||
|
||||
qhandle_t damageBlendBlobShader;
|
||||
|
||||
// fonts...
|
||||
//
|
||||
qhandle_t qhFontSmall;
|
||||
qhandle_t qhFontMedium;
|
||||
|
||||
// special effects models / etc.
|
||||
qhandle_t personalShieldShader;
|
||||
qhandle_t cloakedShader;
|
||||
|
||||
// Interface media
|
||||
qhandle_t ammoslider;
|
||||
// qhandle_t emplacedHealthBarShader;
|
||||
|
||||
qhandle_t DPForcePowerOverlay;
|
||||
|
||||
qhandle_t bdecal_burnmark1;
|
||||
qhandle_t bdecal_saberglowmark;
|
||||
|
||||
qhandle_t messageLitOn;
|
||||
qhandle_t messageLitOff;
|
||||
qhandle_t messageObjCircle;
|
||||
|
||||
// qhandle_t batteryChargeShader;
|
||||
qhandle_t useableHint;
|
||||
|
||||
qhandle_t levelLoad;
|
||||
|
||||
//new stuff for Jedi Academy
|
||||
//force power icons
|
||||
// qhandle_t forcePowerIcons[NUM_FORCE_POWERS];
|
||||
qhandle_t rageRecShader;
|
||||
qhandle_t playerShieldDamage;
|
||||
qhandle_t forceSightBubble;
|
||||
qhandle_t forceShell;
|
||||
qhandle_t sightShell;
|
||||
qhandle_t drainShader;
|
||||
|
||||
// sounds
|
||||
sfxHandle_t disintegrateSound;
|
||||
sfxHandle_t disintegrate2Sound;
|
||||
sfxHandle_t disintegrate3Sound;
|
||||
|
||||
sfxHandle_t grenadeBounce1;
|
||||
sfxHandle_t grenadeBounce2;
|
||||
|
||||
sfxHandle_t flechetteStickSound;
|
||||
sfxHandle_t detPackStickSound;
|
||||
sfxHandle_t tripMineStickSound;
|
||||
|
||||
sfxHandle_t selectSound;
|
||||
sfxHandle_t selectSound2;
|
||||
sfxHandle_t overchargeSlowSound;
|
||||
sfxHandle_t overchargeFastSound;
|
||||
sfxHandle_t overchargeLoopSound;
|
||||
sfxHandle_t overchargeEndSound;
|
||||
|
||||
// sfxHandle_t useNothingSound;
|
||||
sfxHandle_t footsteps[FOOTSTEP_TOTAL][4];
|
||||
|
||||
// sfxHandle_t talkSound;
|
||||
sfxHandle_t noAmmoSound;
|
||||
|
||||
sfxHandle_t landSound;
|
||||
sfxHandle_t rollSound;
|
||||
sfxHandle_t messageLitSound;
|
||||
|
||||
sfxHandle_t batteryChargeSound;
|
||||
|
||||
sfxHandle_t watrInSound;
|
||||
sfxHandle_t watrOutSound;
|
||||
sfxHandle_t watrUnSound;
|
||||
|
||||
sfxHandle_t lavaInSound;
|
||||
sfxHandle_t lavaOutSound;
|
||||
sfxHandle_t lavaUnSound;
|
||||
|
||||
sfxHandle_t noforceSound;
|
||||
|
||||
// Zoom
|
||||
sfxHandle_t zoomStart;
|
||||
sfxHandle_t zoomLoop;
|
||||
sfxHandle_t zoomEnd;
|
||||
sfxHandle_t disruptorZoomLoop;
|
||||
|
||||
//new stuff for Jedi Academy
|
||||
sfxHandle_t drainSound;
|
||||
|
||||
#ifdef _IMMERSION
|
||||
//force feedback stuff
|
||||
ffHandle_t grenadeBounce1Force;
|
||||
ffHandle_t grenadeBounce2Force;
|
||||
|
||||
ffHandle_t selectForce;
|
||||
|
||||
ffHandle_t footstepForces[FOOTSTEP_TOTAL][4];
|
||||
|
||||
ffHandle_t noAmmoForce;
|
||||
|
||||
ffHandle_t landForce;
|
||||
ffHandle_t messageLitForce;
|
||||
|
||||
ffHandle_t watrInForce;
|
||||
ffHandle_t watrOutForce;
|
||||
ffHandle_t watrUnForce;
|
||||
|
||||
ffHandle_t zoomStartForce;
|
||||
ffHandle_t zoomLoopForce;
|
||||
ffHandle_t zoomEndForce;
|
||||
ffHandle_t disruptorZoomLoopForce;
|
||||
#endif // _IMMERSION
|
||||
} cgMedia_t;
|
||||
|
||||
|
||||
// Stored FX handles
|
||||
//--------------------
|
||||
typedef struct
|
||||
{
|
||||
// BRYAR PISTOL
|
||||
fxHandle_t bryarShotEffect;
|
||||
fxHandle_t bryarPowerupShotEffect;
|
||||
fxHandle_t bryarWallImpactEffect;
|
||||
fxHandle_t bryarWallImpactEffect2;
|
||||
fxHandle_t bryarWallImpactEffect3;
|
||||
fxHandle_t bryarFleshImpactEffect;
|
||||
|
||||
// BLASTER
|
||||
fxHandle_t blasterShotEffect;
|
||||
fxHandle_t blasterOverchargeEffect;
|
||||
fxHandle_t blasterWallImpactEffect;
|
||||
fxHandle_t blasterFleshImpactEffect;
|
||||
|
||||
// BOWCASTER
|
||||
fxHandle_t bowcasterShotEffect;
|
||||
fxHandle_t bowcasterBounceEffect;
|
||||
fxHandle_t bowcasterImpactEffect;
|
||||
|
||||
// FLECHETTE
|
||||
fxHandle_t flechetteShotEffect;
|
||||
fxHandle_t flechetteAltShotEffect;
|
||||
fxHandle_t flechetteShotDeathEffect;
|
||||
fxHandle_t flechetteFleshImpactEffect;
|
||||
fxHandle_t flechetteRicochetEffect;
|
||||
|
||||
//FORCE
|
||||
fxHandle_t forceConfusion;
|
||||
fxHandle_t forceLightning;
|
||||
fxHandle_t forceLightningWide;
|
||||
//fxHandle_t forceInvincibility;
|
||||
fxHandle_t forceHeal;
|
||||
|
||||
//new stuff for Jedi Academy
|
||||
fxHandle_t forceDrain;
|
||||
fxHandle_t forceDrainWide;
|
||||
fxHandle_t forceDrained;
|
||||
|
||||
//footstep effects
|
||||
fxHandle_t footstepMud;
|
||||
fxHandle_t footstepSand;
|
||||
fxHandle_t footstepSnow;
|
||||
fxHandle_t footstepGravel;
|
||||
//landing effects
|
||||
fxHandle_t landingMud;
|
||||
fxHandle_t landingSand;
|
||||
fxHandle_t landingDirt;
|
||||
fxHandle_t landingSnow;
|
||||
fxHandle_t landingGravel;
|
||||
} cgEffects_t;
|
||||
|
||||
|
||||
// The client game static (cgs) structure hold everything
|
||||
// loaded or calculated from the gamestate. It will NOT
|
||||
// be cleared when a tournement restart is done, allowing
|
||||
// all clients to begin playing instantly
|
||||
#define STRIPED_LEVELNAME_VARIATIONS 3 // sigh, to cope with levels that use text from >1 SP file (plus 1 for common)
|
||||
typedef struct {
|
||||
gameState_t gameState; // gamestate from server
|
||||
glconfig_t glconfig; // rendering configuration
|
||||
|
||||
int serverCommandSequence; // reliable command stream counter
|
||||
|
||||
// parsed from serverinfo
|
||||
int dmflags;
|
||||
int teamflags;
|
||||
int timelimit;
|
||||
int maxclients;
|
||||
char mapname[MAX_QPATH];
|
||||
char stripLevelName[STRIPED_LEVELNAME_VARIATIONS][MAX_QPATH];
|
||||
|
||||
//
|
||||
// locally derived information from gamestate
|
||||
//
|
||||
qhandle_t model_draw[MAX_MODELS];
|
||||
sfxHandle_t sound_precache[MAX_SOUNDS];
|
||||
#ifdef _IMMERSION
|
||||
ffHandle_t force_precache[MAX_FORCES];
|
||||
#endif // _IMMERSION
|
||||
// Ghoul2 start
|
||||
qhandle_t skins[MAX_CHARSKINS];
|
||||
|
||||
// Ghoul2 end
|
||||
|
||||
int numInlineModels;
|
||||
qhandle_t inlineDrawModel[MAX_SUBMODELS];
|
||||
vec3_t inlineModelMidpoints[MAX_SUBMODELS];
|
||||
|
||||
clientInfo_t clientinfo[MAX_CLIENTS];
|
||||
|
||||
// media
|
||||
cgMedia_t media;
|
||||
|
||||
// effects
|
||||
cgEffects_t effects;
|
||||
|
||||
} cgs_t;
|
||||
|
||||
extern cgs_t cgs;
|
||||
|
||||
#endif //__CG_MEDIA_H_
|
||||
8262
code/cgame/cg_players.cpp
Normal file
8262
code/cgame/cg_players.cpp
Normal file
File diff suppressed because it is too large
Load Diff
364
code/cgame/cg_playerstate.cpp
Normal file
364
code/cgame/cg_playerstate.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
// cg_playerstate.c -- this file acts on changes in a new playerState_t
|
||||
// With normal play, this will be done after local prediction, but when
|
||||
// following another player or playing back a demo, it will be checked
|
||||
// when the snapshot transitions like all the other entities
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_CheckAmmo
|
||||
|
||||
If the ammo has gone low enough to generate the warning, play a sound
|
||||
==============
|
||||
*/
|
||||
void CG_CheckAmmo( void )
|
||||
{
|
||||
// int i;
|
||||
int total;
|
||||
int previous;
|
||||
// int weapons;
|
||||
|
||||
#if 0
|
||||
|
||||
// see about how many seconds of ammo we have remaining
|
||||
weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
|
||||
total = 0;
|
||||
|
||||
for ( i = WP_SABER; i < WP_NUM_WEAPONS i++ )
|
||||
{
|
||||
if ( ! ( weapons & ( 1 << i ) ) )
|
||||
continue;
|
||||
|
||||
/*
|
||||
switch ( i )
|
||||
{
|
||||
case WP_ROCKET_LAUNCHER:
|
||||
case WP_GRENADE_LAUNCHER:
|
||||
case WP_RAILGUN:
|
||||
case WP_SHOTGUN:
|
||||
total += cg.snap->ps.ammo[i] * 1000;
|
||||
break;
|
||||
default:
|
||||
total += cg.snap->ps.ammo[i] * 200;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( total >= 5000 )
|
||||
{
|
||||
cg.lowAmmoWarning = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't bother drawing the ammo warning when have no weapon selected
|
||||
if ( cg.weaponSelect == WP_NONE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
total = cg.snap->ps.ammo[weaponData[cg.weaponSelect].ammoIndex];
|
||||
|
||||
if (total > weaponData[cg.weaponSelect].ammoLow) // Low on ammo?
|
||||
{
|
||||
cg.lowAmmoWarning = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
previous = cg.lowAmmoWarning;
|
||||
|
||||
if (!total) // We're completely freak'in out!
|
||||
{
|
||||
cg.lowAmmoWarning = 2;
|
||||
}
|
||||
else // Got a little left
|
||||
{
|
||||
cg.lowAmmoWarning = 1;
|
||||
}
|
||||
|
||||
// play a sound on transitions
|
||||
if ( cg.lowAmmoWarning != previous ) {
|
||||
cgi_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND ); //"sound/weapons/noammo.wav"
|
||||
#ifdef _IMMERSION
|
||||
cgi_FF_Start( cgs.media.noAmmoForce, FF_CLIENT_LOCAL );
|
||||
#endif // _IMMERSION
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_DamageFeedback
|
||||
==============
|
||||
*/
|
||||
void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
|
||||
float left, front, up;
|
||||
float kick;
|
||||
int health;
|
||||
float scale;
|
||||
vec3_t dir;
|
||||
vec3_t angles;
|
||||
float dist;
|
||||
float yaw, pitch;
|
||||
|
||||
//FIXME: Based on MOD, do different kinds of damage effects,
|
||||
// for example, Borg damage could progressively tint screen green and raise FOV?
|
||||
|
||||
// the lower on health you are, the greater the view kick will be
|
||||
health = cg.snap->ps.stats[STAT_HEALTH];
|
||||
if ( health < 40 ) {
|
||||
scale = 1;
|
||||
} else {
|
||||
scale = 40.0 / health;
|
||||
}
|
||||
kick = damage * scale;
|
||||
|
||||
if (kick < 5)
|
||||
kick = 5;
|
||||
if (kick > 10)
|
||||
kick = 10;
|
||||
|
||||
// if yaw and pitch are both 255, make the damage always centered (falling, etc)
|
||||
if ( yawByte == 255 && pitchByte == 255 ) {
|
||||
cg.damageX = 0;
|
||||
cg.damageY = 0;
|
||||
cg.v_dmg_roll = 0;
|
||||
cg.v_dmg_pitch = -kick;
|
||||
} else {
|
||||
// positional
|
||||
pitch = pitchByte / 255.0 * 360;
|
||||
yaw = yawByte / 255.0 * 360;
|
||||
|
||||
angles[PITCH] = pitch;
|
||||
angles[YAW] = yaw;
|
||||
angles[ROLL] = 0;
|
||||
|
||||
AngleVectors( angles, dir, NULL, NULL );
|
||||
VectorSubtract( vec3_origin, dir, dir );
|
||||
|
||||
front = DotProduct (dir, cg.refdef.viewaxis[0] );
|
||||
left = DotProduct (dir, cg.refdef.viewaxis[1] );
|
||||
up = DotProduct (dir, cg.refdef.viewaxis[2] );
|
||||
|
||||
dir[0] = front;
|
||||
dir[1] = left;
|
||||
dir[2] = 0;
|
||||
dist = VectorLength( dir );
|
||||
if ( dist < 0.1 ) {
|
||||
dist = 0.1f;
|
||||
}
|
||||
|
||||
cg.v_dmg_roll = kick * left;
|
||||
|
||||
cg.v_dmg_pitch = -kick * front;
|
||||
|
||||
if ( front <= 0.1 ) {
|
||||
front = 0.1f;
|
||||
}
|
||||
cg.damageX = -left / front;
|
||||
cg.damageY = up / dist;
|
||||
}
|
||||
|
||||
// clamp the position
|
||||
if ( cg.damageX > 1.0 ) {
|
||||
cg.damageX = 1.0;
|
||||
}
|
||||
if ( cg.damageX < - 1.0 ) {
|
||||
cg.damageX = -1.0;
|
||||
}
|
||||
|
||||
if ( cg.damageY > 1.0 ) {
|
||||
cg.damageY = 1.0;
|
||||
}
|
||||
if ( cg.damageY < - 1.0 ) {
|
||||
cg.damageY = -1.0;
|
||||
}
|
||||
|
||||
// don't let the screen flashes vary as much
|
||||
if ( kick > 10 ) {
|
||||
kick = 10;
|
||||
}
|
||||
cg.damageValue = kick;
|
||||
cg.v_dmg_time = cg.time + DAMAGE_TIME;
|
||||
cg.damageTime = cg.snap->serverTime;
|
||||
#ifdef _IMMERSION
|
||||
cgi_FF_Start( cgi_FF_Register( "fffx/player/damage", FF_CHANNEL_DAMAGE ), cg.snap->ps.clientNum );
|
||||
#endif // _IMMERSION
|
||||
|
||||
#ifdef _XBOX
|
||||
cgi_FF_Xbox_Damage(damage, cg.damageX);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_Respawn
|
||||
|
||||
A respawn happened this snapshot
|
||||
================
|
||||
*/
|
||||
void CG_Respawn( void ) {
|
||||
// no error decay on player movement
|
||||
cg.thisFrameTeleport = qtrue;
|
||||
|
||||
// display weapons available
|
||||
// cg.weaponSelectTime = cg.time;
|
||||
SetWeaponSelectTime();
|
||||
|
||||
// select the weapon the server says we are using
|
||||
if (cg.snap->ps.weapon)
|
||||
cg.weaponSelect = cg.snap->ps.weapon;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_CheckPlayerstateEvents
|
||||
|
||||
==============
|
||||
*/
|
||||
void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
|
||||
int i;
|
||||
int event;
|
||||
centity_t *cent;
|
||||
|
||||
#if 0
|
||||
if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
|
||||
cent = &cg_entities[ ps->clientNum ];
|
||||
cent->currentState.event = ps->externalEvent;
|
||||
cent->currentState.eventParm = ps->externalEventParm;
|
||||
CG_EntityEvent( cent, cent->lerpOrigin );
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
|
||||
if ( ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]
|
||||
|| i >= ops->eventSequence ) {
|
||||
event = ps->events[ i & (MAX_PS_EVENTS-1) ];
|
||||
|
||||
cent = &cg_entities[ ps->clientNum ];
|
||||
cent->currentState.event = event;
|
||||
cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
|
||||
CG_EntityEvent( cent, cent->lerpOrigin );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_CheckLocalSounds
|
||||
==================
|
||||
*/
|
||||
/*
|
||||
void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {
|
||||
const char *s;
|
||||
|
||||
// hit changes
|
||||
if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {
|
||||
cgi_S_StartLocalSound( "sound/feedback/hit.wav" );
|
||||
} else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {
|
||||
cgi_S_StartLocalSound( "sound/feedback/hit_teammate.wav" );
|
||||
}
|
||||
|
||||
// score up / down changes
|
||||
if ( ps->persistant[PERS_SCORE] > ops->persistant[PERS_SCORE] ) {
|
||||
cgi_S_StartLocalSound( "sound/feedback/scoreup.wav" );
|
||||
} else if ( ps->persistant[PERS_SCORE] < ops->persistant[PERS_SCORE] ) {
|
||||
cgi_S_StartLocalSound( "sound/feedback/scoredown.wav" );
|
||||
}
|
||||
|
||||
// reward sounds
|
||||
if ( ps->persistant[PERS_REWARD_COUNT] > ops->persistant[PERS_REWARD_COUNT] ) {
|
||||
switch ( ps->persistant[PERS_REWARD] ) {
|
||||
case REWARD_IMPRESSIVE:
|
||||
cgi_S_StartLocalSound( "sound/feedback/impressive.wav" );
|
||||
break;
|
||||
case REWARD_EXCELLENT:
|
||||
cgi_S_StartLocalSound( "sound/feedback/excellent.wav" );
|
||||
break;
|
||||
case REWARD_DENIED:
|
||||
cgi_S_StartLocalSound( "sound/feedback/denied.wav" );
|
||||
break;
|
||||
|
||||
default:
|
||||
CG_Error( "Bad reward_t" );
|
||||
}
|
||||
}
|
||||
|
||||
// timelimit warnings
|
||||
if ( cgs.timelimit > 0 ) {
|
||||
if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && cg.time > (cgs.timelimit - 5) * 60 * 1000 ) {
|
||||
cg.timelimitWarnings |= 1;
|
||||
cgi_S_StartLocalSound( "sound/feedback/5_minute.wav" );
|
||||
}
|
||||
if ( !( cg.timelimitWarnings & 2 ) && cg.time > (cgs.timelimit - 1) * 60 * 1000 ) {
|
||||
cg.timelimitWarnings |= 2;
|
||||
cgi_S_StartLocalSound( "sound/feedback/1_minute.wav" );
|
||||
}
|
||||
if ( !( cg.timelimitWarnings & 4 ) && cg.time > ( cgs.timelimit * 60 + 2 ) * 1000 ) {
|
||||
cg.timelimitWarnings |= 4;
|
||||
cgi_S_StartLocalSound( "sound/feedback/sudden_death.wav" );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_TransitionPlayerState
|
||||
|
||||
===============
|
||||
*/
|
||||
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
|
||||
// teleporting
|
||||
if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
|
||||
cg.thisFrameTeleport = qtrue;
|
||||
} else {
|
||||
cg.thisFrameTeleport = qfalse;
|
||||
}
|
||||
|
||||
// check for changing follow mode
|
||||
if ( ps->clientNum != ops->clientNum ) {
|
||||
cg.thisFrameTeleport = qtrue;
|
||||
// make sure we don't get any unwanted transition effects
|
||||
*ops = *ps;
|
||||
}
|
||||
|
||||
// damage events (player is getting wounded)
|
||||
if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
|
||||
CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
|
||||
}
|
||||
|
||||
// respawning
|
||||
if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
|
||||
CG_Respawn();
|
||||
}
|
||||
|
||||
// check for going low on ammo
|
||||
CG_CheckAmmo();
|
||||
|
||||
// run events
|
||||
CG_CheckPlayerstateEvents( ps, ops );
|
||||
|
||||
// smooth the ducking viewheight change
|
||||
if ( ps->viewheight != ops->viewheight )
|
||||
{
|
||||
if ( !cg.nextFrameTeleport )
|
||||
{//when we crouch/uncrouch in mid-air, our viewhieght doesn't actually change in
|
||||
//absolute world coordinates, just locally.
|
||||
cg.duckChange = ps->viewheight - ops->viewheight;
|
||||
cg.duckTime = cg.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
780
code/cgame/cg_predict.cpp
Normal file
780
code/cgame/cg_predict.cpp
Normal file
@@ -0,0 +1,780 @@
|
||||
// cg_predict.c -- this file generates cg.predicted_player_state by either
|
||||
// interpolating between snapshots from the server or locally predicting
|
||||
// ahead the client's movement
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
|
||||
#include "..\game\g_vehicles.h"
|
||||
|
||||
static pmove_t cg_pmove;
|
||||
|
||||
static int cg_numSolidEntities;
|
||||
static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
|
||||
|
||||
#if MEM_DEBUG
|
||||
#include "..\smartheap\heapagnt.h"
|
||||
#define CG_TRACE_PROFILE (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_BuildSolidList
|
||||
|
||||
When a new cg.snap has been set, this function builds a sublist
|
||||
of the entities that are actually solid, to make for more
|
||||
efficient collision detection
|
||||
====================
|
||||
*/
|
||||
void CG_BuildSolidList( void )
|
||||
{
|
||||
int i;
|
||||
centity_t *cent;
|
||||
vec3_t difference;
|
||||
float dsquared;
|
||||
|
||||
cg_numSolidEntities = 0;
|
||||
|
||||
if(!cg.snap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ )
|
||||
{
|
||||
if ( cg.snap->entities[ i ].number < ENTITYNUM_WORLD )
|
||||
{
|
||||
cent = &cg_entities[ cg.snap->entities[ i ].number ];
|
||||
|
||||
if ( cent->gent != NULL && cent->gent->s.solid )
|
||||
{
|
||||
cg_solidEntities[cg_numSolidEntities] = cent;
|
||||
cg_numSolidEntities++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dsquared = 5000+500;
|
||||
dsquared *= dsquared;
|
||||
|
||||
for(i=0;i<cg_numpermanents;i++)
|
||||
{
|
||||
cent = cg_permanents[i];
|
||||
VectorSubtract(cent->lerpOrigin, cg.snap->ps.origin, difference);
|
||||
if (cent->currentState.eType == ET_TERRAIN ||
|
||||
((difference[0]*difference[0]) + (difference[1]*difference[1]) + (difference[2]*difference[2])) <= dsquared)
|
||||
{
|
||||
cent->currentValid = qtrue;
|
||||
if ( cent->nextState && cent->nextState->solid )
|
||||
{
|
||||
cg_solidEntities[cg_numSolidEntities] = cent;
|
||||
cg_numSolidEntities++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cent->currentValid = qfalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_ClipMoveToEntities
|
||||
|
||||
====================
|
||||
*/
|
||||
void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
|
||||
int skipNumber, int mask, trace_t *tr ) {
|
||||
int i, x, zd, zu;
|
||||
trace_t trace;
|
||||
entityState_t *ent;
|
||||
clipHandle_t cmodel;
|
||||
vec3_t bmins, bmaxs;
|
||||
vec3_t origin, angles;
|
||||
centity_t *cent;
|
||||
|
||||
for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
|
||||
cent = cg_solidEntities[ i ];
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->number == skipNumber ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->eType == ET_PUSH_TRIGGER ) {
|
||||
continue;
|
||||
}
|
||||
if ( ent->eType == ET_TELEPORT_TRIGGER ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->solid == SOLID_BMODEL ) {
|
||||
// special value for bmodel
|
||||
cmodel = cgi_CM_InlineModel( ent->modelindex );
|
||||
VectorCopy( cent->lerpAngles, angles );
|
||||
|
||||
//Hmm... this would cause traces against brush movers to snap at 20fps (as with the third person camera)...
|
||||
//Let's use the lerpOrigin for now and see if it breaks anything...
|
||||
//EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, origin );
|
||||
VectorCopy( cent->lerpOrigin, origin );
|
||||
|
||||
} else {
|
||||
// encoded bbox
|
||||
x = (ent->solid & 255);
|
||||
zd = ((ent->solid>>8) & 255);
|
||||
zu = ((ent->solid>>16) & 255) - 32;
|
||||
|
||||
bmins[0] = bmins[1] = -x;
|
||||
bmaxs[0] = bmaxs[1] = x;
|
||||
bmins[2] = -zd;
|
||||
bmaxs[2] = zu;
|
||||
|
||||
cmodel = cgi_CM_TempBoxModel( bmins, bmaxs );//, cent->gent->contents );
|
||||
VectorCopy( vec3_origin, angles );
|
||||
VectorCopy( cent->lerpOrigin, origin );
|
||||
}
|
||||
|
||||
|
||||
cgi_CM_TransformedBoxTrace ( &trace, start, end,
|
||||
mins, maxs, cmodel, mask, origin, angles);
|
||||
|
||||
if (trace.allsolid || trace.fraction < tr->fraction) {
|
||||
trace.entityNum = ent->number;
|
||||
*tr = trace;
|
||||
} else if (trace.startsolid) {
|
||||
tr->startsolid = qtrue;
|
||||
}
|
||||
if ( tr->allsolid ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_Trace
|
||||
================
|
||||
*/
|
||||
void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
|
||||
const int skipNumber, const int mask, const EG2_Collision eG2TraceType/*=G2_NOCOLLIDE*/, const int useLod/*=0*/) {
|
||||
trace_t t;
|
||||
#if CG_TRACE_PROFILE
|
||||
#if MEM_DEBUG
|
||||
{
|
||||
int old=dbgMemSetCheckpoint(2004);
|
||||
malloc(1);
|
||||
dbgMemSetCheckpoint(old);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
cgi_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
|
||||
t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
|
||||
// check all other solid models
|
||||
CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
|
||||
|
||||
*result = t;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_PointContents
|
||||
================
|
||||
*/
|
||||
|
||||
#define USE_SV_PNT_CONTENTS (1)
|
||||
|
||||
#if USE_SV_PNT_CONTENTS
|
||||
int CG_PointContents( const vec3_t point, int passEntityNum ) {
|
||||
return gi.pointcontents(point,passEntityNum );
|
||||
}
|
||||
#else
|
||||
int CG_PointContents( const vec3_t point, int passEntityNum ) {
|
||||
int i;
|
||||
entityState_t *ent;
|
||||
centity_t *cent;
|
||||
clipHandle_t cmodel;
|
||||
int contents;
|
||||
|
||||
#if CG_TRACE_PROFILE
|
||||
#if MEM_DEBUG
|
||||
{
|
||||
int old=dbgMemSetCheckpoint(2005);
|
||||
malloc(1);
|
||||
dbgMemSetCheckpoint(old);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
contents = cgi_CM_PointContents (point, 0);
|
||||
|
||||
for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
|
||||
cent = cg_solidEntities[ i ];
|
||||
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->number == passEntityNum ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ent->solid != SOLID_BMODEL) { // special value for bmodel
|
||||
continue;
|
||||
}
|
||||
|
||||
cmodel = cgi_CM_InlineModel( ent->modelindex );
|
||||
if ( !cmodel ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
contents |= cgi_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CG_SetClientViewAngles( vec3_t angles, qboolean overrideViewEnt )
|
||||
{
|
||||
if ( cg.snap->ps.viewEntity <= 0 || cg.snap->ps.viewEntity >= ENTITYNUM_WORLD || overrideViewEnt )
|
||||
{//don't clamp angles when looking through a viewEntity
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
cg.predicted_player_state.viewangles[i] = angles[i];
|
||||
cg.predicted_player_state.delta_angles[i] = 0;
|
||||
cg.snap->ps.viewangles[i] = angles[i];
|
||||
cg.snap->ps.delta_angles[i] = 0;
|
||||
g_entities[0].client->pers.cmd_angles[i] = ANGLE2SHORT(angles[i]);
|
||||
}
|
||||
cgi_SetUserCmdAngles( angles[PITCH], angles[YAW], angles[ROLL] );
|
||||
}
|
||||
}
|
||||
|
||||
extern qboolean PM_AdjustAnglesToGripper( gentity_t *gent, usercmd_t *cmd );
|
||||
extern qboolean PM_AdjustAnglesForSpinningFlip( gentity_t *ent, usercmd_t *ucmd, qboolean anglesOnly );
|
||||
extern qboolean G_CheckClampUcmd( gentity_t *ent, usercmd_t *ucmd );
|
||||
extern Vehicle_t *G_IsRidingVehicle( gentity_t *ent );
|
||||
qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles )
|
||||
{
|
||||
qboolean overridAngles = qfalse;
|
||||
if ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD )
|
||||
{//controlling something else
|
||||
memset( cmd, 0, sizeof( usercmd_t ) );
|
||||
/*
|
||||
//to keep pointing in same dir, need to set cmd.angles
|
||||
cmd->angles[PITCH] = ANGLE2SHORT( cg.snap->ps.viewangles[PITCH] ) - cg.snap->ps.delta_angles[PITCH];
|
||||
cmd->angles[YAW] = ANGLE2SHORT( cg.snap->ps.viewangles[YAW] ) - cg.snap->ps.delta_angles[YAW];
|
||||
cmd->angles[ROLL] = 0;
|
||||
*/
|
||||
VectorCopy( g_entities[0].pos4, viewangles );
|
||||
overridAngles = qtrue;
|
||||
//CG_SetClientViewAngles( g_entities[cg.snap->ps.viewEntity].client->ps.viewangles, qtrue );
|
||||
}
|
||||
else if ( G_IsRidingVehicle( &g_entities[0] ) )
|
||||
{
|
||||
overridAngles = qtrue;
|
||||
/*
|
||||
int vehIndex = g_entities[0].owner->client->ps.vehicleIndex;
|
||||
if ( vehIndex != VEHICLE_NONE
|
||||
&& (vehicleData[vehIndex].type == VH_FIGHTER || (vehicleData[vehIndex].type == VH_SPEEDER )) )
|
||||
{//in vehicle flight mode
|
||||
float speed = VectorLength( cg.snap->ps.velocity );
|
||||
if ( !speed || cg.snap->ps.groundEntityNum != ENTITYNUM_NONE )
|
||||
{
|
||||
cmd->rightmove = 0;
|
||||
cmd->angles[PITCH] = 0;
|
||||
cmd->angles[YAW] = ANGLE2SHORT( cg.snap->ps.viewangles[YAW] ) - cg.snap->ps.delta_angles[YAW];
|
||||
CG_SetClientViewAngles( cg.snap->ps.viewangles, qfalse );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if ( &g_entities[0] && g_entities[0].client )
|
||||
{
|
||||
if ( !PM_AdjustAnglesToGripper( &g_entities[0], cmd ) )
|
||||
{
|
||||
if ( PM_AdjustAnglesForSpinningFlip( &g_entities[0], cmd, qtrue ) )
|
||||
{
|
||||
CG_SetClientViewAngles( g_entities[0].client->ps.viewangles, qfalse );
|
||||
if ( viewangles )
|
||||
{
|
||||
VectorCopy( g_entities[0].client->ps.viewangles, viewangles );
|
||||
overridAngles = qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CG_SetClientViewAngles( g_entities[0].client->ps.viewangles, qfalse );
|
||||
if ( viewangles )
|
||||
{
|
||||
VectorCopy( g_entities[0].client->ps.viewangles, viewangles );
|
||||
overridAngles = qtrue;
|
||||
}
|
||||
}
|
||||
if ( G_CheckClampUcmd( &g_entities[0], cmd ) )
|
||||
{
|
||||
CG_SetClientViewAngles( g_entities[0].client->ps.viewangles, qfalse );
|
||||
if ( viewangles )
|
||||
{
|
||||
VectorCopy( g_entities[0].client->ps.viewangles, viewangles );
|
||||
overridAngles = qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return overridAngles;
|
||||
}
|
||||
|
||||
qboolean CG_OnMovingPlat( playerState_t *ps )
|
||||
{
|
||||
if ( ps->groundEntityNum != ENTITYNUM_NONE )
|
||||
{
|
||||
entityState_t *es = &cg_entities[ps->groundEntityNum].currentState;
|
||||
if ( es->eType == ET_MOVER )
|
||||
{//on a mover
|
||||
if ( es->pos.trType != TR_STATIONARY )
|
||||
{
|
||||
if ( es->pos.trType != TR_LINEAR_STOP && es->pos.trType != TR_NONLINEAR_STOP )
|
||||
{//a constant mover
|
||||
if ( !VectorCompare( vec3_origin, es->pos.trDelta ) )
|
||||
{//is moving
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{//a linear-stop mover
|
||||
if ( es->pos.trTime+es->pos.trDuration > cg.time )
|
||||
{//still moving
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return qfalse;
|
||||
}
|
||||
/*
|
||||
========================
|
||||
CG_InterpolatePlayerState
|
||||
|
||||
Generates cg.predicted_player_state by interpolating between
|
||||
cg.snap->player_state and cg.nextFrame->player_state
|
||||
========================
|
||||
*/
|
||||
void CG_InterpolatePlayerState( qboolean grabAngles ) {
|
||||
float f;
|
||||
int i;
|
||||
playerState_t *out;
|
||||
snapshot_t *prev, *next;
|
||||
qboolean skip = qfalse;
|
||||
vec3_t oldOrg;
|
||||
|
||||
out = &cg.predicted_player_state;
|
||||
prev = cg.snap;
|
||||
next = cg.nextSnap;
|
||||
|
||||
VectorCopy(out->origin,oldOrg);
|
||||
*out = cg.snap->ps;
|
||||
|
||||
// if we are still allowing local input, short circuit the view angles
|
||||
if ( grabAngles ) {
|
||||
usercmd_t cmd;
|
||||
int cmdNum;
|
||||
|
||||
cmdNum = cgi_GetCurrentCmdNumber();
|
||||
cgi_GetUserCmd( cmdNum, &cmd );
|
||||
|
||||
skip = CG_CheckModifyUCmd( &cmd, out->viewangles );
|
||||
|
||||
if ( !skip )
|
||||
{
|
||||
//NULL so that it doesn't execute a block of code that must be run from game
|
||||
PM_UpdateViewAngles( out, &cmd, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
// if the next frame is a teleport, we can't lerp to it
|
||||
if ( cg.nextFrameTeleport )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!( !next || next->serverTime <= prev->serverTime ) )
|
||||
{
|
||||
|
||||
f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
|
||||
|
||||
i = next->ps.bobCycle;
|
||||
if ( i < prev->ps.bobCycle )
|
||||
{
|
||||
i += 256; // handle wraparound
|
||||
}
|
||||
out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
|
||||
|
||||
for ( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
|
||||
if ( !grabAngles )
|
||||
{
|
||||
out->viewangles[i] = LerpAngle(
|
||||
prev->ps.viewangles[i], next->ps.viewangles[i], f );
|
||||
}
|
||||
out->velocity[i] = prev->ps.velocity[i] +
|
||||
f * (next->ps.velocity[i] - prev->ps.velocity[i] );
|
||||
}
|
||||
}
|
||||
|
||||
bool onPlat=false;
|
||||
centity_t *pent=0;
|
||||
if (out->groundEntityNum>0)
|
||||
{
|
||||
pent=&cg_entities[out->groundEntityNum];
|
||||
if (pent->currentState.eType == ET_MOVER )
|
||||
|
||||
{
|
||||
onPlat=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
cg.validPPS &&
|
||||
cg_smoothPlayerPos.value>0.0f &&
|
||||
cg_smoothPlayerPos.value<1.0f &&
|
||||
!onPlat
|
||||
)
|
||||
{
|
||||
// 0 = no smoothing, 1 = no movement
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
out->origin[i]=cg_smoothPlayerPos.value*(oldOrg[i]-out->origin[i])+out->origin[i];
|
||||
}
|
||||
}
|
||||
else if (onPlat&&cg_smoothPlayerPlat.value>0.0f&&cg_smoothPlayerPlat.value<1.0f)
|
||||
{
|
||||
// if (cg.frametime<150)
|
||||
// {
|
||||
assert(pent);
|
||||
vec3_t p1,p2,vel;
|
||||
float lerpTime;
|
||||
|
||||
|
||||
EvaluateTrajectory( &pent->currentState.pos,cg.snap->serverTime, p1 );
|
||||
if ( cg.nextSnap &&cg.nextSnap->serverTime > cg.snap->serverTime && pent->nextState)
|
||||
{
|
||||
EvaluateTrajectory( &pent->nextState->pos,cg.nextSnap->serverTime, p2 );
|
||||
lerpTime=float(cg.nextSnap->serverTime - cg.snap->serverTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
EvaluateTrajectory( &pent->currentState.pos,cg.snap->serverTime+50, p2 );
|
||||
lerpTime=50.0f;
|
||||
}
|
||||
|
||||
float accel=cg_smoothPlayerPlatAccel.value*cg.frametime/lerpTime;
|
||||
|
||||
if (accel>20.0f)
|
||||
{
|
||||
accel=20.0f;
|
||||
}
|
||||
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
vel[i]=accel*(p2[i]-p1[i]);
|
||||
}
|
||||
|
||||
VectorAdd(out->origin,vel,out->origin);
|
||||
|
||||
if (cg.validPPS &&
|
||||
cg_smoothPlayerPlat.value>0.0f &&
|
||||
cg_smoothPlayerPlat.value<1.0f
|
||||
)
|
||||
{
|
||||
// 0 = no smoothing, 1 = no movement
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
out->origin[i]=cg_smoothPlayerPlat.value*(oldOrg[i]-out->origin[i])+out->origin[i];
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_TouchItem
|
||||
===================
|
||||
*/
|
||||
void CG_TouchItem( centity_t *cent ) {
|
||||
gitem_t *item;
|
||||
|
||||
// never pick an item up twice in a prediction
|
||||
if ( cent->miscTime == cg.time ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !BG_PlayerTouchesItem( &cg.predicted_player_state, ¢->currentState, cg.time ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !BG_CanItemBeGrabbed( ¢->currentState, &cg.predicted_player_state ) ) {
|
||||
return; // can't hold it
|
||||
}
|
||||
|
||||
item = &bg_itemlist[ cent->currentState.modelindex ];
|
||||
|
||||
// grab it
|
||||
AddEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predicted_player_state);
|
||||
|
||||
// remove it from the frame so it won't be drawn
|
||||
cent->currentState.eFlags |= EF_NODRAW;
|
||||
|
||||
// don't touch it again this prediction
|
||||
cent->miscTime = cg.time;
|
||||
|
||||
// if its a weapon, give them some predicted ammo so the autoswitch will work
|
||||
if ( item->giType == IT_WEAPON ) {
|
||||
int ammotype = weaponData[item->giTag].ammoIndex;
|
||||
cg.predicted_player_state.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
|
||||
if ( !cg.predicted_player_state.ammo[ ammotype] ) {
|
||||
cg.predicted_player_state.ammo[ ammotype ] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
CG_TouchTriggerPrediction
|
||||
|
||||
Predict push triggers and items
|
||||
Only called for the last command
|
||||
=========================
|
||||
*/
|
||||
void CG_TouchTriggerPrediction( void ) {
|
||||
int i;
|
||||
trace_t trace;
|
||||
entityState_t *ent;
|
||||
clipHandle_t cmodel;
|
||||
centity_t *cent;
|
||||
qboolean spectator;
|
||||
|
||||
// dead clients don't activate triggers
|
||||
if ( cg.predicted_player_state.stats[STAT_HEALTH] <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
spectator = ( cg.predicted_player_state.pm_type == PM_SPECTATOR );
|
||||
|
||||
if ( cg.predicted_player_state.pm_type != PM_NORMAL && !spectator ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
|
||||
cent = &cg_entities[ cg.snap->entities[ i ].number ];
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->eType == ET_ITEM && !spectator ) {
|
||||
CG_TouchItem( cent );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->eType != ET_PUSH_TRIGGER && ent->eType != ET_TELEPORT_TRIGGER ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->solid != SOLID_BMODEL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cmodel = cgi_CM_InlineModel( ent->modelindex );
|
||||
if ( !cmodel ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cgi_CM_BoxTrace( &trace, cg.predicted_player_state.origin, cg.predicted_player_state.origin,
|
||||
cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
|
||||
|
||||
if ( !trace.startsolid ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->eType == ET_TELEPORT_TRIGGER ) {
|
||||
cg.hyperspace = qtrue;
|
||||
} else {
|
||||
// we hit this push trigger
|
||||
if ( spectator ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VectorCopy( ent->origin2, cg.predicted_player_state.velocity );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_PredictPlayerState
|
||||
|
||||
Generates cg.predicted_player_state for the current cg.time
|
||||
cg.predicted_player_state is guaranteed to be valid after exiting.
|
||||
|
||||
For normal gameplay, it will be the result of predicted usercmd_t on
|
||||
top of the most recent playerState_t received from the server.
|
||||
|
||||
Each new refdef will usually have exactly one new usercmd over the last,
|
||||
but we have to simulate all unacknowledged commands since the last snapshot
|
||||
received. This means that on an internet connection, quite a few
|
||||
pmoves may be issued each frame.
|
||||
|
||||
OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
|
||||
differs from the predicted one.
|
||||
|
||||
We detect prediction errors and allow them to be decayed off over several frames
|
||||
to ease the jerk.
|
||||
=================
|
||||
*/
|
||||
extern qboolean player_locked;
|
||||
void CG_PredictPlayerState( void ) {
|
||||
int cmdNum, current;
|
||||
playerState_t oldPlayerState;
|
||||
|
||||
cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
|
||||
|
||||
// if this is the first frame we must guarantee
|
||||
// predicted_player_state is valid even if there is some
|
||||
// other error condition
|
||||
if ( !cg.validPPS ) {
|
||||
cg.validPPS = qtrue;
|
||||
cg.predicted_player_state = cg.snap->ps;
|
||||
}
|
||||
|
||||
|
||||
if ( 1 )//cg_timescale.value >= 1.0f )
|
||||
{
|
||||
// demo playback just copies the moves
|
||||
/*
|
||||
if ( (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
|
||||
CG_InterpolatePlayerState( qfalse );
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// non-predicting local movement will grab the latest angles
|
||||
CG_InterpolatePlayerState( qtrue );
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare for pmove
|
||||
//FIXME: is this bad???
|
||||
cg_pmove.gent = NULL;
|
||||
cg_pmove.ps = &cg.predicted_player_state;
|
||||
cg_pmove.trace = CG_Trace;
|
||||
cg_pmove.pointcontents = CG_PointContents;
|
||||
cg_pmove.tracemask = MASK_PLAYERSOLID;
|
||||
cg_pmove.noFootsteps = 0;//( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
|
||||
|
||||
// save the state before the pmove so we can detect transitions
|
||||
oldPlayerState = cg.predicted_player_state;
|
||||
|
||||
// if we are too far out of date, just freeze
|
||||
cmdNum = cg.snap->cmdNum;
|
||||
current = cgi_GetCurrentCmdNumber();
|
||||
|
||||
if ( current - cmdNum >= CMD_BACKUP ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the most recent information we have
|
||||
cg.predicted_player_state = cg.snap->ps;
|
||||
|
||||
// we should always be predicting at least one frame
|
||||
if ( cmdNum >= current ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// run cmds
|
||||
do {
|
||||
// check for a prediction error from last frame
|
||||
// on a lan, this will often be the exact value
|
||||
// from the snapshot, but on a wan we will have
|
||||
// to predict several commands to get to the point
|
||||
// we want to compare
|
||||
if ( cmdNum == current - 1 ) {
|
||||
vec3_t delta;
|
||||
float len;
|
||||
|
||||
if ( cg.thisFrameTeleport ) {
|
||||
// a teleport will not cause an error decay
|
||||
VectorClear( cg.predictedError );
|
||||
cg.thisFrameTeleport = qfalse;
|
||||
} else {
|
||||
vec3_t adjusted;
|
||||
CG_AdjustPositionForMover( cg.predicted_player_state.origin,
|
||||
cg.predicted_player_state.groundEntityNum, cg.oldTime, adjusted );
|
||||
|
||||
VectorSubtract( oldPlayerState.origin, adjusted, delta );
|
||||
len = VectorLength( delta );
|
||||
if ( len > 0.1 ) {
|
||||
if ( cg_errorDecay.integer ) {
|
||||
int t;
|
||||
float f;
|
||||
|
||||
t = cg.time - cg.predictedErrorTime;
|
||||
f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
|
||||
if ( f < 0 ) {
|
||||
f = 0;
|
||||
}
|
||||
VectorScale( cg.predictedError, f, cg.predictedError );
|
||||
} else {
|
||||
VectorClear( cg.predictedError );
|
||||
}
|
||||
VectorAdd( delta, cg.predictedError, cg.predictedError );
|
||||
cg.predictedErrorTime = cg.oldTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the command can't be gotten because it is
|
||||
// too far out of date, the frame is invalid
|
||||
// this should never happen, because we check ranges at
|
||||
// the top of the function
|
||||
cmdNum++;
|
||||
if ( !cgi_GetUserCmd( cmdNum, &cg_pmove.cmd ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
gentity_t *ent = &g_entities[0];//cheating and dirty, I know, but this is a SP game so prediction can cheat
|
||||
if ( player_locked ||
|
||||
(ent && !ent->s.number&&ent->aimDebounceTime>level.time) ||
|
||||
(ent && ent->client && ent->client->ps.pm_time && (ent->client->ps.pm_flags&PMF_TIME_KNOCKBACK)) ||
|
||||
(ent && ent->forcePushTime > level.time) )
|
||||
{//lock out player control unless dead
|
||||
//VectorClear( cg_pmove.cmd.angles );
|
||||
cg_pmove.cmd.forwardmove = 0;
|
||||
cg_pmove.cmd.rightmove = 0;
|
||||
cg_pmove.cmd.buttons = 0;
|
||||
cg_pmove.cmd.upmove = 0;
|
||||
}
|
||||
CG_CheckModifyUCmd( &cg_pmove.cmd, NULL );
|
||||
//FIXME: prediction on clients in timescale results in jerky positional translation
|
||||
Pmove( &cg_pmove );
|
||||
|
||||
// add push trigger movement effects
|
||||
CG_TouchTriggerPrediction();
|
||||
|
||||
} while ( cmdNum < current );
|
||||
|
||||
// adjust for the movement of the groundentity
|
||||
CG_AdjustPositionForMover( cg.predicted_player_state.origin,
|
||||
cg.predicted_player_state.groundEntityNum,
|
||||
cg.time, cg.predicted_player_state.origin );
|
||||
|
||||
// fire events and other transition triggered things
|
||||
CG_TransitionPlayerState( &cg.predicted_player_state, &oldPlayerState );
|
||||
}
|
||||
|
||||
|
||||
214
code/cgame/cg_public.h
Normal file
214
code/cgame/cg_public.h
Normal file
@@ -0,0 +1,214 @@
|
||||
#ifndef _CG_PUBLIC_H
|
||||
#define _CG_PUBLIC_H
|
||||
|
||||
#define NUM_EXPLOSION_SHADERS 8
|
||||
#define NUM_EXPLOSION_FRAMES 3
|
||||
|
||||
#define CMD_BACKUP 64
|
||||
#define CMD_MASK (CMD_BACKUP - 1)
|
||||
// allow a lot of command backups for very fast systems
|
||||
// multiple commands may be combined into a single packet, so this
|
||||
// needs to be larger than PACKET_BACKUP
|
||||
|
||||
|
||||
#define MAX_ENTITIES_IN_SNAPSHOT 512
|
||||
|
||||
#define SNAPFLAG_RATE_DELAYED 1 // the server withheld a packet to save bandwidth
|
||||
#define SNAPFLAG_DROPPED_COMMANDS 2 // the server lost some cmds coming from the client
|
||||
|
||||
// snapshots are a view of the server at a given time
|
||||
|
||||
// Snapshots are generated at regular time intervals by the server,
|
||||
// but they may not be sent if a client's rate level is exceeded, or
|
||||
// they may be dropped by the network.
|
||||
struct snapshot_s
|
||||
{
|
||||
int snapFlags; // SNAPFLAG_RATE_DELAYED, SNAPFLAG_DROPPED_COMMANDS
|
||||
int ping;
|
||||
|
||||
int serverTime; // server time the message is valid for (in msec)
|
||||
|
||||
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
|
||||
|
||||
int cmdNum; // the next cmdNum the server is expecting
|
||||
// client side prediction should start with this cmd
|
||||
playerState_t ps; // complete information about the current player at this time
|
||||
|
||||
int numEntities; // all of the entities that need to be presented
|
||||
entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
|
||||
|
||||
int numConfigstringChanges; // configstrings that have changed since the last
|
||||
int configstringNum; // acknowledged snapshot_t (which is usually NOT the previous snapshot!)
|
||||
|
||||
int numServerCommands; // text based server commands to execute when this
|
||||
int serverCommandSequence; // snapshot becomes current
|
||||
};
|
||||
|
||||
typedef snapshot_s snapshot_t;
|
||||
|
||||
|
||||
/*
|
||||
==================================================================
|
||||
|
||||
functions imported from the main executable
|
||||
|
||||
==================================================================
|
||||
*/
|
||||
|
||||
#define CGAME_IMPORT_API_VERSION 4
|
||||
|
||||
typedef enum {
|
||||
CG_PRINT,
|
||||
CG_ERROR,
|
||||
CG_MILLISECONDS,
|
||||
CG_CVAR_REGISTER,
|
||||
CG_CVAR_UPDATE,
|
||||
CG_CVAR_SET,
|
||||
CG_ARGC,
|
||||
CG_ARGV,
|
||||
CG_ARGS,
|
||||
CG_FS_FOPENFILE,
|
||||
CG_FS_READ,
|
||||
CG_FS_WRITE,
|
||||
CG_FS_FCLOSEFILE,
|
||||
CG_SENDCONSOLECOMMAND,
|
||||
CG_ADDCOMMAND,
|
||||
CG_SENDCLIENTCOMMAND,
|
||||
CG_UPDATESCREEN,
|
||||
CG_RMG_INIT,
|
||||
CG_CM_REGISTER_TERRAIN,
|
||||
CG_RE_INIT_RENDERER_TERRAIN,
|
||||
CG_CM_LOADMAP,
|
||||
CG_CM_NUMINLINEMODELS,
|
||||
CG_CM_INLINEMODEL,
|
||||
CG_CM_TEMPBOXMODEL,
|
||||
CG_CM_POINTCONTENTS,
|
||||
CG_CM_TRANSFORMEDPOINTCONTENTS,
|
||||
CG_CM_BOXTRACE,
|
||||
CG_CM_TRANSFORMEDBOXTRACE,
|
||||
CG_CM_MARKFRAGMENTS,
|
||||
CG_CM_SNAPPVS,
|
||||
CG_S_STARTSOUND,
|
||||
CG_S_STARTLOCALSOUND,
|
||||
CG_S_CLEARLOOPINGSOUNDS,
|
||||
CG_S_ADDLOOPINGSOUND,
|
||||
CG_S_STOPSOUNDS,
|
||||
CG_S_UPDATEENTITYPOSITION,
|
||||
CG_S_RESPATIALIZE,
|
||||
CG_S_REGISTERSOUND,
|
||||
CG_S_STARTBACKGROUNDTRACK,
|
||||
#ifdef _IMMERSION
|
||||
CG_FF_START,
|
||||
CG_FF_STOP,
|
||||
CG_FF_STOPALL,
|
||||
CG_FF_SHAKE,
|
||||
CG_FF_REGISTER,
|
||||
CG_FF_ADDLOOPINGFORCE,
|
||||
#else
|
||||
CG_FF_STARTFX,
|
||||
CG_FF_ENSUREFX,
|
||||
CG_FF_STOPFX,
|
||||
CG_FF_STOPALLFX,
|
||||
#endif // _IMMERSION
|
||||
#ifdef _XBOX
|
||||
CG_FF_XBOX_SHAKE,
|
||||
CG_FF_XBOX_DAMAGE,
|
||||
#endif
|
||||
CG_R_LOADWORLDMAP,
|
||||
CG_R_REGISTERMODEL,
|
||||
CG_R_REGISTERSKIN,
|
||||
CG_R_REGISTERSHADER,
|
||||
CG_R_REGISTERSHADERNOMIP,
|
||||
CG_R_REGISTERFONT,
|
||||
CG_R_FONTSTRLENPIXELS,
|
||||
CG_R_FONTSTRLENCHARS,
|
||||
CG_R_FONTHEIGHTPIXELS,
|
||||
CG_R_FONTDRAWSTRING,
|
||||
CG_LANGUAGE_ISASIAN,
|
||||
CG_LANGUAGE_USESSPACES,
|
||||
CG_ANYLANGUAGE_READFROMSTRING,
|
||||
CG_R_SETREFRACTIONPROP,
|
||||
CG_R_CLEARSCENE,
|
||||
CG_R_ADDREFENTITYTOSCENE,
|
||||
|
||||
CG_R_INPVS,
|
||||
|
||||
CG_R_GETLIGHTING,
|
||||
CG_R_ADDPOLYTOSCENE,
|
||||
CG_R_ADDLIGHTTOSCENE,
|
||||
CG_R_RENDERSCENE,
|
||||
CG_R_SETCOLOR,
|
||||
CG_R_DRAWSTRETCHPIC,
|
||||
//CG_R_DRAWSCREENSHOT,
|
||||
CG_R_MODELBOUNDS,
|
||||
CG_R_LERPTAG,
|
||||
CG_R_DRAWROTATEPIC,
|
||||
CG_R_DRAWROTATEPIC2,
|
||||
CG_R_SETRANGEFOG,
|
||||
CG_R_LA_GOGGLES,
|
||||
CG_R_SCISSOR,
|
||||
CG_GETGLCONFIG,
|
||||
CG_GETGAMESTATE,
|
||||
CG_GETCURRENTSNAPSHOTNUMBER,
|
||||
CG_GETSNAPSHOT,
|
||||
|
||||
CG_GETDEFAULTSTATE,
|
||||
|
||||
CG_GETSERVERCOMMAND,
|
||||
CG_GETCURRENTCMDNUMBER,
|
||||
CG_GETUSERCMD,
|
||||
CG_SETUSERCMDVALUE,
|
||||
CG_SETUSERCMDANGLES,
|
||||
CG_S_UPDATEAMBIENTSET,
|
||||
CG_S_ADDLOCALSET,
|
||||
CG_AS_PARSESETS,
|
||||
CG_AS_ADDENTRY,
|
||||
CG_AS_GETBMODELSOUND,
|
||||
CG_S_GETSAMPLELENGTH,
|
||||
COM_SETORGANGLES,
|
||||
/*
|
||||
Ghoul2 Insert Start
|
||||
*/
|
||||
CG_G2_LISTBONES,
|
||||
CG_G2_LISTSURFACES,
|
||||
CG_G2_HAVEWEGHOULMODELS,
|
||||
CG_G2_SETMODELS,
|
||||
/*
|
||||
Ghoul2 Insert End
|
||||
*/
|
||||
|
||||
CG_R_GET_LIGHT_STYLE,
|
||||
CG_R_SET_LIGHT_STYLE,
|
||||
CG_R_GET_BMODEL_VERTS,
|
||||
CG_R_WORLD_EFFECT_COMMAND,
|
||||
|
||||
CG_CIN_PLAYCINEMATIC,
|
||||
CG_CIN_STOPCINEMATIC,
|
||||
CG_CIN_RUNCINEMATIC,
|
||||
CG_CIN_DRAWCINEMATIC,
|
||||
CG_CIN_SETEXTENTS,
|
||||
CG_Z_MALLOC,
|
||||
CG_Z_FREE,
|
||||
CG_UI_MENU_RESET,
|
||||
CG_UI_MENU_NEW,
|
||||
CG_UI_SETACTIVE_MENU,
|
||||
CG_UI_MENU_OPENBYNAME,
|
||||
CG_UI_PARSE_INT,
|
||||
CG_UI_PARSE_STRING,
|
||||
CG_UI_PARSE_FLOAT,
|
||||
CG_UI_STARTPARSESESSION,
|
||||
CG_UI_ENDPARSESESSION,
|
||||
CG_UI_PARSEEXT,
|
||||
CG_UI_MENUPAINT_ALL,
|
||||
CG_UI_MENUCLOSE_ALL,
|
||||
CG_UI_STRING_INIT,
|
||||
CG_UI_GETMENUINFO,
|
||||
CG_SP_GETSTRINGTEXTSTRING,
|
||||
CG_UI_GETITEMTEXT,
|
||||
CG_UI_GETITEMINFO,
|
||||
|
||||
} cgameImport_t;
|
||||
|
||||
//----------------------------------------------
|
||||
|
||||
#endif _CG_PUBLIC_H
|
||||
187
code/cgame/cg_scoreboard.cpp
Normal file
187
code/cgame/cg_scoreboard.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "..\game\objectives.h"
|
||||
#include "..\game\b_local.h"
|
||||
#include "..\ui\ui_shared.h"
|
||||
|
||||
#define SCOREBOARD_WIDTH (26*BIGCHAR_WIDTH)
|
||||
|
||||
|
||||
/*
|
||||
static void Scoreboard_Draw( void )
|
||||
{
|
||||
vec4_t newColor;
|
||||
/*
|
||||
player = g_entities[0];
|
||||
if( player->client->ps.persistant[PERS_ACCURACY_SHOTS] ) {
|
||||
accuracy = player->client->ps.persistant[PERS_ACCURACY_HITS] * 100 / player->client->ps.persistant[PERS_ACCURACY_SHOTS];
|
||||
}
|
||||
*/
|
||||
/* cg.LCARSTextTime = 0; // Turn off LCARS screen
|
||||
|
||||
// Background
|
||||
newColor[0] = colorTable[CT_BLACK][0];
|
||||
newColor[1] = colorTable[CT_BLACK][1];
|
||||
newColor[2] = colorTable[CT_BLACK][2];
|
||||
newColor[3] = 0.5;
|
||||
cgi_R_SetColor(newColor);
|
||||
CG_DrawPic( 137, 73, 475, 300, cgs.media.whiteShader); // Background
|
||||
CG_DrawPic( 120, 99, 18, 256, cgs.media.whiteShader); // Background
|
||||
CG_DrawPic( 40, 94, 66, 266, cgs.media.whiteShader); // Background
|
||||
|
||||
// Right side box
|
||||
cgi_R_SetColor( colorTable[CT_DKBROWN1]);
|
||||
CG_DrawPic( 120, 354, 32, 32, cgs.media.status_corner_16_18);
|
||||
CG_DrawPic( 94, 356, 16, 32, cgs.media.status_corner_8_16_b);
|
||||
CG_DrawPic( 94, 73, 16, 32, cgs.media.status_corner_8_22);
|
||||
|
||||
CG_DrawPic(135,73, 302, 22, cgs.media.whiteShader); // Top
|
||||
|
||||
CG_DrawPic(120, 100, 18, 12, cgs.media.whiteShader); // Middle Top
|
||||
CG_DrawPic(120, 353, 18, 4, cgs.media.whiteShader); // Middle Bottom
|
||||
|
||||
CG_DrawPic(130,357, 482, 18, cgs.media.whiteShader); // Bottom
|
||||
|
||||
// Left side box
|
||||
cgi_R_SetColor( colorTable[CT_DKBROWN1]);
|
||||
CG_DrawPic(40,73, 56, 22, cgs.media.whiteShader); // Top
|
||||
|
||||
CG_DrawPic(98,95, 8, 17, cgs.media.whiteShader); // Middle Top
|
||||
CG_DrawPic(98,353, 8, 7, cgs.media.whiteShader); // Middle Bottom
|
||||
|
||||
CG_DrawPic(40,357, 58, 18, cgs.media.whiteShader); // Bottom
|
||||
|
||||
CG_DrawProportionalString( 356, 208, "%", UI_RIGHT | UI_SMALLFONT, colorTable[CT_LTPURPLE1] );
|
||||
CG_DrawProportionalString( 610, 72, ingame_text[IGT_MISSIONANALYSIS],UI_RIGHT| CG_BIGFONT, colorTable[CT_LTORANGE] );
|
||||
|
||||
CG_PrintScreenGraphics(statsmenu_graphics,SMG_MAX);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_MissionFailed
|
||||
=================
|
||||
*/
|
||||
int statusTextIndex = -1;
|
||||
void CG_MissionFailed(void)
|
||||
{
|
||||
char *text;
|
||||
|
||||
if (!cg.missionFailedScreen)
|
||||
{
|
||||
cgi_UI_SetActive_Menu("missionfailed_menu");
|
||||
|
||||
// If you're in camera mode when when you lose (Chewie kills you)
|
||||
// then the above fails. This should check for that. We'll end up
|
||||
// waiting until the camera stuff stops:
|
||||
if( !Menu_GetFocused() )
|
||||
return;
|
||||
|
||||
cg.missionFailedScreen = qtrue;
|
||||
|
||||
switch (statusTextIndex)
|
||||
{
|
||||
case -1: //Our HERO DIED!!!
|
||||
text = "@SP_INGAME_MISSIONFAILED_PLAYER";
|
||||
break;
|
||||
case MISSIONFAILED_JAN:
|
||||
text = "@SP_INGAME_MISSIONFAILED_JAN";
|
||||
break;
|
||||
case MISSIONFAILED_LUKE:
|
||||
text = "@SP_INGAME_MISSIONFAILED_LUKE";
|
||||
break;
|
||||
case MISSIONFAILED_LANDO:
|
||||
text = "@SP_INGAME_MISSIONFAILED_LANDO";
|
||||
break;
|
||||
case MISSIONFAILED_R5D2:
|
||||
text = "@SP_INGAME_MISSIONFAILED_R5D2";
|
||||
break;
|
||||
case MISSIONFAILED_WARDEN:
|
||||
text = "@SP_INGAME_MISSIONFAILED_WARDEN";
|
||||
break;
|
||||
case MISSIONFAILED_PRISONERS:
|
||||
text = "@SP_INGAME_MISSIONFAILED_PRISONERS";
|
||||
break;
|
||||
case MISSIONFAILED_EMPLACEDGUNS:
|
||||
text = "@SP_INGAME_MISSIONFAILED_EMPLACEDGUNS";
|
||||
break;
|
||||
case MISSIONFAILED_LADYLUCK:
|
||||
text = "@SP_INGAME_MISSIONFAILED_LADYLUCK";
|
||||
break;
|
||||
case MISSIONFAILED_KYLECAPTURE:
|
||||
text = "@SP_INGAME_MISSIONFAILED_KYLECAPTURE";
|
||||
break;
|
||||
case MISSIONFAILED_TOOMANYALLIESDIED:
|
||||
text = "@SP_INGAME_MISSIONFAILED_TOOMANYALLIESDIED";
|
||||
break;
|
||||
|
||||
case MISSIONFAILED_CHEWIE:
|
||||
text = "@SP_INGAME_MISSIONFAILED_CHEWIE";
|
||||
break;
|
||||
|
||||
case MISSIONFAILED_KYLE:
|
||||
text = "@SP_INGAME_MISSIONFAILED_KYLE";
|
||||
break;
|
||||
|
||||
case MISSIONFAILED_ROSH:
|
||||
text = "@SP_INGAME_MISSIONFAILED_ROSH";
|
||||
break;
|
||||
|
||||
case MISSIONFAILED_WEDGE:
|
||||
text = "@SP_INGAME_MISSIONFAILED_WEDGE";
|
||||
break;
|
||||
|
||||
case MISSIONFAILED_TURNED:
|
||||
text = "@SP_INGAME_MISSIONFAILED_TURNED";
|
||||
break;
|
||||
|
||||
default:
|
||||
text = "@SP_INGAME_MISSIONFAILED_UNKNOWN";
|
||||
break;
|
||||
}
|
||||
//done with the variable for this time so reset it.
|
||||
statusTextIndex = -1;
|
||||
gi.cvar_set("ui_missionfailed_text", text);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_DrawScoreboard
|
||||
|
||||
Draw the normal in-game scoreboard
|
||||
return value is bool to NOT draw centerstring
|
||||
=================
|
||||
*/
|
||||
qboolean CG_DrawScoreboard( void )
|
||||
{
|
||||
// don't draw anything if the menu is up
|
||||
if ( cg_paused.integer )
|
||||
{
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// Character is either dead, or a script has brought up the screen
|
||||
if (((cg.predicted_player_state.pm_type == PM_DEAD) && (cg.missionStatusDeadTime < level.time))
|
||||
|| (cg.missionStatusShow))
|
||||
{
|
||||
CG_MissionFailed();
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
void ScoreBoardReset(void)
|
||||
{
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
|
||||
259
code/cgame/cg_servercmds.cpp
Normal file
259
code/cgame/cg_servercmds.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
// cg_servercmds.c -- text commands sent by the server
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
#include "cg_media.h"
|
||||
#include "FxScheduler.h"
|
||||
#include "cg_lights.h"
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_ParseServerinfo
|
||||
|
||||
This is called explicitly when the gamestate is first received,
|
||||
and whenever the server updates any serverinfo flagged cvars
|
||||
================
|
||||
*/
|
||||
void CG_ParseServerinfo( void ) {
|
||||
const char *info;
|
||||
char *mapname;
|
||||
|
||||
info = CG_ConfigString( CS_SERVERINFO );
|
||||
cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
|
||||
cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
|
||||
cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
|
||||
cgs.maxclients = 1;
|
||||
mapname = Info_ValueForKey( info, "mapname" );
|
||||
Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
|
||||
char *p = strrchr(mapname,'/');
|
||||
strcpy( cgs.stripLevelName[0], p?p+1:mapname );
|
||||
strupr( cgs.stripLevelName[0] );
|
||||
for (int i=1; i<STRIPED_LEVELNAME_VARIATIONS; i++) // clear retry-array
|
||||
{
|
||||
cgs.stripLevelName[i][0]='\0';
|
||||
}
|
||||
// be careful with the []-numbers here. Currently I use 0,1,2 for replacements or substitution, and [3] for "INGAME"
|
||||
// I know, if I'd known there was going to be this much messing about I'd have subroutinised it all and done it
|
||||
// neater, but it kinda evolved... Feel free to bug me if you want to add to it... ? -Ste.
|
||||
//
|
||||
|
||||
//FIXME: a better way to handle sound-matched strings from other levels (currently uses levelname+sound as key)
|
||||
|
||||
// additional String files needed for some levels...
|
||||
//
|
||||
// JKA...
|
||||
if (!stricmp(cgs.stripLevelName[0],"YAVIN1B"))
|
||||
{
|
||||
strcpy( cgs.stripLevelName[1], "YAVIN1");
|
||||
}
|
||||
|
||||
/* // JK2...
|
||||
if (!stricmp(cgs.stripLevelName[0],"KEJIM_BASE") ||
|
||||
!stricmp(cgs.stripLevelName[0],"KEJIM_POST")
|
||||
)
|
||||
{
|
||||
strcpy( cgs.stripLevelName[1], "ARTUS_MINE" );
|
||||
}
|
||||
if (!stricmp(cgs.stripLevelName[0],"DOOM_DETENTION") ||
|
||||
!stricmp(cgs.stripLevelName[0],"DOOM_SHIELDS")
|
||||
)
|
||||
{
|
||||
strcpy( cgs.stripLevelName[1], "DOOM_COMM" );
|
||||
}
|
||||
if (!stricmp(cgs.stripLevelName[0],"DOOM_COMM"))
|
||||
{
|
||||
strcpy( cgs.stripLevelName[1], "CAIRN_BAY" );
|
||||
}
|
||||
if (!stricmp(cgs.stripLevelName[0],"NS_STARPAD"))
|
||||
{
|
||||
strcpy( cgs.stripLevelName[1], "ARTUS_TOPSIDE" ); // for dream sequence...
|
||||
|
||||
strcpy( cgs.stripLevelName[2], "BESPIN_UNDERCITY" ); // for dream sequence...
|
||||
}
|
||||
if (!stricmp(cgs.stripLevelName[0],"BESPIN_PLATFORM"))
|
||||
{
|
||||
strcpy( cgs.stripLevelName[1], "BESPIN_UNDERCITY" );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_ConfigStringModified
|
||||
|
||||
================
|
||||
*/
|
||||
void CG_RegisterClientModels (int entityNum);
|
||||
extern void cgi_R_WorldEffectCommand( const char *command );
|
||||
static void CG_ConfigStringModified( void ) {
|
||||
const char *str;
|
||||
int num;
|
||||
|
||||
num = atoi( CG_Argv( 1 ) );
|
||||
|
||||
// get the gamestate from the client system, which will have the
|
||||
// new configstring already integrated
|
||||
cgi_GetGameState( &cgs.gameState );
|
||||
|
||||
// look up the individual string that was modified
|
||||
str = CG_ConfigString( num );
|
||||
|
||||
// do something with it if necessary
|
||||
if ( num == CS_ITEMS ) {
|
||||
int i;
|
||||
for ( i = 1 ; i < bg_numItems ; i++ ) {
|
||||
if ( str[ i ] == '1' )
|
||||
{
|
||||
if (bg_itemlist[i].classname)
|
||||
{
|
||||
CG_RegisterItemSounds( i );
|
||||
CG_RegisterItemVisuals( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( num == CS_MUSIC ) {
|
||||
CG_StartMusic( qtrue );
|
||||
} else if ( num == CS_SERVERINFO ) {
|
||||
CG_ParseServerinfo();
|
||||
} else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
|
||||
cgs.model_draw[ num-CS_MODELS ] = cgi_R_RegisterModel( str );
|
||||
// OutputDebugString(va("### CG_ConfigStringModified(): cgs.model_draw[%d] = \"%s\"\n",num-CS_MODELS,str));
|
||||
// GHOUL2 Insert start
|
||||
} else if ( num >= CS_CHARSKINS && num < CS_CHARSKINS+MAX_CHARSKINS ) {
|
||||
cgs.skins[ num-CS_CHARSKINS ] = cgi_R_RegisterSkin( str );
|
||||
// Ghoul2 Insert end
|
||||
} else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
|
||||
if ( str[0] != '*' ) {
|
||||
cgs.sound_precache[ num-CS_SOUNDS] = cgi_S_RegisterSound( str );
|
||||
}
|
||||
}
|
||||
else if ( num >= CS_EFFECTS && num < CS_EFFECTS + MAX_FX )
|
||||
{
|
||||
theFxScheduler.RegisterEffect( str );
|
||||
}
|
||||
else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
|
||||
CG_NewClientinfo( num - CS_PLAYERS );
|
||||
CG_RegisterClientModels( num - CS_PLAYERS );
|
||||
}
|
||||
else if ( num >= CS_LIGHT_STYLES && num < CS_LIGHT_STYLES + (MAX_LIGHT_STYLES*3))
|
||||
{
|
||||
CG_SetLightstyle(num - CS_LIGHT_STYLES);
|
||||
}
|
||||
else if ( num >= CS_WORLD_FX && num < CS_WORLD_FX + MAX_WORLD_FX )
|
||||
{
|
||||
cgi_R_WorldEffectCommand( str );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_ServerCommand
|
||||
|
||||
The string has been tokenized and can be retrieved with
|
||||
Cmd_Argc() / Cmd_Argv()
|
||||
=================
|
||||
*/
|
||||
static void CG_ServerCommand( void ) {
|
||||
const char *cmd;
|
||||
|
||||
cmd = CG_Argv(0);
|
||||
|
||||
if ( !strcmp( cmd, "cp" ) ) {
|
||||
CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.25 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "cs" ) ) {
|
||||
CG_ConfigStringModified();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "print" ) ) {
|
||||
CG_Printf( "%s", CG_Argv(1) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "chat" ) ) {
|
||||
// cgi_S_StartLocalSound ( cgs.media.talkSound, CHAN_LOCAL_SOUND );
|
||||
CG_Printf( "%s\n", CG_Argv(1) );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Scroll text
|
||||
if ( !strcmp( cmd, "st" ) )
|
||||
{
|
||||
#ifdef _XBOX
|
||||
if(cg.widescreen)
|
||||
CG_ScrollText( CG_Argv(1), 720 - 16 );
|
||||
else
|
||||
#endif
|
||||
CG_ScrollText( CG_Argv(1), SCREEN_WIDTH - 16 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Cinematic text
|
||||
if ( !strcmp( cmd, "ct" ) )
|
||||
{
|
||||
CG_CaptionText( CG_Argv(1), cgs.sound_precache[atoi(CG_Argv(2))], SCREEN_HEIGHT * 0.25 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Text stop
|
||||
if ( !strcmp( cmd, "cts" ) )
|
||||
{
|
||||
CG_CaptionTextStop();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Text to appear in center of screen with an LCARS frame around it.
|
||||
if ( !strcmp( cmd, "lt" ) )
|
||||
{
|
||||
CG_Printf("CG_LCARSText() being called. Tell Ste\nString: \"%s\"\n",CG_Argv(1));
|
||||
return;
|
||||
}
|
||||
|
||||
// clientLevelShot is sent before taking a special screenshot for
|
||||
// the menu system during development
|
||||
if ( !strcmp( cmd, "clientLevelShot" ) ) {
|
||||
cg.levelShot = qtrue;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "vmsg" ) ) {
|
||||
#if 0
|
||||
char snd[MAX_QPATH];
|
||||
|
||||
Com_sprintf(snd, sizeof(snd),
|
||||
"sound/teamplay/vmsg/%s.wav", CG_Argv(1) );
|
||||
cgi_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO,
|
||||
cgi_S_RegisterSound (snd) );
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
CG_Printf( "Unknown client game command: %s\n", cmd );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_ExecuteNewServerCommands
|
||||
|
||||
Execute all of the server commands that were received along
|
||||
with this this snapshot.
|
||||
====================
|
||||
*/
|
||||
void CG_ExecuteNewServerCommands( int latestSequence ) {
|
||||
while ( cgs.serverCommandSequence < latestSequence ) {
|
||||
if ( cgi_GetServerCommand( ++cgs.serverCommandSequence ) ) {
|
||||
CG_ServerCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
407
code/cgame/cg_snapshot.cpp
Normal file
407
code/cgame/cg_snapshot.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
// cg_snapshot.c -- things that happen on snapshot transition,
|
||||
// not necessarily every single frame
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_ResetEntity
|
||||
==================
|
||||
*/
|
||||
void CG_ResetEntity( centity_t *cent ) {
|
||||
// if an event is set, assume it is new enough to use
|
||||
// if the event had timed out, it would have been cleared
|
||||
cent->previousEvent = 0;
|
||||
|
||||
// cent->trailTime = cg.snap->serverTime;
|
||||
|
||||
VectorCopy (cent->currentState.origin, cent->lerpOrigin);
|
||||
VectorCopy (cent->currentState.angles, cent->lerpAngles);
|
||||
if ( cent->currentState.eType == ET_PLAYER ) {
|
||||
CG_ResetPlayerEntity( cent );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_TransitionEntity
|
||||
|
||||
cent->nextState is moved to cent->currentState and events are fired
|
||||
===============
|
||||
*/
|
||||
void CG_TransitionEntity( centity_t *cent ) {
|
||||
if (cent->nextState) {
|
||||
cent->currentState = *cent->nextState;
|
||||
}
|
||||
cent->currentValid = qtrue;
|
||||
|
||||
// reset if the entity wasn't in the last frame or was teleported
|
||||
if ( !cent->interpolate ) {
|
||||
CG_ResetEntity( cent );
|
||||
}
|
||||
|
||||
// clear the next state. if will be set by the next CG_SetNextSnap
|
||||
cent->interpolate = qfalse;
|
||||
|
||||
if ( cent->currentState.number != 0 )
|
||||
{
|
||||
// check for events
|
||||
CG_CheckEvents( cent );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_SetInitialSnapshot
|
||||
|
||||
This will only happen on the very first snapshot, or
|
||||
on tourney restarts. All other times will use
|
||||
CG_TransitionSnapshot instead.
|
||||
==================
|
||||
*/
|
||||
void CG_SetInitialSnapshot( snapshot_t *snap ) {
|
||||
int i;
|
||||
centity_t *cent;
|
||||
entityState_t *state;
|
||||
|
||||
cg.snap = snap;
|
||||
|
||||
// sort out solid entities
|
||||
//CG_BuildSolidList();
|
||||
|
||||
CG_ExecuteNewServerCommands( snap->serverCommandSequence );
|
||||
|
||||
// set our local weapon selection pointer to
|
||||
// what the server has indicated the current weapon is
|
||||
CG_Respawn();
|
||||
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
|
||||
state = &cg.snap->entities[ i ];
|
||||
cent = &cg_entities[ state->number ];
|
||||
|
||||
cent->currentState = *state;
|
||||
cent->interpolate = qfalse;
|
||||
cent->currentValid = qtrue;
|
||||
|
||||
CG_ResetEntity( cent );
|
||||
|
||||
// check for events
|
||||
CG_CheckEvents( cent );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_TransitionSnapshot
|
||||
|
||||
The transition point from snap to nextSnap has passed
|
||||
===================
|
||||
*/
|
||||
void CG_TransitionSnapshot( void ) {
|
||||
centity_t *cent;
|
||||
snapshot_t *oldFrame;
|
||||
int i;
|
||||
|
||||
if ( !cg.snap ) {
|
||||
CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
|
||||
}
|
||||
if ( !cg.nextSnap ) {
|
||||
CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
|
||||
}
|
||||
|
||||
// execute any server string commands before transitioning entities
|
||||
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
|
||||
|
||||
// clear the currentValid flag for all entities in the existing snapshot
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
|
||||
cent = &cg_entities[ cg.snap->entities[ i ].number ];
|
||||
cent->currentValid = qfalse;
|
||||
}
|
||||
|
||||
// move nextSnap to snap and do the transitions
|
||||
oldFrame = cg.snap;
|
||||
cg.snap = cg.nextSnap;
|
||||
|
||||
// sort out solid entities
|
||||
//CG_BuildSolidList();
|
||||
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ )
|
||||
{
|
||||
if ( 1 ) //cg.snap->entities[ i ].number != 0 ) // I guess the player adds his/her events elsewhere, so doing this also gives us double events for the player!
|
||||
{
|
||||
cent = &cg_entities[ cg.snap->entities[ i ].number ];
|
||||
CG_TransitionEntity( cent );
|
||||
}
|
||||
}
|
||||
|
||||
cg.nextSnap = NULL;
|
||||
|
||||
// check for playerstate transition events
|
||||
if ( oldFrame ) {
|
||||
// if we are not doing client side movement prediction for any
|
||||
// reason, then the client events and view changes will be issued now
|
||||
//if ( cg_timescale.value >= 1.0f )
|
||||
{
|
||||
CG_TransitionPlayerState( &cg.snap->ps, &oldFrame->ps );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_SetEntityNextState
|
||||
|
||||
Determine if the entity can be interpolated between the states
|
||||
present in cg.snap and cg,nextSnap
|
||||
===============
|
||||
*/
|
||||
void CG_SetEntityNextState( centity_t *cent, entityState_t *state ) {
|
||||
cent->nextState = state;
|
||||
|
||||
// since we can't interpolate ghoul2 stuff from one frame to another, I'm just going to copy the ghoul2 info directly into the current state now
|
||||
// CGhoul2Info *currentModel = &state->ghoul2[1];
|
||||
// cent->gent->ghoul2 = state->ghoul2;
|
||||
// CGhoul2Info *newModel = ¢->gent->ghoul2[1];
|
||||
|
||||
|
||||
// if this frame is a teleport, or the entity wasn't in the
|
||||
// previous frame, don't interpolate
|
||||
if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ state->eFlags ) & EF_TELEPORT_BIT ) ) {
|
||||
cent->interpolate = qfalse;
|
||||
} else {
|
||||
cent->interpolate = qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_SetNextSnap
|
||||
|
||||
A new snapshot has just been read in from the client system.
|
||||
===================
|
||||
*/
|
||||
void CG_SetNextSnap( snapshot_t *snap ) {
|
||||
int num;
|
||||
entityState_t *es;
|
||||
centity_t *cent;
|
||||
|
||||
cg.nextSnap = snap;
|
||||
|
||||
// check for extrapolation errors
|
||||
for ( num = 0 ; num < snap->numEntities ; num++ ) {
|
||||
es = &snap->entities[num];
|
||||
cent = &cg_entities[ es->number ];
|
||||
CG_SetEntityNextState( cent, es );
|
||||
}
|
||||
|
||||
// if the next frame is a teleport for the playerstate,
|
||||
if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
|
||||
cg.nextFrameTeleport = qtrue;
|
||||
} else {
|
||||
cg.nextFrameTeleport = qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
CG_ReadNextSnapshot
|
||||
|
||||
This is the only place new snapshots are requested
|
||||
This may increment cg.processedSnapshotNum multiple
|
||||
times if the client system fails to return a
|
||||
valid snapshot.
|
||||
========================
|
||||
*/
|
||||
snapshot_t *CG_ReadNextSnapshot( void ) {
|
||||
qboolean r;
|
||||
snapshot_t *dest;
|
||||
|
||||
while ( cg.processedSnapshotNum < cg.latestSnapshotNum ) {
|
||||
// decide which of the two slots to load it into
|
||||
if ( cg.snap == &cg.activeSnapshots[0] ) {
|
||||
dest = &cg.activeSnapshots[1];
|
||||
} else {
|
||||
dest = &cg.activeSnapshots[0];
|
||||
}
|
||||
|
||||
// try to read the snapshot from the client system
|
||||
cg.processedSnapshotNum++;
|
||||
r = cgi_GetSnapshot( cg.processedSnapshotNum, dest );
|
||||
|
||||
// if it succeeded, return
|
||||
if ( r ) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
// a GetSnapshot will return failure if the snapshot
|
||||
// never arrived, or is so old that its entities
|
||||
// have been shoved off the end of the circular
|
||||
// buffer in the client system.
|
||||
|
||||
// record as a dropped packet
|
||||
// CG_AddLagometerSnapshotInfo( NULL );
|
||||
|
||||
// If there are additional snapshots, continue trying to
|
||||
// read them.
|
||||
}
|
||||
|
||||
// nothing left to read
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_RestartLevel
|
||||
|
||||
A tournement restart will clear everything, but doesn't
|
||||
require a reload of all the media
|
||||
=================
|
||||
*/
|
||||
extern void CG_LinkCentsToGents(void);
|
||||
static void CG_RestartLevel( void ) {
|
||||
int snapshotNum;
|
||||
int r;
|
||||
|
||||
snapshotNum = cg.processedSnapshotNum;
|
||||
|
||||
memset( cg_entities, 0, sizeof( cg_entities ) );
|
||||
CG_Init_CG();
|
||||
|
||||
CG_LinkCentsToGents();
|
||||
CG_InitLocalEntities();
|
||||
CG_InitMarkPolys();
|
||||
|
||||
// regrab the first snapshot of the restart
|
||||
|
||||
cg.processedSnapshotNum = snapshotNum;
|
||||
r = cgi_GetSnapshot( cg.processedSnapshotNum, &cg.activeSnapshots[0] );
|
||||
if ( !r ) {
|
||||
CG_Error( "cgi_GetSnapshot failed on restart" );
|
||||
}
|
||||
|
||||
CG_SetInitialSnapshot( &cg.activeSnapshots[0] );
|
||||
cg.time = cg.snap->serverTime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
CG_ProcessSnapshots
|
||||
|
||||
We are trying to set up a renderable view, so determine
|
||||
what the simulated time is, and try to get snapshots
|
||||
both before and after that time if available.
|
||||
|
||||
If we don't have a valid cg.snap after exiting this function,
|
||||
then a 3D game view cannot be rendered. This should only happen
|
||||
right after the initial connection. After cg.snap has been valid
|
||||
once, it will never turn invalid.
|
||||
|
||||
Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
|
||||
hasn't arrived yet (it becomes an extrapolating situation instead
|
||||
of an interpolating one)
|
||||
|
||||
============
|
||||
*/
|
||||
void CG_ProcessSnapshots( void ) {
|
||||
snapshot_t *snap;
|
||||
int n;
|
||||
qboolean newSnapshots;
|
||||
|
||||
// see what the latest snapshot the client system has is
|
||||
cgi_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
|
||||
if ( n != cg.latestSnapshotNum ) {
|
||||
if ( n < cg.latestSnapshotNum ) {
|
||||
// this should never happen
|
||||
CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
|
||||
}
|
||||
cg.latestSnapshotNum = n;
|
||||
newSnapshots = qtrue;
|
||||
} else {
|
||||
newSnapshots = qfalse;
|
||||
}
|
||||
|
||||
// If we have yet to receive a snapshot, check for it.
|
||||
// Once we have gotten the first snapshot, cg.snap will
|
||||
// always have valid data for the rest of the game
|
||||
if ( !cg.snap ) {
|
||||
snap = CG_ReadNextSnapshot();
|
||||
if ( !snap ) {
|
||||
// we can't continue until we get a snapshot
|
||||
return;
|
||||
}
|
||||
|
||||
// set our weapon selection to what
|
||||
// the playerstate is currently using
|
||||
CG_SetInitialSnapshot( snap );
|
||||
}
|
||||
|
||||
// loop until we either have a valid nextSnap with a serverTime
|
||||
// greater than cg.time to interpolate towards, or we run
|
||||
// out of available snapshots
|
||||
do {
|
||||
// if we don't have a nextframe, try to read a new one in
|
||||
if ( !cg.nextSnap ) {
|
||||
snap = CG_ReadNextSnapshot();
|
||||
|
||||
// if we still don't have a nextframe, we will just have to
|
||||
// extrapolate
|
||||
if ( !snap ) {
|
||||
break;
|
||||
}
|
||||
|
||||
CG_SetNextSnap( snap );
|
||||
|
||||
// if time went backwards, we have a level restart
|
||||
if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
|
||||
// restart the level
|
||||
CG_RestartLevel();
|
||||
continue; // we might also get a nextsnap
|
||||
}
|
||||
}
|
||||
|
||||
// if our time is < nextFrame's, we have a nice interpolating state
|
||||
if ( cg.time < cg.nextSnap->serverTime ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// we have passed the transition from nextFrame to frame
|
||||
CG_TransitionSnapshot();
|
||||
} while ( 1 );
|
||||
|
||||
if ( cg.snap->serverTime > cg.time )
|
||||
{
|
||||
cg.time=cg.snap->serverTime;
|
||||
#if _DEBUG
|
||||
Com_Printf("CG_ProcessSnapshots: cg.snap->serverTime > cg.time");
|
||||
#endif
|
||||
|
||||
}
|
||||
if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time )
|
||||
{
|
||||
cg.time=cg.nextSnap->serverTime-1;
|
||||
#if _DEBUG
|
||||
Com_Printf("CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time");
|
||||
#endif
|
||||
}
|
||||
// assert our valid conditions upon exiting
|
||||
if ( cg.snap == NULL ) {
|
||||
CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
|
||||
}
|
||||
if ( cg.snap->serverTime > cg.time ) {
|
||||
CG_Error( "CG_ProcessSnapshots: cg.snap->serverTime > cg.time" );
|
||||
}
|
||||
if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
|
||||
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
|
||||
}
|
||||
}
|
||||
|
||||
646
code/cgame/cg_syscalls.cpp
Normal file
646
code/cgame/cg_syscalls.cpp
Normal file
@@ -0,0 +1,646 @@
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
//#include "cg_local.h"
|
||||
|
||||
// this file is only included when building a dll
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _IMMERSION
|
||||
#include "../ff/ff.h"
|
||||
#else
|
||||
///////////////////// this is a bit kludgy, but it only gives access to one
|
||||
// enum table because of the #define. May get changed.
|
||||
#define CGAME_ONLY
|
||||
#include "../client/fffx.h"
|
||||
//
|
||||
/////////////////////
|
||||
#endif // _IMMERSION
|
||||
|
||||
|
||||
|
||||
|
||||
//prototypes
|
||||
extern void CG_PreInit();
|
||||
|
||||
static int (*syscall)( int arg, ... ) = (int (*)( int, ...))-1;
|
||||
|
||||
#ifdef _XBOX
|
||||
void cg_dllEntry( int (*syscallptr)( int arg,... ) ) {
|
||||
#else
|
||||
void dllEntry( int (*syscallptr)( int arg,... ) ) {
|
||||
#endif
|
||||
syscall = syscallptr;
|
||||
CG_PreInit();
|
||||
}
|
||||
|
||||
|
||||
inline int PASSFLOAT( float x ) {
|
||||
float floatTemp;
|
||||
floatTemp = x;
|
||||
return *(int *)&floatTemp;
|
||||
}
|
||||
|
||||
void cgi_Printf( const char *fmt ) {
|
||||
syscall( CG_PRINT, fmt );
|
||||
}
|
||||
|
||||
void cgi_Error( const char *fmt ) {
|
||||
syscall( CG_ERROR, fmt );
|
||||
}
|
||||
|
||||
int cgi_Milliseconds( void ) {
|
||||
return syscall( CG_MILLISECONDS );
|
||||
}
|
||||
|
||||
void cgi_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
|
||||
syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );
|
||||
}
|
||||
|
||||
void cgi_Cvar_Update( vmCvar_t *vmCvar ) {
|
||||
syscall( CG_CVAR_UPDATE, vmCvar );
|
||||
}
|
||||
|
||||
void cgi_Cvar_Set( const char *var_name, const char *value ) {
|
||||
syscall( CG_CVAR_SET, var_name, value );
|
||||
}
|
||||
|
||||
int cgi_Argc( void ) {
|
||||
return syscall( CG_ARGC );
|
||||
}
|
||||
|
||||
void cgi_Argv( int n, char *buffer, int bufferLength ) {
|
||||
syscall( CG_ARGV, n, buffer, bufferLength );
|
||||
}
|
||||
|
||||
void cgi_Args( char *buffer, int bufferLength ) {
|
||||
syscall( CG_ARGS, buffer, bufferLength );
|
||||
}
|
||||
|
||||
int cgi_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
|
||||
return syscall( CG_FS_FOPENFILE, qpath, f, mode );
|
||||
}
|
||||
|
||||
int cgi_FS_Read( void *buffer, int len, fileHandle_t f ) {
|
||||
return syscall( CG_FS_READ, buffer, len, f );
|
||||
}
|
||||
|
||||
int cgi_FS_Write( const void *buffer, int len, fileHandle_t f ) {
|
||||
return syscall( CG_FS_WRITE, buffer, len, f );
|
||||
}
|
||||
|
||||
void cgi_FS_FCloseFile( fileHandle_t f ) {
|
||||
syscall( CG_FS_FCLOSEFILE, f );
|
||||
}
|
||||
|
||||
void cgi_SendConsoleCommand( const char *text ) {
|
||||
syscall( CG_SENDCONSOLECOMMAND, text );
|
||||
}
|
||||
|
||||
void cgi_AddCommand( const char *cmdName ) {
|
||||
syscall( CG_ADDCOMMAND, cmdName );
|
||||
}
|
||||
|
||||
void cgi_SendClientCommand( const char *s ) {
|
||||
syscall( CG_SENDCLIENTCOMMAND, s );
|
||||
}
|
||||
|
||||
void cgi_UpdateScreen( void ) {
|
||||
syscall( CG_UPDATESCREEN );
|
||||
}
|
||||
|
||||
//RMG BEGIN
|
||||
void cgi_RMG_Init(int terrainID, const char *terrainInfo)
|
||||
{
|
||||
syscall( CG_RMG_INIT, terrainID, terrainInfo);
|
||||
}
|
||||
|
||||
int cgi_CM_RegisterTerrain(const char *terrainInfo)
|
||||
{
|
||||
return syscall( CG_CM_REGISTER_TERRAIN, terrainInfo);
|
||||
}
|
||||
|
||||
void cgi_RE_InitRendererTerrain( const char *terrainInfo )
|
||||
{
|
||||
syscall(CG_RE_INIT_RENDERER_TERRAIN, terrainInfo);
|
||||
}
|
||||
//RMG END
|
||||
|
||||
void cgi_CM_LoadMap( const char *mapname, qboolean subBSP ) {
|
||||
syscall( CG_CM_LOADMAP, mapname, subBSP );
|
||||
}
|
||||
|
||||
int cgi_CM_NumInlineModels( void ) {
|
||||
return syscall( CG_CM_NUMINLINEMODELS );
|
||||
}
|
||||
|
||||
clipHandle_t cgi_CM_InlineModel( int index ) {
|
||||
return syscall( CG_CM_INLINEMODEL, index );
|
||||
}
|
||||
|
||||
clipHandle_t cgi_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {//, const int contents ) {
|
||||
return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );//, contents );
|
||||
}
|
||||
|
||||
int cgi_CM_PointContents( const vec3_t p, clipHandle_t model ) {
|
||||
return syscall( CG_CM_POINTCONTENTS, p, model );
|
||||
}
|
||||
|
||||
int cgi_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {
|
||||
return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );
|
||||
}
|
||||
|
||||
void cgi_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
|
||||
const vec3_t mins, const vec3_t maxs,
|
||||
clipHandle_t model, int brushmask ) {
|
||||
syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );
|
||||
}
|
||||
|
||||
void cgi_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
|
||||
const vec3_t mins, const vec3_t maxs,
|
||||
clipHandle_t model, int brushmask,
|
||||
const vec3_t origin, const vec3_t angles ) {
|
||||
syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
|
||||
}
|
||||
|
||||
int cgi_CM_MarkFragments( int numPoints, const vec3_t *points,
|
||||
const vec3_t projection,
|
||||
int maxPoints, vec3_t pointBuffer,
|
||||
int maxFragments, markFragment_t *fragmentBuffer ) {
|
||||
return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
|
||||
}
|
||||
|
||||
void cgi_CM_SnapPVS(vec3_t origin,byte *buffer)
|
||||
{
|
||||
syscall(CG_CM_SNAPPVS,origin,buffer);
|
||||
}
|
||||
|
||||
void cgi_S_StopSounds( void )
|
||||
{
|
||||
syscall( CG_S_STOPSOUNDS);
|
||||
}
|
||||
|
||||
void cgi_S_StartSound( const vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {
|
||||
syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );
|
||||
}
|
||||
|
||||
void cgi_AS_ParseSets( void ) {
|
||||
syscall( CG_AS_PARSESETS );
|
||||
}
|
||||
|
||||
void cgi_AS_AddPrecacheEntry( const char *name ) {
|
||||
syscall( CG_AS_ADDENTRY, name );
|
||||
}
|
||||
|
||||
void cgi_S_UpdateAmbientSet( const char *name, vec3_t origin ) {
|
||||
syscall( CG_S_UPDATEAMBIENTSET, name, origin );
|
||||
}
|
||||
|
||||
int cgi_S_AddLocalSet( const char *name, vec3_t listener_origin, vec3_t origin, int entID, int time ) {
|
||||
return syscall( CG_S_ADDLOCALSET, name, listener_origin, origin, entID, time );
|
||||
}
|
||||
|
||||
sfxHandle_t cgi_AS_GetBModelSound( const char *name, int stage ) {
|
||||
return syscall( CG_AS_GETBMODELSOUND, name, stage );
|
||||
}
|
||||
|
||||
void cgi_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
|
||||
syscall( CG_S_STARTLOCALSOUND, sfx, channelNum );
|
||||
}
|
||||
|
||||
void cgi_S_ClearLoopingSounds( void ) {
|
||||
syscall( CG_S_CLEARLOOPINGSOUNDS );
|
||||
}
|
||||
|
||||
void cgi_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, soundChannel_t chan ) {
|
||||
syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx, chan );
|
||||
}
|
||||
|
||||
void cgi_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
|
||||
syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );
|
||||
}
|
||||
|
||||
void cgi_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], qboolean inwater ) {
|
||||
syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );
|
||||
}
|
||||
|
||||
sfxHandle_t cgi_S_RegisterSound( const char *sample ) {
|
||||
return syscall( CG_S_REGISTERSOUND, sample );
|
||||
}
|
||||
|
||||
void cgi_S_StartBackgroundTrack( const char *intro, const char *loop, qboolean bForceStart ) {
|
||||
syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop, bForceStart );
|
||||
}
|
||||
|
||||
float cgi_S_GetSampleLength( sfxHandle_t sfx ) {
|
||||
return syscall( CG_S_GETSAMPLELENGTH, sfx);
|
||||
}
|
||||
|
||||
#ifdef _IMMERSION
|
||||
|
||||
void cgi_FF_Start( ffHandle_t ff, int clientNum ){
|
||||
syscall( CG_FF_START, ff, clientNum );
|
||||
}
|
||||
|
||||
void cgi_FF_Stop( ffHandle_t ff, int clientNum ){
|
||||
syscall( CG_FF_STOP, ff, clientNum );
|
||||
}
|
||||
|
||||
void cgi_FF_StopAll( void ){
|
||||
syscall( CG_FF_STOPALL );
|
||||
}
|
||||
|
||||
void cgi_FF_Shake( int intensity, int duration ){
|
||||
syscall( CG_FF_SHAKE, intensity, duration );
|
||||
}
|
||||
|
||||
ffHandle_t cgi_FF_Register( const char *name, int channel ){
|
||||
return syscall( CG_FF_REGISTER, name, channel );
|
||||
}
|
||||
|
||||
void cgi_FF_AddLoopingForce( ffHandle_t handle, int entNum ){
|
||||
syscall( CG_FF_ADDLOOPINGFORCE, handle, entNum );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void cgi_FF_StartFX( int iFX ){
|
||||
syscall( CG_FF_STARTFX, iFX );
|
||||
}
|
||||
|
||||
void cgi_FF_EnsureFX( int iFX ){
|
||||
syscall( CG_FF_ENSUREFX, iFX );
|
||||
}
|
||||
|
||||
void cgi_FF_StopFX( int iFX ){
|
||||
syscall( CG_FF_STOPFX, iFX );
|
||||
}
|
||||
|
||||
void cgi_FF_StopAllFX( void ){
|
||||
syscall( CG_FF_STOPALLFX );
|
||||
}
|
||||
|
||||
#endif // _IMMERSION
|
||||
|
||||
#ifdef _XBOX
|
||||
|
||||
void cgi_FF_Xbox_Shake( float intensity, int duration ){
|
||||
syscall( CG_FF_XBOX_SHAKE, PASSFLOAT(intensity), duration );
|
||||
}
|
||||
|
||||
void cgi_FF_Xbox_Damage( int damage, float xpos ) {
|
||||
syscall( CG_FF_XBOX_DAMAGE, damage, PASSFLOAT(xpos) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void cgi_R_LoadWorldMap( const char *mapname ) {
|
||||
syscall( CG_R_LOADWORLDMAP, mapname );
|
||||
}
|
||||
|
||||
qhandle_t cgi_R_RegisterModel( const char *name ) {
|
||||
return syscall( CG_R_REGISTERMODEL, name );
|
||||
}
|
||||
|
||||
qhandle_t cgi_R_RegisterSkin( const char *name ) {
|
||||
return syscall( CG_R_REGISTERSKIN, name );
|
||||
}
|
||||
|
||||
qhandle_t cgi_R_RegisterShader( const char *name ) {
|
||||
qhandle_t hShader = syscall( CG_R_REGISTERSHADER, name );
|
||||
assert (hShader);
|
||||
return hShader;
|
||||
}
|
||||
|
||||
qhandle_t cgi_R_RegisterShaderNoMip( const char *name ) {
|
||||
return syscall( CG_R_REGISTERSHADERNOMIP, name );
|
||||
}
|
||||
|
||||
qhandle_t cgi_R_RegisterFont( const char *name ) {
|
||||
return syscall( CG_R_REGISTERFONT, name );
|
||||
}
|
||||
|
||||
int cgi_R_Font_StrLenPixels(const char *text, const int iFontIndex, const float scale /*= 1.0f*/) {
|
||||
return syscall( CG_R_FONTSTRLENPIXELS, text, iFontIndex, PASSFLOAT(scale) ) ;
|
||||
}
|
||||
|
||||
int cgi_R_Font_StrLenChars(const char *text) {
|
||||
return syscall( CG_R_FONTSTRLENCHARS, text ) ;
|
||||
}
|
||||
|
||||
int cgi_R_Font_HeightPixels(const int iFontIndex, const float scale /*= 1.0f*/) {
|
||||
return syscall( CG_R_FONTHEIGHTPIXELS, iFontIndex, PASSFLOAT(scale) );
|
||||
}
|
||||
|
||||
qboolean cgi_Language_IsAsian( void )
|
||||
{
|
||||
return syscall( CG_LANGUAGE_ISASIAN );
|
||||
}
|
||||
|
||||
qboolean cgi_Language_UsesSpaces(void)
|
||||
{
|
||||
return syscall( CG_LANGUAGE_USESSPACES );
|
||||
}
|
||||
|
||||
unsigned int cgi_AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation /* = NULL */ )
|
||||
{
|
||||
return syscall( CG_ANYLANGUAGE_READFROMSTRING, psText, piAdvanceCount, pbIsTrailingPunctuation );
|
||||
}
|
||||
|
||||
void cgi_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iMaxPixelWidth, const float scale /*= 1.0f*/) {
|
||||
syscall (CG_R_FONTDRAWSTRING, ox, oy, text, rgba, setIndex, iMaxPixelWidth, PASSFLOAT(scale) );
|
||||
}
|
||||
|
||||
//set some properties for the draw layer for my refractive effect (here primarily for mod authors) -rww
|
||||
void cgi_R_SetRefractProp(float alpha, float stretch, qboolean prepost, qboolean negate)
|
||||
{
|
||||
syscall(CG_R_SETREFRACTIONPROP, PASSFLOAT(alpha), PASSFLOAT(stretch), prepost, negate);
|
||||
}
|
||||
|
||||
void cgi_R_ClearScene( void ) {
|
||||
syscall( CG_R_CLEARSCENE );
|
||||
}
|
||||
|
||||
void cgi_R_AddRefEntityToScene( const refEntity_t *re ) {
|
||||
syscall( CG_R_ADDREFENTITYTOSCENE, re );
|
||||
}
|
||||
|
||||
qboolean cgi_R_inPVS( vec3_t p1, vec3_t p2 )
|
||||
{
|
||||
return syscall( CG_R_INPVS, p1, p2 );
|
||||
}
|
||||
|
||||
|
||||
void cgi_R_GetLighting( const vec3_t origin, vec3_t ambientLight, vec3_t directedLight, vec3_t ligthDir ) {
|
||||
syscall( CG_R_GETLIGHTING, origin, ambientLight, directedLight, ligthDir );
|
||||
}
|
||||
|
||||
void cgi_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
|
||||
syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
|
||||
}
|
||||
|
||||
void cgi_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
|
||||
syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
|
||||
}
|
||||
|
||||
void cgi_R_RenderScene( const refdef_t *fd ) {
|
||||
syscall( CG_R_RENDERSCENE, fd );
|
||||
}
|
||||
|
||||
void cgi_R_SetColor( const float *rgba ) {
|
||||
syscall( CG_R_SETCOLOR, rgba );
|
||||
}
|
||||
|
||||
void cgi_R_DrawStretchPic( float x, float y, float w, float h,
|
||||
float s1, float t1, float s2, float t2, qhandle_t hShader ) {
|
||||
syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
|
||||
}
|
||||
|
||||
//void cgi_R_DrawScreenShot( float x, float y, float w, float h){
|
||||
// syscall( CG_R_DRAWSCREENSHOT, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h) );
|
||||
//}
|
||||
|
||||
void cgi_R_ModelBounds( qhandle_t model, vec3_t mins, vec3_t maxs ) {
|
||||
syscall( CG_R_MODELBOUNDS, model, mins, maxs );
|
||||
}
|
||||
|
||||
void cgi_R_LerpTag( orientation_t *tag, qhandle_t mod, int startFrame, int endFrame,
|
||||
float frac, const char *tagName ) {
|
||||
syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
|
||||
}
|
||||
|
||||
void cgi_R_DrawRotatePic( float x, float y, float w, float h,
|
||||
float s1, float t1, float s2, float t2,float a, qhandle_t hShader )
|
||||
{
|
||||
syscall( CG_R_DRAWROTATEPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), PASSFLOAT(a), hShader );
|
||||
}
|
||||
|
||||
void cgi_R_DrawRotatePic2( float x, float y, float w, float h,
|
||||
float s1, float t1, float s2, float t2,float a, qhandle_t hShader )
|
||||
{
|
||||
syscall( CG_R_DRAWROTATEPIC2, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), PASSFLOAT(a), hShader );
|
||||
}
|
||||
|
||||
//linear fogging, with settable range -rww
|
||||
void cgi_R_SetRangeFog(float range)
|
||||
{
|
||||
syscall(CG_R_SETRANGEFOG, PASSFLOAT(range));
|
||||
}
|
||||
|
||||
void cgi_R_LAGoggles( void )
|
||||
{
|
||||
syscall( CG_R_LA_GOGGLES );
|
||||
}
|
||||
|
||||
void cgi_R_Scissor( float x, float y, float w, float h)
|
||||
{
|
||||
syscall( CG_R_SCISSOR, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h));
|
||||
}
|
||||
|
||||
void cgi_GetGlconfig( glconfig_t *glconfig ) {
|
||||
syscall( CG_GETGLCONFIG, glconfig );
|
||||
}
|
||||
|
||||
void cgi_GetGameState( gameState_t *gamestate ) {
|
||||
syscall( CG_GETGAMESTATE, gamestate );
|
||||
}
|
||||
|
||||
void cgi_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
|
||||
syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );
|
||||
}
|
||||
|
||||
qboolean cgi_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
|
||||
return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );
|
||||
}
|
||||
|
||||
qboolean cgi_GetDefaultState(int entityIndex, entityState_t *state )
|
||||
{
|
||||
return syscall( CG_GETDEFAULTSTATE, entityIndex, state );
|
||||
}
|
||||
|
||||
qboolean cgi_GetServerCommand( int serverCommandNumber ) {
|
||||
return syscall( CG_GETSERVERCOMMAND, serverCommandNumber );
|
||||
}
|
||||
|
||||
int cgi_GetCurrentCmdNumber( void ) {
|
||||
return syscall( CG_GETCURRENTCMDNUMBER );
|
||||
}
|
||||
|
||||
qboolean cgi_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
|
||||
return syscall( CG_GETUSERCMD, cmdNumber, ucmd );
|
||||
}
|
||||
|
||||
void cgi_SetUserCmdValue( int stateValue, float sensitivityScale, float mPitchOverride, float mYawOverride ) {
|
||||
syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale), PASSFLOAT(mPitchOverride), PASSFLOAT(mYawOverride) );
|
||||
}
|
||||
|
||||
void cgi_SetUserCmdAngles( float pitchOverride, float yawOverride, float rollOverride ) {
|
||||
syscall( CG_SETUSERCMDANGLES, PASSFLOAT(pitchOverride), PASSFLOAT(yawOverride), PASSFLOAT(rollOverride) );
|
||||
}
|
||||
/*
|
||||
Ghoul2 Insert Start
|
||||
*/
|
||||
// CG Specific API calls
|
||||
void trap_G2_SetGhoul2ModelIndexes(CGhoul2Info_v &ghoul2, qhandle_t *modelList, qhandle_t *skinList)
|
||||
{
|
||||
syscall( CG_G2_SETMODELS, &ghoul2, modelList, skinList);
|
||||
}
|
||||
/*
|
||||
Ghoul2 Insert End
|
||||
*/
|
||||
|
||||
void trap_Com_SetOrgAngles(vec3_t org,vec3_t angles)
|
||||
{
|
||||
syscall(COM_SETORGANGLES,org,angles);
|
||||
}
|
||||
|
||||
void trap_R_GetLightStyle(int style, color4ub_t color)
|
||||
{
|
||||
syscall(CG_R_GET_LIGHT_STYLE, style, color);
|
||||
}
|
||||
|
||||
void trap_R_SetLightStyle(int style, int color)
|
||||
{
|
||||
syscall(CG_R_SET_LIGHT_STYLE, style, color);
|
||||
}
|
||||
|
||||
void cgi_R_GetBModelVerts(int bmodelIndex, vec3_t *verts, vec3_t normal )
|
||||
{
|
||||
syscall( CG_R_GET_BMODEL_VERTS, bmodelIndex, verts, normal );
|
||||
}
|
||||
|
||||
void cgi_R_WorldEffectCommand( const char *command )
|
||||
{
|
||||
syscall( CG_R_WORLD_EFFECT_COMMAND, command );
|
||||
}
|
||||
|
||||
// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
|
||||
int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits, const char *psAudioFile /* = NULL */) {
|
||||
return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits, psAudioFile);
|
||||
}
|
||||
|
||||
// stops playing the cinematic and ends it. should always return FMV_EOF
|
||||
// cinematics must be stopped in reverse order of when they are started
|
||||
e_status trap_CIN_StopCinematic(int handle) {
|
||||
return (e_status) syscall(CG_CIN_STOPCINEMATIC, handle);
|
||||
}
|
||||
|
||||
|
||||
// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
|
||||
e_status trap_CIN_RunCinematic (int handle) {
|
||||
return (e_status) syscall(CG_CIN_RUNCINEMATIC, handle);
|
||||
}
|
||||
|
||||
|
||||
// draws the current frame
|
||||
void trap_CIN_DrawCinematic (int handle) {
|
||||
syscall(CG_CIN_DRAWCINEMATIC, handle);
|
||||
}
|
||||
|
||||
|
||||
// allows you to resize the animation dynamically
|
||||
void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
|
||||
syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);
|
||||
}
|
||||
|
||||
void *cgi_Z_Malloc( int size, int tag )
|
||||
{
|
||||
return (void *)syscall(CG_Z_MALLOC,size,tag);
|
||||
}
|
||||
|
||||
void cgi_Z_Free( void *ptr )
|
||||
{
|
||||
syscall(CG_Z_FREE,ptr);
|
||||
}
|
||||
|
||||
void cgi_UI_SetActive_Menu(char *name)
|
||||
{
|
||||
syscall(CG_UI_SETACTIVE_MENU,name);
|
||||
}
|
||||
|
||||
void cgi_UI_Menu_OpenByName(char *buf)
|
||||
{
|
||||
syscall(CG_UI_MENU_OPENBYNAME,buf);
|
||||
}
|
||||
|
||||
void cgi_UI_Menu_Reset(void)
|
||||
{
|
||||
syscall(CG_UI_MENU_RESET);
|
||||
}
|
||||
|
||||
void cgi_UI_Menu_New(char *buf)
|
||||
{
|
||||
syscall(CG_UI_MENU_NEW,buf);
|
||||
}
|
||||
|
||||
void cgi_UI_Parse_Int(int *value)
|
||||
{
|
||||
syscall(CG_UI_PARSE_INT,value);
|
||||
}
|
||||
|
||||
void cgi_UI_Parse_String(char *buf)
|
||||
{
|
||||
syscall(CG_UI_PARSE_STRING,buf);
|
||||
}
|
||||
|
||||
void cgi_UI_Parse_Float(float *value)
|
||||
{
|
||||
syscall(CG_UI_PARSE_FLOAT,value);
|
||||
}
|
||||
|
||||
int cgi_UI_StartParseSession(char *menuFile,char **buf)
|
||||
{
|
||||
return(int) syscall(CG_UI_STARTPARSESESSION,menuFile,buf);
|
||||
}
|
||||
|
||||
void cgi_UI_EndParseSession(char *buf)
|
||||
{
|
||||
syscall(CG_UI_ENDPARSESESSION,buf);
|
||||
}
|
||||
|
||||
void cgi_UI_ParseExt(char **token)
|
||||
{
|
||||
syscall(CG_UI_PARSEEXT,token);
|
||||
}
|
||||
|
||||
void cgi_UI_MenuCloseAll(void)
|
||||
{
|
||||
syscall(CG_UI_MENUCLOSE_ALL);
|
||||
}
|
||||
|
||||
void cgi_UI_MenuPaintAll(void)
|
||||
{
|
||||
syscall(CG_UI_MENUPAINT_ALL);
|
||||
}
|
||||
|
||||
void cgi_UI_String_Init(void)
|
||||
{
|
||||
syscall(CG_UI_STRING_INIT);
|
||||
}
|
||||
|
||||
int cgi_UI_GetMenuInfo(char *menuFile,int *x,int *y,int *w,int *h)
|
||||
{
|
||||
return(int) syscall(CG_UI_GETMENUINFO,menuFile,x,y,w,h);
|
||||
}
|
||||
|
||||
int cgi_UI_GetMenuItemInfo(const char *menuFile,const char *itemName, int *x,int *y,int *w,int *h,vec4_t color,qhandle_t *background)
|
||||
{
|
||||
return(int) syscall(CG_UI_GETITEMINFO,menuFile,itemName,x,y,w,h,color,background);
|
||||
}
|
||||
|
||||
int cgi_UI_GetItemText(char *menuFile,char *itemName, char* text)
|
||||
{
|
||||
return(int) syscall(CG_UI_GETITEMTEXT,menuFile,itemName,text);
|
||||
}
|
||||
|
||||
int cgi_SP_GetStringTextString(const char *text, char *buffer, int bufferLength)
|
||||
{
|
||||
return syscall( CG_SP_GETSTRINGTEXTSTRING, text, buffer, bufferLength );
|
||||
}
|
||||
|
||||
int cgi_EndGame(void)
|
||||
{
|
||||
return syscall( CG_SENDCONSOLECOMMAND, "cam_disable; disconnect\n" );//; cinematic outcast
|
||||
}
|
||||
786
code/cgame/cg_text.cpp
Normal file
786
code/cgame/cg_text.cpp
Normal file
@@ -0,0 +1,786 @@
|
||||
// cg_text.c --
|
||||
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
#include "cg_media.h"
|
||||
|
||||
|
||||
//int precacheWav_i; // Current high index of precacheWav array
|
||||
//precacheWav_t precacheWav[MAX_PRECACHEWAV];
|
||||
|
||||
|
||||
//int precacheText_i; // Current high index of precacheText array
|
||||
//precacheText_t precacheText[MAX_PRECACHETEXT];
|
||||
#define TEXT_SCREEN_WIDTH_FRACTION_CUTSCENE 0.85
|
||||
#define TEXT_SCREEN_WIDTH_FRACTION_INGAME 0.85
|
||||
#define TEXT_SCREEN_HEIGHT_INGAME 0.15f
|
||||
#define TEXT_CUTSCENE_Y_BOOST 18
|
||||
#define NUDGE_PERCENTAGE 0.90
|
||||
|
||||
extern vec4_t textcolor_caption;
|
||||
extern vec4_t textcolor_center;
|
||||
extern vec4_t textcolor_scroll;
|
||||
|
||||
|
||||
// display text in a supplied box, start at top left and going down by however many pixels I feel like internally,
|
||||
// return value is NULL if all fitted, else char * of next char to continue from that didn't fit.
|
||||
//
|
||||
// (coords are in the usual 640x480 virtual space)...
|
||||
//
|
||||
// ( if you get the same char * returned as what you passed in, then none of it fitted at all (box too small) )
|
||||
//
|
||||
// this is execrable, and should NOT have had to've been done now, but...
|
||||
//
|
||||
float gfAdvanceHack = 0.0f; // MUST default to this
|
||||
int giLinesOutput; // hack-city after release, only used by one function
|
||||
//
|
||||
const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight,
|
||||
const char *psText, int iFontHandle, float fScale,
|
||||
const vec4_t v4Color)
|
||||
{
|
||||
giLinesOutput = 0;
|
||||
cgi_R_SetColor( v4Color );
|
||||
|
||||
// Setup a reasonable vertical spacing (taiwanese & japanese need 1.5 fontheight, so use that for all)...
|
||||
//
|
||||
const int iFontHeight = cgi_R_Font_HeightPixels(iFontHandle, fScale);
|
||||
const int iFontHeightAdvance = (int) ( ((gfAdvanceHack == 0.0f) ? 1.5f : gfAdvanceHack) * (float) iFontHeight);
|
||||
int iYpos = iBoxY; // start print pos
|
||||
|
||||
// this could probably be simplified now, but it was converted from something else I didn't originally write,
|
||||
// and it works anyway so wtf...
|
||||
//
|
||||
const char *psCurrentTextReadPos = psText;
|
||||
const char *psReadPosAtLineStart = psCurrentTextReadPos;
|
||||
const char *psBestLineBreakSrcPos = psCurrentTextReadPos;
|
||||
const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes)
|
||||
while( *psCurrentTextReadPos && (iYpos + iFontHeight < (iBoxY + iBoxHeight)) )
|
||||
{
|
||||
char sLineForDisplay[2048]; // ott
|
||||
|
||||
// construct a line...
|
||||
//
|
||||
psCurrentTextReadPos = psReadPosAtLineStart;
|
||||
sLineForDisplay[0] = '\0';
|
||||
while ( *psCurrentTextReadPos )
|
||||
{
|
||||
psLastGood_s = psCurrentTextReadPos;
|
||||
|
||||
// read letter...
|
||||
//
|
||||
qboolean bIsTrailingPunctuation;
|
||||
int iAdvanceCount;
|
||||
unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(psCurrentTextReadPos, &iAdvanceCount, &bIsTrailingPunctuation);
|
||||
psCurrentTextReadPos += iAdvanceCount;
|
||||
|
||||
// concat onto string so far...
|
||||
//
|
||||
if (uiLetter == 32 && sLineForDisplay[0] == '\0')
|
||||
{
|
||||
psReadPosAtLineStart++;
|
||||
continue; // unless it's a space at the start of a line, in which case ignore it.
|
||||
}
|
||||
|
||||
if (uiLetter > 255)
|
||||
{
|
||||
Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c",uiLetter & 0xFF));
|
||||
}
|
||||
|
||||
if (uiLetter == '\n')
|
||||
{
|
||||
// explicit new line...
|
||||
//
|
||||
sLineForDisplay[ strlen(sLineForDisplay)-1 ] = '\0'; // kill the CR
|
||||
psReadPosAtLineStart = psCurrentTextReadPos;
|
||||
psBestLineBreakSrcPos = psCurrentTextReadPos;
|
||||
break; // print this line
|
||||
}
|
||||
else
|
||||
if ( cgi_R_Font_StrLenPixels(sLineForDisplay, iFontHandle, fScale) >= iBoxWidth )
|
||||
{
|
||||
// reached screen edge, so cap off string at bytepos after last good position...
|
||||
//
|
||||
if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces())
|
||||
{
|
||||
// Special case, don't consider line breaking if you're on an asian punctuation char of
|
||||
// a language that doesn't use spaces...
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
if (psBestLineBreakSrcPos == psReadPosAtLineStart)
|
||||
{
|
||||
// aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string,
|
||||
// since it doesn't have a single space or punctuation mark right the way across one line
|
||||
// of the screen. So far, this has only happened in testing when I hardwired a taiwanese
|
||||
// string into this function while the game was running in english (which should NEVER happen
|
||||
// normally). On the other hand I suppose it'psCurrentTextReadPos entirely possible that some taiwanese string
|
||||
// might have no punctuation at all, so...
|
||||
//
|
||||
psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter
|
||||
}
|
||||
|
||||
sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0';
|
||||
psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos;
|
||||
break; // print this line
|
||||
}
|
||||
}
|
||||
|
||||
// record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space)
|
||||
//
|
||||
if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces()))
|
||||
{
|
||||
psBestLineBreakSrcPos = psCurrentTextReadPos;
|
||||
}
|
||||
}
|
||||
|
||||
// ... and print it...
|
||||
//
|
||||
cgi_R_Font_DrawString(iBoxX, iYpos, sLineForDisplay, v4Color, iFontHandle, -1, fScale);
|
||||
iYpos += iFontHeightAdvance;
|
||||
giLinesOutput++;
|
||||
|
||||
// and echo to console in dev mode...
|
||||
//
|
||||
if ( cg_developer.integer )
|
||||
{
|
||||
// Com_Printf( "%psCurrentTextReadPos\n", sLineForDisplay );
|
||||
}
|
||||
}
|
||||
return psReadPosAtLineStart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
CAPTION TEXT
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
void CG_CaptionTextStop(void)
|
||||
{
|
||||
cg.captionTextTime = 0;
|
||||
}
|
||||
|
||||
// try and get the correct StripEd text (with retry) for a given reference...
|
||||
//
|
||||
// returns 0 if failed, else strlen...
|
||||
//
|
||||
static int cg_SP_GetStringTextStringWithRetry( LPCSTR psReference, char *psDest, int iSizeofDest)
|
||||
{
|
||||
int iReturn;
|
||||
|
||||
if (psReference[0] == '#')
|
||||
{
|
||||
// then we know the striped package name is already built in, so do NOT try prepending anything else...
|
||||
//
|
||||
return cgi_SP_GetStringTextString( va("%s",psReference+1), psDest, iSizeofDest );
|
||||
}
|
||||
|
||||
for (int i=0; i<STRIPED_LEVELNAME_VARIATIONS; i++)
|
||||
{
|
||||
if (cgs.stripLevelName[i][0]) // entry present?
|
||||
{
|
||||
iReturn = cgi_SP_GetStringTextString( va("%s_%s",cgs.stripLevelName[i],psReference), psDest, iSizeofDest );
|
||||
if (iReturn)
|
||||
{
|
||||
return iReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// slightly confusingly, the char arg for this function is an audio filename of the form "path/path/filename",
|
||||
// the "filename" part of which should be the same as the StripEd reference we're looking for in the current
|
||||
// level's string package...
|
||||
//
|
||||
void CG_CaptionText( const char *str, int sound, int y )
|
||||
{
|
||||
const char *s, *holds;
|
||||
int i;
|
||||
int holdTime;
|
||||
char text[8192]={0};
|
||||
|
||||
const float fFontScale = cgi_Language_IsAsian() ? 0.8f : 1.0f;
|
||||
|
||||
holds = strrchr(str,'/');
|
||||
if (!holds)
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf("WARNING: CG_CaptionText given audio filename with no '/':'%s'\n",str);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = cg_SP_GetStringTextStringWithRetry( holds+1, text, sizeof(text) );
|
||||
//ensure we found a match
|
||||
if (!i)
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
// we only care about some sound dirs...
|
||||
if (!strnicmp(str,"sound/chars/",12)) // whichever language it is, it'll be pathed as english at this point
|
||||
{
|
||||
Com_Printf("WARNING: CG_CaptionText given invalid text key :'%s'\n",str);
|
||||
}
|
||||
else
|
||||
{
|
||||
// anything else is probably stuff we don't care about. It certainly shouldn't be speech, anyway
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
const int fontHeight = (int) ((cgi_Language_IsAsian() ? 1.4f : 1.0f) * (float) cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, fFontScale)); // taiwanese & japanese need 1.5 fontheight spacing
|
||||
int lineWidth;
|
||||
|
||||
cg.captionTextTime = cg.time;
|
||||
if (in_camera) {
|
||||
cg.captionTextY = SCREEN_HEIGHT - (client_camera.bar_height_dest/2)- TEXT_CUTSCENE_Y_BOOST; // ths is now a centre'd Y, not a start Y
|
||||
#ifdef _XBOX
|
||||
if(cg.widescreen)
|
||||
lineWidth = 720 * TEXT_SCREEN_WIDTH_FRACTION_CUTSCENE ;
|
||||
else
|
||||
#endif
|
||||
lineWidth = SCREEN_WIDTH * TEXT_SCREEN_WIDTH_FRACTION_CUTSCENE ;
|
||||
|
||||
} else { //get above the hud
|
||||
cg.captionTextY = (int) (TEXT_SCREEN_HEIGHT_INGAME * ((float)SCREEN_HEIGHT - (float)fontHeight * 1.5f)); // do NOT move this, it has to fit in between the weapon HUD and the datapad update.
|
||||
#ifdef _XBOX
|
||||
if(cg.widescreen)
|
||||
lineWidth = 720 * TEXT_SCREEN_WIDTH_FRACTION_INGAME ;
|
||||
else
|
||||
#endif
|
||||
lineWidth = SCREEN_WIDTH * TEXT_SCREEN_WIDTH_FRACTION_INGAME ;
|
||||
}
|
||||
cg.captionTextCurrentLine = 0;
|
||||
|
||||
// count the number of lines for centering
|
||||
cg.scrollTextLines = 1;
|
||||
|
||||
memset (cg.captionText, 0, sizeof(cg.captionText));
|
||||
|
||||
// Break into individual lines
|
||||
i = 0; // this could be completely removed and replace by "cg.scrollTextLines-1", but wtf?
|
||||
|
||||
s=(const char*)&text;
|
||||
// tai...
|
||||
// s="賽卓哥爾博士已經安全了,我也把所有發現報告給「商店」。很不幸地,瑞士警局有些白癡發現了一些狀況,準備在機場逮捕亞歷西‧納克瑞得。他偽裝成外交使節,穿過了層層防備。現在他握有人質,並且威脅要散播病毒。根據最新的報告,納克瑞得以及他的黨羽已經完全佔據了機場。我受命來追捕納克瑞得以及救出所有人質。這並不容易。";
|
||||
// kor...
|
||||
// s="Wp:澗顫歜檜棻 詩萼. 斜菟檜 蜓フ渠煎 啻陛 澀ブ雖 晦渠ビ啊棻.澗顫歜檜棻 詩萼. 斜菟檜 蜓フ渠煎 啻陛 澀ブ雖 晦渠ビ啊棻.";
|
||||
holds = s;
|
||||
|
||||
int iPlayingTimeMS = cgi_S_GetSampleLength(sound);
|
||||
int iLengthInChars = strlen(s);//cgi_R_Font_StrLenChars(s); // strlen is also good for MBCS in this instance, since it's for timing
|
||||
if (iLengthInChars == 0)
|
||||
{
|
||||
iLengthInChars = 1;
|
||||
}
|
||||
cg.captionLetterTime = iPlayingTimeMS / iLengthInChars;
|
||||
|
||||
const char *psBestLineBreakSrcPos = s;
|
||||
const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes)
|
||||
while( *s )
|
||||
{
|
||||
psLastGood_s = s;
|
||||
|
||||
// read letter...
|
||||
//
|
||||
qboolean bIsTrailingPunctuation;
|
||||
int iAdvanceCount;
|
||||
unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(s, &iAdvanceCount, &bIsTrailingPunctuation);
|
||||
s += iAdvanceCount;
|
||||
|
||||
// concat onto string so far...
|
||||
//
|
||||
if (uiLetter == 32 && cg.captionText[i][0] == '\0')
|
||||
{
|
||||
holds++;
|
||||
continue; // unless it's a space at the start of a line, in which case ignore it.
|
||||
}
|
||||
|
||||
if (uiLetter > 255)
|
||||
{
|
||||
Q_strcat(cg.captionText[i],sizeof(cg.captionText[i]),va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcat(cg.captionText[i],sizeof(cg.captionText[i]),va("%c",uiLetter & 0xFF));
|
||||
}
|
||||
|
||||
if (uiLetter == '\n')
|
||||
{
|
||||
// explicit new line...
|
||||
//
|
||||
cg.captionText[i][ strlen(cg.captionText[i])-1 ] = '\0'; // kill the CR
|
||||
i++;
|
||||
holds = s;
|
||||
psBestLineBreakSrcPos = s;
|
||||
cg.scrollTextLines++;
|
||||
}
|
||||
else
|
||||
if ( cgi_R_Font_StrLenPixels(cg.captionText[i], cgs.media.qhFontMedium, fFontScale) >= lineWidth)
|
||||
{
|
||||
// reached screen edge, so cap off string at bytepos after last good position...
|
||||
//
|
||||
if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces())
|
||||
{
|
||||
// Special case, don't consider line breaking if you're on an asian punctuation char of
|
||||
// a language that doesn't use spaces...
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
if (psBestLineBreakSrcPos == holds)
|
||||
{
|
||||
// aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string,
|
||||
// since it doesn't have a single space or punctuation mark right the way across one line
|
||||
// of the screen. So far, this has only happened in testing when I hardwired a taiwanese
|
||||
// string into this function while the game was running in english (which should NEVER happen
|
||||
// normally). On the other hand I suppose it's entirely possible that some taiwanese string
|
||||
// might have no punctuation at all, so...
|
||||
//
|
||||
psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter
|
||||
}
|
||||
|
||||
cg.captionText[i][ psBestLineBreakSrcPos - holds ] = '\0';
|
||||
holds = s = psBestLineBreakSrcPos;
|
||||
i++;
|
||||
cg.scrollTextLines++;
|
||||
}
|
||||
}
|
||||
|
||||
// record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space)
|
||||
//
|
||||
if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces()))
|
||||
{
|
||||
psBestLineBreakSrcPos = s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// calc the length of time to hold each 2 lines of text on the screen.... presumably this works?
|
||||
//
|
||||
holdTime = strlen(cg.captionText[0]);
|
||||
if (cg.scrollTextLines > 1)
|
||||
{
|
||||
holdTime += strlen(cg.captionText[1]); // strlen is also good for MBCS in this instance, since it's for timing
|
||||
}
|
||||
cg.captionNextTextTime = cg.time + (/*JLF nudge it forward*/NUDGE_PERCENTAGE * holdTime * cg.captionLetterTime);
|
||||
|
||||
cg.scrollTextTime = 0; // No scrolling during captions
|
||||
|
||||
//Echo to console in dev mode
|
||||
if ( cg_developer.integer )
|
||||
{
|
||||
Com_Printf( "%s\n", cg.captionText[0] ); // ste: was [i], but surely sentence 0 is more useful than last?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CG_DrawCaptionText(void)
|
||||
{
|
||||
int i;
|
||||
int x, y, w;
|
||||
int holdTime;
|
||||
|
||||
if ( !cg.captionTextTime )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float fFontScale = cgi_Language_IsAsian() ? 0.8f : 1.0f;
|
||||
|
||||
if (cg_skippingcin.integer != 0)
|
||||
{
|
||||
cg.captionTextTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cg.captionNextTextTime < cg.time )
|
||||
{
|
||||
cg.captionTextCurrentLine += 2;
|
||||
|
||||
if (cg.captionTextCurrentLine >= cg.scrollTextLines)
|
||||
{
|
||||
cg.captionTextTime = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
holdTime = strlen(cg.captionText[cg.captionTextCurrentLine]);
|
||||
if (cg.scrollTextLines >= cg.captionTextCurrentLine)
|
||||
{
|
||||
// ( strlen is also good for MBCS in this instance, since it's for timing -ste)
|
||||
//
|
||||
holdTime += strlen(cg.captionText[cg.captionTextCurrentLine + 1]);
|
||||
}
|
||||
|
||||
cg.captionNextTextTime = cg.time + (holdTime * cg.captionLetterTime);//50);
|
||||
}
|
||||
}
|
||||
|
||||
// Give a color if one wasn't given
|
||||
if((textcolor_caption[0] == 0) && (textcolor_caption[1] == 0) &&
|
||||
(textcolor_caption[2] == 0) && (textcolor_caption[3] == 0))
|
||||
{
|
||||
Vector4Copy( colorTable[CT_WHITE], textcolor_caption );
|
||||
}
|
||||
|
||||
cgi_R_SetColor(textcolor_caption);
|
||||
|
||||
// Set Y of the first line (varies if only printing one line of text)
|
||||
// (this all works, please don't mess with it)
|
||||
const int fontHeight = (int) ((cgi_Language_IsAsian() ? 1.4f : 1.0f) * (float) cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, fFontScale));
|
||||
const bool bPrinting2Lines = !!(cg.captionText[ cg.captionTextCurrentLine+1 ][0]);
|
||||
y = cg.captionTextY - ( (float)fontHeight * (bPrinting2Lines ? 1 : 0.5f)); // captionTextY was a centered Y pos, not a top one
|
||||
y -= cgi_Language_IsAsian() ? 0 : 4;
|
||||
|
||||
for (i= cg.captionTextCurrentLine;i< cg.captionTextCurrentLine + 2;++i)
|
||||
{
|
||||
w = cgi_R_Font_StrLenPixels(cg.captionText[i], cgs.media.qhFontMedium, fFontScale);
|
||||
if (w)
|
||||
{
|
||||
x = (SCREEN_WIDTH-w) / 2;
|
||||
cgi_R_Font_DrawString(x, y, cg.captionText[i], textcolor_caption, cgs.media.qhFontMedium, -1, fFontScale);
|
||||
y += fontHeight;
|
||||
}
|
||||
}
|
||||
|
||||
cgi_R_SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
SCROLL TEXT
|
||||
|
||||
===============================================================================
|
||||
|
||||
CG_ScrollText - split text up into seperate lines
|
||||
|
||||
'str' arg is StripEd string reference, eg "CREDITS_RAVEN"
|
||||
|
||||
*/
|
||||
int giScrollTextPixelWidth = SCREEN_WIDTH;
|
||||
void CG_ScrollText( const char *str, int iPixelWidth )
|
||||
{
|
||||
const char *s,*holds;
|
||||
int i;//, len;//, numChars;
|
||||
|
||||
giScrollTextPixelWidth = iPixelWidth;
|
||||
|
||||
// first, ask the strlen of the final string...
|
||||
//
|
||||
i = cgi_SP_GetStringTextString( str, NULL, 0 );
|
||||
|
||||
//ensure we found a match
|
||||
if (!i)
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf("WARNING: CG_ScrollText given invalid text key :'%s'\n",str);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
//
|
||||
// malloc space to hold it...
|
||||
//
|
||||
char *psText = (char *) cgi_Z_Malloc( i+1, TAG_TEMP_WORKSPACE );
|
||||
//
|
||||
// now get the string...
|
||||
//
|
||||
i = cgi_SP_GetStringTextString( str, psText, i+1 );
|
||||
//ensure we found a match
|
||||
if (!i)
|
||||
{
|
||||
assert(0); // should never get here now, but wtf?
|
||||
cgi_Z_Free(psText);
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf("WARNING: CG_ScrollText given invalid text key :'%s'\n",str);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
cg.scrollTextTime = cg.time;
|
||||
cg.printTextY = SCREEN_HEIGHT;
|
||||
cg.scrollTextLines = 1;
|
||||
|
||||
s = psText;
|
||||
i = 0;
|
||||
holds = s;
|
||||
|
||||
const char *psBestLineBreakSrcPos = s;
|
||||
const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes)
|
||||
while( *s )
|
||||
{
|
||||
psLastGood_s = s;
|
||||
|
||||
// read letter...
|
||||
//
|
||||
qboolean bIsTrailingPunctuation;
|
||||
int iAdvanceCount;
|
||||
unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(s, &iAdvanceCount, &bIsTrailingPunctuation);
|
||||
s += iAdvanceCount;
|
||||
|
||||
// concat onto string so far...
|
||||
//
|
||||
if (uiLetter == 32 && cg.printText[i][0] == '\0')
|
||||
{
|
||||
holds++;
|
||||
continue; // unless it's a space at the start of a line, in which case ignore it.
|
||||
}
|
||||
|
||||
if (uiLetter > 255)
|
||||
{
|
||||
Q_strcat(cg.printText[i],sizeof(cg.printText[i]),va("%c%c",uiLetter >> 8, uiLetter & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcat(cg.printText[i],sizeof(cg.printText[i]),va("%c",uiLetter & 0xFF));
|
||||
}
|
||||
|
||||
// record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space)
|
||||
//
|
||||
if (bIsTrailingPunctuation || uiLetter == ' ')
|
||||
{
|
||||
psBestLineBreakSrcPos = s;
|
||||
}
|
||||
|
||||
if (uiLetter == '\n')
|
||||
{
|
||||
// explicit new line...
|
||||
//
|
||||
cg.printText[i][ strlen(cg.printText[i])-1 ] = '\0'; // kill the CR
|
||||
i++;
|
||||
assert (i < (sizeof(cg.printText)/sizeof(cg.printText[0])) );
|
||||
if (i >= (sizeof(cg.printText)/sizeof(cg.printText[0])) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
holds = s;
|
||||
cg.scrollTextLines++;
|
||||
}
|
||||
else
|
||||
if ( cgi_R_Font_StrLenPixels(cg.printText[i], cgs.media.qhFontMedium, 1.0f) >= iPixelWidth)
|
||||
{
|
||||
// reached screen edge, so cap off string at bytepos after last good position...
|
||||
//
|
||||
if (psBestLineBreakSrcPos == holds)
|
||||
{
|
||||
// aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string,
|
||||
// since it doesn't have a single space or punctuation mark right the way across one line
|
||||
// of the screen. So far, this has only happened in testing when I hardwired a taiwanese
|
||||
// string into this function while the game was running in english (which should NEVER happen
|
||||
// normally). On the other hand I suppose it's entirely possible that some taiwanese string
|
||||
// might have no punctuation at all, so...
|
||||
//
|
||||
psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter
|
||||
}
|
||||
|
||||
cg.printText[i][ psBestLineBreakSrcPos - holds ] = '\0';
|
||||
holds = s = psBestLineBreakSrcPos;
|
||||
i++;
|
||||
assert (i < (sizeof(cg.printText)/sizeof(cg.printText[0])) );
|
||||
cg.scrollTextLines++;
|
||||
}
|
||||
}
|
||||
|
||||
cg.captionTextTime = 0; // No captions during scrolling
|
||||
cgi_Z_Free(psText);
|
||||
}
|
||||
|
||||
|
||||
// draws using [textcolor_scroll]...
|
||||
//
|
||||
#define SCROLL_LPM (1/50.0) // 1 line per 50 ms
|
||||
void CG_DrawScrollText(void)
|
||||
{
|
||||
char *start;
|
||||
int i;
|
||||
int x,y;
|
||||
const int fontHeight = (int) (1.5f * (float) cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f)); // taiwanese & japanese need 1.5 fontheight spacing
|
||||
|
||||
if ( !cg.scrollTextTime )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cgi_R_SetColor( textcolor_scroll );
|
||||
|
||||
y = cg.printTextY - (cg.time - cg.scrollTextTime) * SCROLL_LPM;
|
||||
|
||||
// cgi_R_Font_DrawString(320, 200, va("Scrolltext printing @ %d",y), colorTable[CT_LTGOLD1], cgs.media.qhFontMedium, -1, 1.0f);
|
||||
|
||||
// See if text has finished scrolling off screen
|
||||
if ((y + cg.scrollTextLines * fontHeight) < 1)
|
||||
{
|
||||
cg.scrollTextTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0;i<cg.scrollTextLines;++i)
|
||||
{
|
||||
|
||||
// Is this line off top of screen?
|
||||
if ((y + ((i +1) * fontHeight)) < 1)
|
||||
{
|
||||
y += fontHeight;
|
||||
continue;
|
||||
}
|
||||
// or past bottom of screen?
|
||||
else if (y > SCREEN_HEIGHT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
start = cg.printText[i];
|
||||
|
||||
// w = cgi_R_Font_StrLenPixels(cg.printText[i], cgs.media.qhFontMedium, 1.0f);
|
||||
// if (w)
|
||||
{
|
||||
x = (SCREEN_WIDTH - giScrollTextPixelWidth) / 2;
|
||||
cgi_R_Font_DrawString(x,y, cg.printText[i], textcolor_scroll, cgs.media.qhFontMedium, -1, 1.0f);
|
||||
y += fontHeight;
|
||||
}
|
||||
}
|
||||
|
||||
cgi_R_SetColor( NULL );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
CENTER PRINTING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_CenterPrint
|
||||
|
||||
Called for important messages that should stay in the center of the screen
|
||||
for a few moments
|
||||
==============
|
||||
*/
|
||||
void CG_CenterPrint( const char *str, int y) {
|
||||
char *s;
|
||||
|
||||
// Find text to match the str given
|
||||
if (*str == '@')
|
||||
{
|
||||
int i;
|
||||
|
||||
i = cgi_SP_GetStringTextString( str+1, cg.centerPrint, sizeof(cg.centerPrint) );
|
||||
|
||||
if (!i)
|
||||
{
|
||||
Com_Printf (S_COLOR_RED"CG_CenterPrint: cannot find reference '%s' in StringPackage!\n",str);
|
||||
Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
|
||||
}
|
||||
|
||||
cg.centerPrintTime = cg.time;
|
||||
cg.centerPrintY = y;
|
||||
|
||||
// count the number of lines for centering
|
||||
cg.centerPrintLines = 1;
|
||||
s = cg.centerPrint;
|
||||
while( *s ) {
|
||||
if (*s == '\n')
|
||||
cg.centerPrintLines++;
|
||||
s++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_DrawCenterString
|
||||
===================
|
||||
*/
|
||||
void CG_DrawCenterString( void )
|
||||
{
|
||||
char *start;
|
||||
int l;
|
||||
int x, y, w;
|
||||
float *color;
|
||||
|
||||
if ( !cg.centerPrintTime ) {
|
||||
return;
|
||||
}
|
||||
|
||||
color = CG_FadeColor( cg.centerPrintTime, 1000 * 3 );
|
||||
if ( !color ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if((textcolor_center[0] == 0) && (textcolor_center[1] == 0) &&
|
||||
(textcolor_center[2] == 0) && (textcolor_center[3] == 0))
|
||||
{
|
||||
Vector4Copy( colorTable[CT_WHITE], textcolor_center );
|
||||
}
|
||||
|
||||
start = cg.centerPrint;
|
||||
|
||||
const int fontHeight = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f);
|
||||
y = cg.centerPrintY - (cg.centerPrintLines * fontHeight) / 2;
|
||||
|
||||
while ( 1 ) {
|
||||
char linebuffer[1024];
|
||||
|
||||
// this is kind of unpleasant when dealing with MBCS, but...
|
||||
//
|
||||
const char *psString = start;
|
||||
int iOutIndex = 0;
|
||||
for ( l = 0; l < sizeof(linebuffer)-1; l++ ) {
|
||||
int iAdvanceCount;
|
||||
unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(psString, &iAdvanceCount);
|
||||
psString += iAdvanceCount;
|
||||
if (!uiLetter || uiLetter == '\n'){
|
||||
break;
|
||||
}
|
||||
if (uiLetter > 255)
|
||||
{
|
||||
linebuffer[iOutIndex++] = uiLetter >> 8;
|
||||
linebuffer[iOutIndex++] = uiLetter & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
linebuffer[iOutIndex++] = uiLetter & 0xFF;
|
||||
}
|
||||
}
|
||||
linebuffer[iOutIndex++] = '\0';
|
||||
|
||||
w = cgi_R_Font_StrLenPixels(linebuffer, cgs.media.qhFontMedium, 1.0f);
|
||||
|
||||
x = ( SCREEN_WIDTH - w ) / 2;
|
||||
|
||||
cgi_R_Font_DrawString(x,y,linebuffer, textcolor_center, cgs.media.qhFontMedium, -1, 1.0f);
|
||||
|
||||
y += fontHeight;
|
||||
|
||||
while ( *start && ( *start != '\n' ) ) {
|
||||
start++;
|
||||
}
|
||||
if ( !*start ) {
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
}
|
||||
2249
code/cgame/cg_view.cpp
Normal file
2249
code/cgame/cg_view.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3164
code/cgame/cg_weapons.cpp
Normal file
3164
code/cgame/cg_weapons.cpp
Normal file
File diff suppressed because it is too large
Load Diff
10
code/cgame/common_headers.h
Normal file
10
code/cgame/common_headers.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// this line must stay at top so the whole PCH thing works...
|
||||
#include "cg_headers.h"
|
||||
|
||||
// I am a dummy header file that takes the place of the PCH files in SoF2. This is done so that we can easily
|
||||
// transport fx files amongst CHC, SoF2, and the effects editor...( If you are looking at this and have a better
|
||||
// idea, just let me know what the better solution is. )
|
||||
// The files can't be shared directly through Source Safe since the projects reside in different SS databases.
|
||||
//
|
||||
// - JD
|
||||
|
||||
82
code/cgame/strip_objectives.h
Normal file
82
code/cgame/strip_objectives.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef __strip_objectives_h
|
||||
#define __strip_objectives_h
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
|
||||
the objectives... duh...
|
||||
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
#define PACKAGE_OBJECTIVES 0x08
|
||||
|
||||
enum
|
||||
{
|
||||
OBJECTIVES_KEJIM_POST_OBJ1 = 0x0800,
|
||||
OBJECTIVES_KEJIM_POST_OBJ2 = 0x0801,
|
||||
OBJECTIVES_KEJIM_BASE_OBJ1 = 0x0802,
|
||||
OBJECTIVES_KEJIM_BASE_OBJ2 = 0x0803,
|
||||
OBJECTIVES_KEJIM_BASE_OBJ3 = 0x0804,
|
||||
OBJECTIVES_ARTUS_MINE_OBJ1 = 0x0805,
|
||||
OBJECTIVES_ARTUS_MINE_OBJ2 = 0x0806,
|
||||
OBJECTIVES_ARTUS_MINE_OBJ3 = 0x0807,
|
||||
OBJECTIVES_ARTUS_DETENTION_OBJ1 = 0x0808,
|
||||
OBJECTIVES_ARTUS_DETENTION_OBJ2 = 0x0809,
|
||||
OBJECTIVES_ARTUS_TOPSIDE_OBJ1 = 0x080a,
|
||||
OBJECTIVES_ARTUS_TOPSIDE_OBJ2 = 0x080b,
|
||||
OBJECTIVES_YAVIN_TEMPLE_OBJ1 = 0x080c,
|
||||
OBJECTIVES_YAVIN_TRIAL_OBJ1 = 0x080d,
|
||||
OBJECTIVES_YAVIN_TRIAL_OBJ2 = 0x080e,
|
||||
OBJECTIVES_NS_STREETS_OBJ1 = 0x080f,
|
||||
OBJECTIVES_NS_STREETS_OBJ2 = 0x0810,
|
||||
OBJECTIVES_NS_STREETS_OBJ3 = 0x0811,
|
||||
OBJECTIVES_NS_HIDEOUT_OBJ1 = 0x0812,
|
||||
OBJECTIVES_NS_HIDEOUT_OBJ2 = 0x0813,
|
||||
OBJECTIVES_NS_STARPAD_OBJ1 = 0x0814,
|
||||
OBJECTIVES_NS_STARPAD_OBJ2 = 0x0815,
|
||||
OBJECTIVES_NS_STARPAD_OBJ3 = 0x0816,
|
||||
OBJECTIVES_NS_STARPAD_OBJ4 = 0x0817,
|
||||
OBJECTIVES_NS_STARPAD_OBJ5 = 0x0818,
|
||||
OBJECTIVES_BESPIN_UNDERCITY_OBJ1 = 0x0819,
|
||||
OBJECTIVES_BESPIN_UNDERCITY_OBJ2 = 0x081a,
|
||||
OBJECTIVES_BESPIN_STREETS_OBJ1 = 0x081b,
|
||||
OBJECTIVES_BESPIN_STREETS_OBJ2 = 0x081c,
|
||||
OBJECTIVES_BESPIN_PLATFORM_OBJ1 = 0x081d,
|
||||
OBJECTIVES_BESPIN_PLATFORM_OBJ2 = 0x081e,
|
||||
OBJECTIVES_CAIRN_BAY_OBJ1 = 0x081f,
|
||||
OBJECTIVES_CAIRN_BAY_OBJ2 = 0x0820,
|
||||
OBJECTIVES_CAIRN_ASSEMBLY_OBJ1 = 0x0821,
|
||||
OBJECTIVES_CAIRN_REACTOR_OBJ1 = 0x0822,
|
||||
OBJECTIVES_CAIRN_REACTOR_OBJ2 = 0x0823,
|
||||
OBJECTIVES_CAIRN_DOCK1_OBJ1 = 0x0824,
|
||||
OBJECTIVES_CAIRN_DOCK1_OBJ2 = 0x0825,
|
||||
OBJECTIVES_DOOM_COMM_OBJ1 = 0x0826,
|
||||
OBJECTIVES_DOOM_COMM_OBJ2 = 0x0827,
|
||||
OBJECTIVES_DOOM_COMM_OBJ3 = 0x0828,
|
||||
OBJECTIVES_DOOM_DETENTION_OBJ1 = 0x0829,
|
||||
OBJECTIVES_DOOM_DETENTION_OBJ2 = 0x082a,
|
||||
OBJECTIVES_DOOM_SHIELDS_OBJ1 = 0x082b,
|
||||
OBJECTIVES_DOOM_SHIELDS_OBJ2 = 0x082c,
|
||||
OBJECTIVES_YAVIN_SWAMP_OBJ1 = 0x082d,
|
||||
OBJECTIVES_YAVIN_SWAMP_OBJ2 = 0x082e,
|
||||
OBJECTIVES_YAVIN_CANYON_OBJ1 = 0x082f,
|
||||
OBJECTIVES_YAVIN_CANYON_OBJ2 = 0x0830,
|
||||
OBJECTIVES_YAVIN_COURTYARD_OBJ1 = 0x0831,
|
||||
OBJECTIVES_YAVIN_COURTYARD_OBJ2 = 0x0832,
|
||||
OBJECTIVES_YAVIN_FINAL_OBJ1 = 0x0833,
|
||||
OBJECTIVES_KEJIM_POST_OBJ3 = 0x0834,
|
||||
OBJECTIVES_KEJIM_POST_OBJ4 = 0x0835,
|
||||
OBJECTIVES_KEJIM_POST_OBJ5 = 0x0836,
|
||||
OBJECTIVES_ARTUS_DETENTION_OBJ3 = 0x0837,
|
||||
OBJECTIVES_DOOM_COMM_OBJ4 = 0x0838,
|
||||
OBJECTIVES_DOOM_SHIELDS_OBJ3 = 0x0839,
|
||||
OBJECTIVES_DEMO_OBJ1 = 0x083a,
|
||||
OBJECTIVES_DEMO_OBJ2 = 0x083b,
|
||||
OBJECTIVES_DEMO_OBJ3 = 0x083c,
|
||||
OBJECTIVES_DEMO_OBJ4 = 0x083d
|
||||
};
|
||||
|
||||
|
||||
#endif // __strip_objectives_h
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user