mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
Moved some around, more renames
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
#ifndef __OPENEQ_THREED__
|
||||
#define __OPENEQ_THREED__
|
||||
|
||||
#include "3d_base.hpp"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct ObjectGroupEntry
|
||||
{
|
||||
ObjectGroupEntry()
|
||||
{
|
||||
IncludeInMap = true;
|
||||
}
|
||||
|
||||
bool FromTOG;
|
||||
bool IncludeInMap;
|
||||
float TileX, TileY, TileZ;
|
||||
float x, y, z;
|
||||
float RotX, RotY, RotZ;
|
||||
float ScaleX, ScaleY, ScaleZ;
|
||||
list<int> SubObjects;
|
||||
};
|
||||
|
||||
class Octree_Node;
|
||||
|
||||
class Bone {
|
||||
public:
|
||||
char *name;
|
||||
|
||||
int bone1, bone2;
|
||||
|
||||
float x, y, z;
|
||||
float e[4];
|
||||
float scale[3];
|
||||
|
||||
int vert_count;
|
||||
int *verts;
|
||||
};
|
||||
|
||||
class Zone_Model {
|
||||
public:
|
||||
Zone_Model() {}
|
||||
~Zone_Model() {}
|
||||
|
||||
Vertex **verts;
|
||||
Polygon **polys;
|
||||
Octree_Node *octree;
|
||||
Texture **tex;
|
||||
|
||||
int vert_count, poly_count, tex_count;
|
||||
};
|
||||
|
||||
class MobModel {
|
||||
public:
|
||||
MobModel() {}
|
||||
~MobModel() {}
|
||||
|
||||
Vertex **verts;
|
||||
Polygon **polys;
|
||||
Texture **tex;
|
||||
|
||||
int vert_count, poly_count, tex_count;
|
||||
|
||||
Bone *bones;
|
||||
|
||||
int bone_count;
|
||||
};
|
||||
|
||||
class Content_3D {
|
||||
public:
|
||||
Content_3D() { this->mob_model_count = 0; this->mob_count = 0; }
|
||||
~Content_3D() {}
|
||||
|
||||
Model *GetModel(char *model_name);
|
||||
|
||||
void GenerateOctree();
|
||||
|
||||
void MergeTextures();
|
||||
void MergeTexturesLazy();
|
||||
|
||||
Zone_Model *zone_model;
|
||||
|
||||
Model **models;
|
||||
Placeable **placeable;
|
||||
|
||||
int model_count, plac_count; // Count of placeable object models and count of instances
|
||||
int ObjectGroupCount;
|
||||
|
||||
MobModel **mob_models;
|
||||
Placeable **mob_locs;
|
||||
int mob_model_count, mob_count;
|
||||
|
||||
vector<ObjectGroupEntry> ObjectGroups;
|
||||
vector<string> ModelNames;
|
||||
vector<Placeable> PlaceableList;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifndef __OPENEQ_THREED_BASE__
|
||||
#define __OPENEQ_THREED_BASE__
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
|
||||
#include "archive.hpp"
|
||||
|
||||
#ifdef GLMODELVIEWER
|
||||
#include <gl\gl.h> // Header File For The OpenGL32 Library
|
||||
#endif
|
||||
|
||||
struct Light {
|
||||
float x, y, z;
|
||||
float r, g, b;
|
||||
float rad;
|
||||
} typedef Light;
|
||||
|
||||
struct Vertex {
|
||||
float x, y, z;
|
||||
float i, j, k;
|
||||
float u, v;
|
||||
|
||||
// int bone;
|
||||
|
||||
Vertex()
|
||||
{
|
||||
x = y = z = i = j = k = u = v = 0.0f;
|
||||
};
|
||||
|
||||
Vertex(float ix, float iy, float iz)
|
||||
{
|
||||
x = ix;
|
||||
y = iy;
|
||||
z = iz;
|
||||
}
|
||||
} typedef Vertex;
|
||||
|
||||
|
||||
struct Polygon {
|
||||
int flags;
|
||||
|
||||
int v1, v2, v3;
|
||||
|
||||
int tex;
|
||||
} typedef Polygon;
|
||||
|
||||
|
||||
struct Texture {
|
||||
Archive *archive;
|
||||
char frame_count;
|
||||
char current_frame;
|
||||
#ifdef GLMODELVIEWER
|
||||
GLuint *tex;
|
||||
#else
|
||||
int32 *tex;
|
||||
#endif
|
||||
char **filenames;
|
||||
|
||||
char flags;
|
||||
} typedef Texture;
|
||||
|
||||
class Model {
|
||||
public:
|
||||
Model() { IncludeInMap = false; verts = nullptr; vert_count = 0; polys = nullptr; poly_count = 0; tex = nullptr; tex_count = 0; name = nullptr; }
|
||||
~Model() {}
|
||||
|
||||
Vertex **verts;
|
||||
Polygon **polys;
|
||||
Texture **tex;
|
||||
|
||||
int vert_count, poly_count, tex_count;
|
||||
|
||||
char *name;
|
||||
bool IncludeInMap; // Include in EQEmu .map file
|
||||
};
|
||||
|
||||
|
||||
class Placeable {
|
||||
public:
|
||||
Placeable() {}
|
||||
|
||||
Placeable(int iModel, float ix, float iy, float iz, float irx, float iry, float irz, float iScale0, float iScale1, float iScale2)
|
||||
{
|
||||
model = iModel;
|
||||
x = ix;
|
||||
y = iy;
|
||||
z = iz;
|
||||
rx = irx;
|
||||
ry = iry;
|
||||
rz = irz;
|
||||
scale[0] = iScale0;
|
||||
scale[1] = iScale1;
|
||||
scale[2] = iScale2;
|
||||
}
|
||||
|
||||
float x, y, z;
|
||||
float rx, ry, rz;
|
||||
float scale[3];
|
||||
|
||||
int model;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,548 @@
|
||||
|
||||
// Quick and dirty EQ model viewer for Windows, using OpenGL
|
||||
//
|
||||
// Put together by Derision from EQEmu forums using basic Windows OpenGL framework from NeHe tutorials @ gamedev.net
|
||||
// and S3D and EQG file loaders from OpenEQ (modified a bit to fix some bugs and support newer EQG formats).
|
||||
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#define Polygon Polygon_win32
|
||||
#include <windows.h>
|
||||
#undef Polygon
|
||||
#endif
|
||||
#include <gl\gl.h>
|
||||
#include <gl\glu.h>
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include "types.h"
|
||||
#include "wld.hpp"
|
||||
#include "archive.hpp"
|
||||
#include "pfs.hpp"
|
||||
#include "file_loader.hpp"
|
||||
#include "zon.hpp"
|
||||
#include "zonv4.hpp"
|
||||
#include "ter.hpp"
|
||||
|
||||
|
||||
typedef struct _vertex{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
}VERTEX;
|
||||
|
||||
void DrawEQModel(FileLoader *fileloader, int modnum);
|
||||
FileLoader *mfileloader;
|
||||
bool ProcessZoneFile(const char *shortname);
|
||||
enum EQFileType { S3D, EQG, UNKNOWN };
|
||||
|
||||
HDC hDC=NULL;
|
||||
HGLRC hRC=NULL;
|
||||
HWND hWnd=NULL;
|
||||
HINSTANCE hInstance;
|
||||
|
||||
bool keys[256];
|
||||
char ch;
|
||||
bool active=true;
|
||||
GLuint base;
|
||||
|
||||
int modelnum = 1; // The Number of the model we are currently displaying.
|
||||
float angle = 0; // used to rotate the model. Updated by a timer
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
|
||||
|
||||
GLvoid BuildFont(GLvoid)
|
||||
{
|
||||
HFONT font;
|
||||
HFONT oldfont;
|
||||
|
||||
base = glGenLists(96);
|
||||
|
||||
font = CreateFont(-24, 0, 0, 0, FW_BOLD, false, false, false, ANSI_CHARSET,
|
||||
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
|
||||
FF_DONTCARE|DEFAULT_PITCH, "Courier New");
|
||||
|
||||
oldfont = (HFONT)SelectObject(hDC, font);
|
||||
wglUseFontBitmaps(hDC, 32, 96, base);
|
||||
SelectObject(hDC, oldfont);
|
||||
DeleteObject(font);
|
||||
}
|
||||
|
||||
GLvoid KillFont(GLvoid)
|
||||
{
|
||||
glDeleteLists(base, 96);
|
||||
}
|
||||
|
||||
GLvoid glPrint(const char *fmt, ...)
|
||||
{
|
||||
char text[256];
|
||||
va_list ap;
|
||||
|
||||
if (fmt == NULL) return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(text, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
glPushAttrib(GL_LIST_BIT);
|
||||
glListBase(base - 32);
|
||||
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
|
||||
{
|
||||
if (height==0)height=1;
|
||||
|
||||
glViewport(0,0,width,height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(60.0f,(GLfloat)width/(GLfloat)height,0.1f,12000.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
int InitGL(GLvoid)
|
||||
{
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
|
||||
glClearDepth(1.0f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
||||
BuildFont();
|
||||
return true;
|
||||
}
|
||||
|
||||
int DrawGLScene(char *ZoneFileName)
|
||||
{
|
||||
char textBuffer[100];
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
|
||||
if(mfileloader->model_data.models[modelnum])
|
||||
DrawEQModel(mfileloader, modelnum);
|
||||
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0f,0.0f,-1.2f);
|
||||
glColor3f(100.0f,0.0f,0.0f);
|
||||
glRasterPos2f(-1.15f,0.56f);
|
||||
|
||||
if(mfileloader->model_data.models[modelnum])
|
||||
if(mfileloader->model_data.models[modelnum]->name)
|
||||
sprintf(textBuffer," %s: Model Number %4d. Name %s", ZoneFileName, modelnum, mfileloader->model_data.models[modelnum]->name);
|
||||
else
|
||||
sprintf(textBuffer," %s: Model Number %4d. Not Viewable (load failed).", ZoneFileName, modelnum);
|
||||
else
|
||||
sprintf(textBuffer," %s: Model Number %4d. Not Viewable (probably zone mesh).", ZoneFileName, modelnum);
|
||||
|
||||
glPrint(textBuffer);
|
||||
sprintf(textBuffer," Use the + and - keys to cycle through models.");
|
||||
glRasterPos2f(-1.15f,0.50f);
|
||||
glPrint(textBuffer);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLvoid KillGLWindow(GLvoid) {
|
||||
if (hRC) {
|
||||
if (!wglMakeCurrent(NULL,NULL)) {
|
||||
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
if (!wglDeleteContext(hRC)) {
|
||||
MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
hRC=NULL;
|
||||
}
|
||||
|
||||
if (hDC && !ReleaseDC(hWnd,hDC)) {
|
||||
MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
|
||||
hDC=NULL;
|
||||
}
|
||||
|
||||
if (hWnd && !DestroyWindow(hWnd)) {
|
||||
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
|
||||
hWnd=NULL;
|
||||
}
|
||||
|
||||
if (!UnregisterClass("OpenGL",hInstance)) {
|
||||
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
|
||||
hInstance=NULL;
|
||||
}
|
||||
KillFont();
|
||||
}
|
||||
|
||||
|
||||
BOOL CreateGLWindow(char* title, int width, int height, int bits) {
|
||||
GLuint PixelFormat;
|
||||
WNDCLASS wc;
|
||||
DWORD dwExStyle;
|
||||
DWORD dwStyle;
|
||||
RECT WindowRect;
|
||||
WindowRect.left=(long)0;
|
||||
WindowRect.right=(long)width;
|
||||
WindowRect.top=(long)0;
|
||||
WindowRect.bottom=(long)height;
|
||||
|
||||
hInstance = GetModuleHandle(NULL);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wc.lpfnWndProc = (WNDPROC) WndProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "OpenGL";
|
||||
|
||||
if (!RegisterClass(&wc)) {
|
||||
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||
dwStyle=WS_OVERLAPPEDWINDOW;
|
||||
|
||||
AdjustWindowRectEx(&WindowRect, dwStyle, false, dwExStyle);
|
||||
|
||||
if (!(hWnd=CreateWindowEx(dwExStyle, "OpenGL", title, dwStyle|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
|
||||
0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
|
||||
NULL, NULL, hInstance, NULL))) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
static PIXELFORMATDESCRIPTOR pfd= {
|
||||
sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,
|
||||
PFD_TYPE_RGBA, bits, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
if (!(hDC=GetDC(hWnd))) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(hRC=wglCreateContext(hDC))) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!wglMakeCurrent(hDC,hRC)) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
ShowWindow(hWnd,SW_SHOW);
|
||||
SetForegroundWindow(hWnd);
|
||||
SetFocus(hWnd);
|
||||
ReSizeGLScene(width, height);
|
||||
|
||||
if (!InitGL()) {
|
||||
KillGLWindow();
|
||||
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetTimer(hWnd, 1, 50, (TIMERPROC) NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_ACTIVATE:
|
||||
if (!HIWORD(wParam)) active=true;
|
||||
else
|
||||
active=false;
|
||||
|
||||
return 0;
|
||||
case WM_SYSCOMMAND:
|
||||
switch (wParam) {
|
||||
case SC_SCREENSAVE:
|
||||
case SC_MONITORPOWER:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case WM_KEYDOWN:
|
||||
keys[wParam] = true;
|
||||
return 0;
|
||||
case WM_CHAR:
|
||||
ch = wParam;
|
||||
return 0;
|
||||
case WM_KEYUP:
|
||||
keys[wParam] = false;
|
||||
return 0;
|
||||
case WM_SIZE:
|
||||
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
|
||||
return 0;
|
||||
case WM_TIMER:
|
||||
angle = angle + 1;
|
||||
if(angle>359) angle = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
void TranslateVertex(VERTEX &v, float XOffset, float YOffset, float ZOffset) {
|
||||
|
||||
v.x = v.x + XOffset;
|
||||
v.y = v.y + YOffset;
|
||||
v.z = v.z + ZOffset;
|
||||
}
|
||||
|
||||
void ScaleVertex(VERTEX &v, float XScale, float YScale, float ZScale) {
|
||||
|
||||
v.x = v.x * XScale;
|
||||
v.y = v.y * YScale;
|
||||
v.z = v.z * ZScale;
|
||||
}
|
||||
|
||||
|
||||
void DrawEQModel(FileLoader *fileloader, int modnum) {
|
||||
|
||||
Polygon *poly;
|
||||
Vertex *verts[3];
|
||||
VERTEX v1, v2, v3;
|
||||
|
||||
float maxDimension = 0, minx = 999999, miny = 999999, minz = 999999, maxx = -999999, maxy=-999999, maxz=-999999;
|
||||
Model *model = fileloader->model_data.models[modnum];
|
||||
|
||||
for(int i = 0; i < model->poly_count; ++i) {
|
||||
poly = model->polys[i];
|
||||
|
||||
verts[0] = model->verts[poly->v1];
|
||||
verts[1] = model->verts[poly->v2];
|
||||
verts[2] = model->verts[poly->v3];
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
if(verts[j]->x > maxDimension) maxDimension = verts[j]->x;
|
||||
if(verts[j]->y > maxDimension) maxDimension = verts[j]->y;
|
||||
if(verts[j]->z > maxDimension) maxDimension = verts[j]->z;
|
||||
|
||||
if(verts[j]->x < minx) minx = verts[j]->x;
|
||||
if(verts[j]->y < miny) miny = verts[j]->y;
|
||||
if(verts[j]->z < minz) minz = verts[j]->z;
|
||||
|
||||
if(verts[j]->x > maxx) maxx = verts[j]->x;
|
||||
if(verts[j]->y > maxy) maxy = verts[j]->y;
|
||||
if(verts[j]->z > maxz) maxz = verts[j]->z;
|
||||
}
|
||||
}
|
||||
|
||||
maxDimension = 0;
|
||||
if(maxx-minx>maxDimension) maxDimension = maxx-minx;
|
||||
if(maxy-miny>maxDimension) maxDimension = maxy-miny;
|
||||
if(maxz-minz>maxDimension) maxDimension = maxz-minz;
|
||||
|
||||
// Hack for very small models (e.g. spoons)
|
||||
if(maxDimension>1)
|
||||
glTranslatef(-1.5f,0.0f,-(maxDimension*2));
|
||||
else
|
||||
glTranslatef(-1.5f,0.0f,-10);
|
||||
|
||||
// angle is updated by a timer every 50ms.
|
||||
glRotatef(angle, 1, 0, 0);
|
||||
glRotatef(angle, 0, 1, 0);
|
||||
glRotatef(angle, 0, 0, 1);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
for(int i = 0; i < model->poly_count; ++i) {
|
||||
poly = model->polys[i];
|
||||
|
||||
verts[0] = model->verts[poly->v1];
|
||||
verts[1] = model->verts[poly->v2];
|
||||
verts[2] = model->verts[poly->v3];
|
||||
|
||||
v1.x = verts[0]->x; v1.y = verts[0]->y; v1.z = verts[0]->z;
|
||||
v2.x = verts[1]->x; v2.y = verts[1]->y; v2.z = verts[1]->z;
|
||||
v3.x = verts[2]->x; v3.y = verts[2]->y; v3.z = verts[2]->z;
|
||||
|
||||
// The aim of this is to centre the model in the window
|
||||
|
||||
TranslateVertex(v1, -(minx + (maxx-minx)/2), -(miny + (maxy-miny)/2), -(minz + (maxz-minz)/2));
|
||||
TranslateVertex(v2, -(minx + (maxx-minx)/2), -(miny + (maxy-miny)/2), -(minz + (maxz-minz)/2));
|
||||
TranslateVertex(v3, -(minx + (maxx-minx)/2), -(miny + (maxy-miny)/2), -(minz + (maxz-minz)/2));
|
||||
|
||||
// For very small models, magnify them
|
||||
if(maxDimension<=1) {
|
||||
ScaleVertex(v1, 10, 10, 10);
|
||||
ScaleVertex(v2, 10, 10, 10);
|
||||
ScaleVertex(v3, 10, 10, 10);
|
||||
}
|
||||
|
||||
// Assign a kind of random colour to each polygon
|
||||
|
||||
//glColor3b((i%50)+50,(i*5)%200,(i*10)%200);
|
||||
float col = (float)(100 + ((i*10) % 150)) /250 * 1.0f;
|
||||
glColor3f(col, col, col);
|
||||
|
||||
glVertex3f(v1.x, v1.z, v1.y);
|
||||
glVertex3f(v2.x, v2.z, v2.y);
|
||||
glVertex3f(v3.x, v3.z, v3.y);
|
||||
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
bool ProcessZoneFile(const char *shortname) {
|
||||
|
||||
char bufs[96];
|
||||
Archive *archive;
|
||||
|
||||
Zone_Model *zm;
|
||||
FILE *fff;
|
||||
EQFileType FileType = UNKNOWN;
|
||||
GLuint *textures;
|
||||
|
||||
sprintf(bufs, "%s.s3d", shortname);
|
||||
|
||||
archive = new PFSLoader();
|
||||
fff = fopen(bufs, "rb");
|
||||
if(fff != NULL)
|
||||
FileType = S3D;
|
||||
else {
|
||||
sprintf(bufs, "%s.eqg", shortname);
|
||||
fff = fopen(bufs, "rb");
|
||||
if(fff != NULL)
|
||||
FileType = EQG;
|
||||
}
|
||||
|
||||
if(FileType == UNKNOWN) {
|
||||
MessageBox(NULL,"Unable to locate specified zone either as EQG or S3D","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(archive->Open(fff) == 0) {
|
||||
MessageBox(NULL,"Unable to open container file","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
switch(FileType) {
|
||||
case S3D:
|
||||
mfileloader = new WLDLoader();
|
||||
if(mfileloader->Open(NULL, (char *) shortname, archive) == 0) {
|
||||
|
||||
MessageBox(NULL,"Error reading WLD from container file","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return(false);
|
||||
}
|
||||
break;
|
||||
case EQG:
|
||||
mfileloader = new ZonLoader();
|
||||
if(mfileloader->Open(NULL, (char *) shortname, archive) == 0) {
|
||||
delete mfileloader;
|
||||
mfileloader = new Zonv4Loader();
|
||||
if(mfileloader->Open(NULL, (char *) shortname, archive) == 0) {
|
||||
MessageBox(NULL,"Error reading ZON/TER from container file","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
if(mfileloader->model_data.model_count==0) {
|
||||
MessageBox(NULL,"No models found. For S3D, probably could not locate _obj.s3d file","ERROR",MB_OK|MB_ICONEXCLAMATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
zm = mfileloader->model_data.zone_model;
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
MSG msg;
|
||||
BOOL done=false;
|
||||
FILE *fp;
|
||||
|
||||
for(int i=0;i<256;i++)
|
||||
keys[i] = false;
|
||||
|
||||
|
||||
char* buf = (char *) new char[strlen(lpCmdLine) + 1] ;
|
||||
char *pTmp = buf;
|
||||
|
||||
if(!strlen(lpCmdLine)) {
|
||||
MessageBox(NULL,"Specify the shortname of the zone (without the S3D or EQG extension) on the command line.",
|
||||
"ERROR",MB_OK | MB_ICONINFORMATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strcpy(buf,lpCmdLine);
|
||||
|
||||
if(!ProcessZoneFile(buf)) return 0;
|
||||
|
||||
if (!CreateGLWindow("EQ Model Viewer",1280,768,16))
|
||||
return 0;
|
||||
|
||||
while(!done) {
|
||||
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
|
||||
if (msg.message==WM_QUIT)
|
||||
done=true;
|
||||
else {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((active && !DrawGLScene(buf)) || keys[VK_ESCAPE])
|
||||
done=true;
|
||||
else
|
||||
SwapBuffers(hDC);
|
||||
|
||||
// Use + and - to cycle through the models
|
||||
|
||||
if (toupper(ch)=='+') {
|
||||
if(modelnum+1 < mfileloader->model_data.model_count)
|
||||
modelnum++;
|
||||
else
|
||||
modelnum=0;
|
||||
angle = 0;
|
||||
}
|
||||
if (toupper(ch)=='-') {
|
||||
if(modelnum>0)
|
||||
modelnum--;
|
||||
else
|
||||
modelnum = mfileloader->model_data.model_count - 1;
|
||||
|
||||
angle = 0;
|
||||
}
|
||||
ch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
KillGLWindow();
|
||||
return (msg.wParam);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource.h"
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
Azone2, awater, listobj, glModelViewer
|
||||
|
||||
azone2 creates .map files for EQEmu, used in LOS and BestZ, etc.
|
||||
|
||||
.S3D and .EQG zone files found with the Titanium EQ distribution are
|
||||
supported.
|
||||
|
||||
to use all of these utilities, copy them to a directory containing your .S3D and .EQG
|
||||
files.
|
||||
|
||||
IMPORTANT NOTE:
|
||||
|
||||
Older EQGs had the .ZON file within the .EQG container. Newer EQGs, e.g.
|
||||
tutorialb, dreadspire, have the .ZON file as a separate file in your EQ directory.
|
||||
To include placeable objects for these, YOU MUST have both the .EQG and .ZON file
|
||||
in the same directory as azone2.
|
||||
|
||||
To generate a map file, specifit the shortname of the zone (without the extension).
|
||||
|
||||
e.g.
|
||||
|
||||
./azone2 tox
|
||||
./azone2 anguish
|
||||
|
||||
Copy the resultant .map file to the Maps directory on your server.
|
||||
|
||||
|
||||
20/06/08 Derision:
|
||||
To include placeable objects, use the listobj program to find the models you want,
|
||||
e.g. ./listobj tox
|
||||
|
||||
LISTOBJ: List Placeable Objects in .S3D or .EQG zone files.
|
||||
Placeable Object 0 @ ( -420.42, 2443.43, -50.30 uses model 27 TIKI_DMSPRITEDEF
|
||||
Placeable Object 1 @ ( -482.54, 2446.06, -45.13 uses model 27 TIKI_DMSPRITEDEF
|
||||
Placeable Object 2 @ ( -439.99, 2603.35, -29.50 uses model 28 TORCH1_DMSPRITEDEF
|
||||
Placeable Object 3 @ ( 158.28, 1094.74, -50.40 uses model 27 TIKI_DMSPRITEDEF
|
||||
Placeable Object 4 @ ( 137.83, 1074.79, -49.91 uses model 17 HUT4_DMSPRITEDEF
|
||||
Placeable Object 5 @ ( 150.64, 1205.48, -48.46 uses model 27 TIKI_DMSPRITEDEF
|
||||
Placeable Object 6 @ ( 128.19, 1204.95, -48.37 uses model 27 TIKI_DMSPRITEDEF
|
||||
Placeable Object 7 @ ( 139.57, 1153.50, -53.74 uses model 20 KDOCK_DMSPRITEDEF
|
||||
Placeable Object 8 @ ( 1139.42, -837.60, -55.38 uses model 5 ERBRAZIER_DMSPRITEDEF
|
||||
|
||||
^
|
||||
|
|
||||
|
|
||||
This is the model number -------------|
|
||||
|
||||
If you want azone to include all occurrences of HUT4_DMSPRITEDF (model 17) and KDOCK_DMSPRITEDF (20),
|
||||
you would add a line to azone.ini as follows:
|
||||
|
||||
# Include huts, houses and bridge from tox
|
||||
tox.s3d,17,20
|
||||
# Include two bridges from Tutorialb
|
||||
tutorialb.eqg,17,47
|
||||
# Include a couple of towers in Anguish
|
||||
anguish.eqg,7,8
|
||||
|
||||
Note that as you can only specify a model number, it is not possible to only have selected occurrences
|
||||
of that model included.
|
||||
|
||||
Lines in azone.ini beginning with a # are ignored.
|
||||
|
||||
TO INCLUDE PLACEABLE MODELS FOR .S3D ZONES, THE _OBJ.S3D FILE FOR THAT ZONE MUST ALSO BE PRESENT IN THE
|
||||
SAME DIRECTORY.
|
||||
|
||||
You can also use glmodelviewer (Windows only) to display the models in a zone to find the ones you want
|
||||
to include. To run it, from a command prompt, e.g.
|
||||
|
||||
glmodelviewer wallofslaughter
|
||||
|
||||
Finally, awater generates .wtr files containing details of the water, lava, PVP etc areas in an S3D zone.
|
||||
Usage example:
|
||||
|
||||
./awater fieldofbone
|
||||
|
||||
The windows solution and project files provided were produced with Visual C++ 2008 and as configured,
|
||||
require a statically linkable zlib.lib.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef __OPENEQ_ARCHIVE_API__
|
||||
#define __OPENEQ_ARCHIVE_API__
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class Archive {
|
||||
public:
|
||||
Archive() {}
|
||||
virtual ~Archive() {}
|
||||
|
||||
virtual int Open(FILE *fp) = 0;
|
||||
virtual int Close() = 0;
|
||||
|
||||
virtual int GetFile(char *name, uchar **buf, int *len) = 0;
|
||||
virtual const char *FindExtension(const char *ext) = 0;
|
||||
|
||||
char **filenames;
|
||||
int count;
|
||||
|
||||
protected:
|
||||
uchar *buffer;
|
||||
int buf_len;
|
||||
|
||||
int status;
|
||||
|
||||
uint32 *files;
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
|
||||
AWater: Generate 'Water Maps' for EQEmu. 'Water Maps' is a misnomer as,
|
||||
while originally intended to produce a map of water regions from .S3D
|
||||
zone files, it also includes details of lava, PVP and other 'special'
|
||||
areas.
|
||||
|
||||
Based on Azone (Father NitWit) and OpenEQ (Daeken et al). Original
|
||||
copyright notice from Azone follows:
|
||||
|
||||
Father Nitwit's Zone to map conversion program.
|
||||
Copyright (C) 2004 Father Nitwit (eqemu@8ass.com)
|
||||
|
||||
This thing uses code from freaku, so whatever license that comes under
|
||||
is relavent, if you care.
|
||||
|
||||
the rest of it is GPL, even though I hate the GPL.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef short SHORT;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
//#include "EQWldData.h"
|
||||
#include "awater.h"
|
||||
#include "types.h"
|
||||
#include "s3d.h"
|
||||
#include "wld.hpp"
|
||||
|
||||
#include "archive.hpp"
|
||||
#include "pfs.hpp"
|
||||
|
||||
#include "file_loader.hpp"
|
||||
#include "zon.hpp"
|
||||
#include "ter.hpp"
|
||||
|
||||
|
||||
//this un-commented works with my map.cpp code correctly.
|
||||
//with both of my inverts there commented.
|
||||
#define INVERSEXY 1
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
//#define SPLIT_DEBUG
|
||||
|
||||
|
||||
bool BuildWaterMap(const char *shortname, long DefaultRegionType);
|
||||
void PrintBSP(BSP_Node *tree, long node_number);
|
||||
long BSPFindRegion(BSP_Node *tree, long node_number, long region);
|
||||
long BSPFindNode(BSP_Node *tree, long node_number, float x, float y, float z);
|
||||
long BSPMarkRegion(BSP_Node *tree, long node_number, long region, int region_type);
|
||||
long BSPCountNodes(BSP_Node *tree, long node_number);
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
long DefaultRegionType=RegionTypeWater;
|
||||
|
||||
if((argc < 2) ||
|
||||
(argc > 3) ||
|
||||
#ifndef WIN32
|
||||
((argc == 3)&&(strcasecmp(argv[1],"-dl")))) {
|
||||
#else
|
||||
((argc == 3)&&(_stricmp(argv[1],"-dl")))) {
|
||||
#endif
|
||||
|
||||
printf("Usage: %s [-dl] (zone short name) to generate a water/lava map\n\n", argv[0]);
|
||||
printf(" -dl = mark special regions as lava if not tagged in .WLD\n");
|
||||
printf("\nIf -dl is omitted, untagged special regions will be marked as water\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
char bufm[250];
|
||||
|
||||
if(argc==3)
|
||||
DefaultRegionType=RegionTypeLava;
|
||||
sprintf(bufm, "%s.wtr", argv[argc-1]);
|
||||
if(!BuildWaterMap(argv[argc-1],DefaultRegionType))
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool BuildWaterMap(const char *shortname, long DefaultRegionType) {
|
||||
|
||||
char bufs[96];
|
||||
Archive *archive;
|
||||
WLDLoader *fileloader;
|
||||
long WaterOrLavaCount = 0;
|
||||
|
||||
//TODO: clean up a LOT of memory that the freaku code does not
|
||||
|
||||
|
||||
sprintf(bufs, "%s.s3d", shortname);
|
||||
|
||||
archive = new PFSLoader();
|
||||
|
||||
FILE *s3df = fopen(bufs, "rb");
|
||||
if(s3df == nullptr) {
|
||||
// One day we may try EQG, but not today.
|
||||
printf("Unable to open s3d file '%s'.\n", bufs);
|
||||
return(false);
|
||||
}
|
||||
if(archive->Open(s3df) == 0) {
|
||||
printf("Unable to open s3d file '%s'.\n", bufs);
|
||||
return(false);
|
||||
}
|
||||
printf("Loading %s...\n", bufs);
|
||||
|
||||
fileloader = new WLDLoader();
|
||||
|
||||
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
|
||||
printf("Error reading WLD from %s\n", bufs);
|
||||
return(false);
|
||||
}
|
||||
|
||||
BSP_Node *tree = fileloader->tree;
|
||||
struct_Data29 *data29;
|
||||
|
||||
|
||||
for(int i=0; i<fileloader->fragcount; i++) {
|
||||
if(fileloader->frags[i]->type == 0x29) {
|
||||
printf("We have a type 0x29 fragment. ");
|
||||
data29 = (struct_Data29 *) fileloader->frags[i]->frag;
|
||||
printf("It has %ld regions and is marked as type %d. ",
|
||||
data29->region_count, data29->region_type);
|
||||
switch(data29->region_type) {
|
||||
case RegionTypeUnsupported: { printf("Unsupported\n"); break; }
|
||||
case RegionTypeUntagged: {
|
||||
printf("Untagged. We will set it to ");
|
||||
if(DefaultRegionType==RegionTypeWater) {
|
||||
printf("Water\n");
|
||||
} else printf("Lava\n");
|
||||
data29->region_type = DefaultRegionType;
|
||||
WaterOrLavaCount++;
|
||||
break;
|
||||
}
|
||||
case RegionTypeWater: { printf("Water\n"); WaterOrLavaCount++; break; }
|
||||
case RegionTypeLava: { printf("Lava\n"); WaterOrLavaCount++; break; }
|
||||
case RegionTypeZoneLine: { printf("Zoneline\n"); break; }
|
||||
case RegionTypePVP: { printf("PVP\n"); break; }
|
||||
case RegionTypeSlime: { printf("Slime\n"); break; }
|
||||
case RegionTypeIce: { printf("Ice\n"); break; }
|
||||
case RegionTypeVWater: { printf("VWATER\n"); break; }
|
||||
default: printf("UNKNOWN\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(tree==nullptr) {
|
||||
printf("No BSP Tree. Bailing out\n");
|
||||
return(false);
|
||||
}
|
||||
|
||||
unsigned long BSPTreeSize = BSPCountNodes(tree, 1);
|
||||
|
||||
printf("There are %ld nodes in the BSP tree\n", BSPTreeSize);
|
||||
|
||||
// Now we mark each leaf in the BSP tree that is in a 'special area' with what type the area is
|
||||
// Water, Lava, Zoneline etc
|
||||
|
||||
for(int i=0; i<fileloader->fragcount; i++) {
|
||||
if(fileloader->frags[i]->type == 0x29) {
|
||||
data29 = (struct_Data29 *) fileloader->frags[i]->frag;
|
||||
for(long j=0; j<data29->region_count; j++) {
|
||||
BSPMarkRegion(tree, 1,data29->region_array[j]+1, data29->region_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now write out the file
|
||||
|
||||
char bufm[250];
|
||||
sprintf(bufm, "%s.wtr", shortname);
|
||||
|
||||
FILE *WaterFile = fopen(bufm, "wb");
|
||||
if(WaterFile == nullptr) {
|
||||
printf("Failed to open %s for writing\n", bufm);
|
||||
return(false);
|
||||
}
|
||||
const char *WFMagic = "EQEMUWATER";
|
||||
const long WFVersion = 1;
|
||||
|
||||
if(fwrite(WFMagic, strlen(WFMagic), 1, WaterFile) != 1) {
|
||||
printf("Error writing output file\n");
|
||||
fclose(WaterFile);
|
||||
return(false);
|
||||
}
|
||||
if(fwrite(&WFVersion, sizeof(WFVersion), 1, WaterFile) != 1) {
|
||||
printf("Error writing output file\n");
|
||||
fclose(WaterFile);
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(fwrite(&BSPTreeSize, sizeof(BSPTreeSize), 1, WaterFile) != 1) {
|
||||
printf("Error writing output file\n");
|
||||
fclose(WaterFile);
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(fwrite(tree, sizeof(BSP_Node), BSPTreeSize, WaterFile) != BSPTreeSize) {
|
||||
printf("Error writing output file\n");
|
||||
fclose(WaterFile);
|
||||
return(false);
|
||||
}
|
||||
|
||||
fclose(WaterFile);
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
void PrintBSP(BSP_Node *tree, long node_number) {
|
||||
printf("Node %ld, Left=%ld, Right=%ld\n",
|
||||
node_number-1,
|
||||
tree[node_number-1].left,
|
||||
tree[node_number-1].right);
|
||||
printf("Normals are %4.3f, %4.3f, %4.3f, SplitD is %4.3f\n",
|
||||
tree[node_number-1].normal[0],
|
||||
tree[node_number-1].normal[1],
|
||||
tree[node_number-1].normal[2],
|
||||
tree[node_number-1].splitdistance);
|
||||
|
||||
if(tree[node_number-1].left!=0) PrintBSP(tree, tree[node_number-1].left);
|
||||
if(tree[node_number-1].right!=0) PrintBSP(tree, tree[node_number-1].right);
|
||||
if((tree[node_number-1].left==0)&&
|
||||
(tree[node_number-1].right==0)) {
|
||||
printf("Region pointer is %ld\n", tree[node_number-1].region);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
long BSPCountNodes(BSP_Node *tree, long node_number) {
|
||||
|
||||
long NodesInRightBranch = 0, NodesInLeftBranch = 0;
|
||||
|
||||
if((tree[node_number-1].left==0)&&
|
||||
(tree[node_number-1].right==0)) return 1;
|
||||
|
||||
if(tree[node_number-1].left!=0) NodesInLeftBranch = BSPCountNodes(tree, (tree[node_number-1].left));
|
||||
if(tree[node_number-1].right!=0) NodesInRightBranch = BSPCountNodes(tree, (tree[node_number-1].right));
|
||||
|
||||
return(NodesInRightBranch + NodesInLeftBranch + 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
long BSPFindRegion(BSP_Node *tree, long node_number, long region) {
|
||||
//printf("Find Region %ld in node %ld\n", region, node_number);
|
||||
if(node_number<1) {
|
||||
printf("Something went wrong\n");
|
||||
exit(1);
|
||||
}
|
||||
if((tree[node_number-1].left==0)&&
|
||||
(tree[node_number-1].right==0)) {
|
||||
if(tree[node_number-1].region==region) return node_number;
|
||||
}
|
||||
|
||||
|
||||
long retnode ;
|
||||
if(tree[node_number-1].left!=0) {
|
||||
retnode = BSPFindRegion(tree, tree[node_number-1].left, region);
|
||||
if(retnode != 0) return retnode ;
|
||||
}
|
||||
|
||||
if(tree[node_number-1].right!=0) {
|
||||
return BSPFindRegion(tree, tree[node_number-1].right, region);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
long BSPFindNode(BSP_Node *tree, long node_number, float x, float y, float z) {
|
||||
|
||||
float distance;
|
||||
|
||||
|
||||
printf("BSP Find Node, currently in Node %ld\n", node_number);
|
||||
// Are we at a leaf
|
||||
|
||||
if((tree[node_number-1].left==0)&&
|
||||
(tree[node_number-1].right==0)) {
|
||||
return tree[node_number-1].region;
|
||||
}
|
||||
|
||||
// No, so determine which side of the split plane we are on
|
||||
//
|
||||
|
||||
distance = (x * tree[node_number-1].normal[0]) +
|
||||
(y * tree[node_number-1].normal[1]) +
|
||||
(z * tree[node_number-1].normal[2]) +
|
||||
tree[node_number-1].splitdistance;
|
||||
printf("Distance is %4.3f\n", distance);
|
||||
// Guess which side to go down
|
||||
if(distance == 0.0f) {
|
||||
printf("Distance is 0, don't know what to do!\n");
|
||||
exit(1);
|
||||
}
|
||||
if(distance >0.0f) {
|
||||
if(tree[node_number-1].left==0) {
|
||||
printf("Pos and no left node, abort!\n");
|
||||
exit(1);
|
||||
}
|
||||
return BSPFindNode(tree, tree[node_number-1].left,
|
||||
x, y, z);
|
||||
}
|
||||
|
||||
if(tree[node_number-1].right==0) {
|
||||
printf("Neg and no right node, abort!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return BSPFindNode(tree, tree[node_number-1].right,
|
||||
x, y, z);
|
||||
|
||||
}
|
||||
|
||||
|
||||
long BSPMarkRegion(BSP_Node *tree, long node_number, long region, int region_type) {
|
||||
//printf("Find Region %ld in node %ld\n", region, node_number);
|
||||
if(node_number<1) {
|
||||
printf("Something went wrong\n");
|
||||
exit(1);
|
||||
}
|
||||
if((tree[node_number-1].left==0)&&
|
||||
(tree[node_number-1].right==0)) {
|
||||
if(tree[node_number-1].region==region) {
|
||||
tree[node_number-1].special=region_type;
|
||||
return node_number;
|
||||
}
|
||||
}
|
||||
|
||||
long retnode ;
|
||||
if(tree[node_number-1].left!=0) {
|
||||
retnode = BSPMarkRegion(tree, tree[node_number-1].left, region, region_type);
|
||||
if(retnode != 0) return retnode ;
|
||||
}
|
||||
|
||||
if(tree[node_number-1].right!=0) {
|
||||
return BSPMarkRegion(tree, tree[node_number-1].right, region, region_type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
typedef enum {
|
||||
RegionTypeUnsupported = -2,
|
||||
RegionTypeUntagged = -1,
|
||||
RegionTypeNormal = 0,
|
||||
RegionTypeWater = 1,
|
||||
RegionTypeLava = 2,
|
||||
RegionTypeZoneLine = 3,
|
||||
RegionTypePVP = 4,
|
||||
RegionTypeSlime = 5,
|
||||
RegionTypeIce = 6,
|
||||
RegionTypeVWater =7
|
||||
|
||||
|
||||
} WaterRegionType;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,200 @@
|
||||
#ifndef AZONE_H
|
||||
#define AZONE_H
|
||||
|
||||
//pull in datatypes from zone's map.h
|
||||
#include "../../zone/map.h"
|
||||
#include "file_loader.hpp"
|
||||
|
||||
/*
|
||||
|
||||
Father Nitwit's zone to map file converter.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define COUNT_MACTHES 1
|
||||
|
||||
//this is the version number to put in the map header
|
||||
#undef MAP_VERSION //override this from map.h with our version
|
||||
#define MAP_VERSION 0x01000000
|
||||
|
||||
//quadtree stopping criteria, comment any to disable them
|
||||
#define MAX_QUADRENT_FACES 50 //if box has fewer than this, stop
|
||||
#define MIN_QUADRENT_SIZE 100.0f //if box has a dimention smaller than this, stop
|
||||
#define MIN_QUADRENT_GAIN 0.3f //minimum split ratio before stopping
|
||||
#define MAX_QUADRENT_MISSES 2 //maximum number of quads which can miss their gains
|
||||
//1 or 2 make sense, others are less useful
|
||||
|
||||
//attepmt to trim the data a little
|
||||
#define MAX_Z 3000.0 //seems to be a lot of points above this
|
||||
//if all points on poly are, kill it.
|
||||
/*
|
||||
This is used for the recursive node structure
|
||||
unsigned shorts are adequate because, worst case
|
||||
even in a zone that is 6000x6000 with a small node
|
||||
size of 30x30, there are only 40000 nodes.
|
||||
|
||||
quadrent definitions:
|
||||
quad 1 (nodes[0]):
|
||||
x>=0, y>=0
|
||||
quad 2 (nodes[1]):
|
||||
x<0, y>=0
|
||||
quad 3 (nodes[2]):
|
||||
x<0, y<0
|
||||
quad 4 (nodes[3]):
|
||||
x>=0, y<0
|
||||
|
||||
*/
|
||||
#define MAX_POLY_VTX 24 //arbitrary, im too lazy to figure it out
|
||||
//cut a triangle at most 6 times....
|
||||
|
||||
enum EQFileType { S3D, EQG, UNKNOWN };
|
||||
|
||||
struct POLYGON {
|
||||
VERTEX /*w[MAX_POLY_VTX], */c[MAX_POLY_VTX];
|
||||
int count; // w is world points, c is for camera points
|
||||
};
|
||||
|
||||
class GPoint {
|
||||
public:
|
||||
GPoint();
|
||||
GPoint(VERTEX &v);
|
||||
GPoint(float x, float y, float z);
|
||||
|
||||
inline void operator()(float nx, float ny, float nz) { x = nx; y = ny; z = nz; }
|
||||
|
||||
GPoint cross(const GPoint &them) const;
|
||||
float dot3(const GPoint &them) const;
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
};
|
||||
GPoint operator-(const GPoint &v1, const GPoint &v2);
|
||||
|
||||
class GVector : public GPoint {
|
||||
public:
|
||||
GVector();
|
||||
GVector(const GPoint &them);
|
||||
GVector(float x, float y, float z, float w = 1.0f);
|
||||
|
||||
inline void operator()(float nx, float ny, float nz, float nw) { x = nx; y = ny; z = nz; W = nw; }
|
||||
float dot4(const GVector &them) const;
|
||||
float dot4(const GPoint &them) const;
|
||||
void normalize();
|
||||
float length();
|
||||
|
||||
float W;
|
||||
};
|
||||
|
||||
struct FaceRecord {
|
||||
FACE *face;
|
||||
unsigned long index;
|
||||
};
|
||||
|
||||
class QTNode;
|
||||
|
||||
class QTBuilder {
|
||||
public:
|
||||
QTBuilder();
|
||||
~QTBuilder();
|
||||
|
||||
bool build(const char *shortname);
|
||||
bool build_eqg(const char *shortname);
|
||||
void AddPlaceable(FileLoader *fileloader, char *ZoneFileName, bool ListPlaceable=false);
|
||||
void AddPlaceableV4(FileLoader *fileloader, char *ZoneFileName, bool ListPlaceable=false);
|
||||
void RotateVertex(VERTEX &v, float XRotation, float YRotation, float ZRotation);
|
||||
void ScaleVertex(VERTEX &v, float XScale, float YScale, float ZScale);
|
||||
void TranslateVertex(VERTEX &v, float XOffset, float YOffset, float ZOffset);
|
||||
bool writeMap(const char *file);
|
||||
|
||||
bool FaceInNode(const QTNode *q, const FACE *f);
|
||||
protected:
|
||||
|
||||
void AddFace(VERTEX &v1, VERTEX &v2, VERTEX &v3);
|
||||
|
||||
int ClipPolygon(POLYGON *poly, GVector *plane);
|
||||
|
||||
//dynamic during load
|
||||
// vector<VERTEX> _VertexList;
|
||||
vector<FACE> _FaceList;
|
||||
|
||||
//static once loaded
|
||||
// unsigned long vertexCount;
|
||||
unsigned long faceCount;
|
||||
// VERTEX * vertexBlock;
|
||||
FACE * faceBlock;
|
||||
|
||||
VERTEX tempvtx[MAX_POLY_VTX];
|
||||
|
||||
QTNode *_root;
|
||||
|
||||
static void NormalizeN(FACE *p);
|
||||
|
||||
#ifdef COUNT_MACTHES
|
||||
unsigned long gEasyMatches;
|
||||
unsigned long gEasyExcludes;
|
||||
unsigned long gHardMatches;
|
||||
unsigned long gHardExcludes;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
//quadtree node container
|
||||
class QTNode {
|
||||
public:
|
||||
QTNode(QTBuilder *builder, float Tminx, float Tmaxx, float Tminy, float Tmaxy);
|
||||
~QTNode();
|
||||
|
||||
void clearNodes();
|
||||
|
||||
void doSplit();
|
||||
void divideYourself(int depth);
|
||||
|
||||
void buildVertexes();
|
||||
|
||||
// bool writeFile(FILE *out);
|
||||
|
||||
unsigned long countNodes() const;
|
||||
unsigned long countFacelists() const;
|
||||
|
||||
void fillBlocks(nodeHeader *heads, unsigned long *flist, unsigned long &hindex, unsigned long &findex);
|
||||
|
||||
float minx;
|
||||
float miny;
|
||||
float maxx;
|
||||
float maxy;
|
||||
unsigned long nfaces;
|
||||
vector<FaceRecord> faces;
|
||||
|
||||
/*
|
||||
quadrent definitions:
|
||||
quad 1 (node1):
|
||||
x>=0, y>=0
|
||||
quad 2 (node2):
|
||||
x<0, y>=0
|
||||
quad 3 (node3):
|
||||
x<0, y<0
|
||||
quad 4 (node4):
|
||||
x>=0, y<0
|
||||
*/
|
||||
QTNode *node1;
|
||||
QTNode *node2;
|
||||
QTNode *node3;
|
||||
QTNode *node4;
|
||||
GPoint v[8];
|
||||
bool final;
|
||||
|
||||
protected:
|
||||
QTBuilder *builder;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Include huts, houses dock and bridge from tox
|
||||
tox.s3d,7,17,20,26
|
||||
# Include two bridges from Tutorialb
|
||||
tutorialb.eqg,17,47
|
||||
# Include prison, ramp and a couple of towers in Anguish
|
||||
anguish.eqg,5,7,8,119
|
||||
# Include ruined buildings in LOIO
|
||||
lakeofillomen.s3d,49,50,51,52,53,54,55,56,57
|
||||
# Include bridges in thundercrest
|
||||
thundercrest.eqg,14,51
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
#ifndef __OPENEQ_DAT__
|
||||
#define __OPENEQ_DAT__
|
||||
|
||||
#include "global.hpp"
|
||||
#include "file_loader.hpp"
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct dat_header {
|
||||
unsigned long version, list_len, mat_count, vert_count, tri_count;
|
||||
} typedef dat_header;
|
||||
|
||||
struct dat_vertex {
|
||||
float x, y, z;
|
||||
float i, j, k;
|
||||
float u, v;
|
||||
} typedef dat_vertex;
|
||||
|
||||
struct dat_vertexV3 {
|
||||
float x, y, z;
|
||||
float i, j, k;
|
||||
long unk1;
|
||||
float unk2, unk3;
|
||||
float u, v;
|
||||
} typedef dat_vertexV3;
|
||||
|
||||
struct dat_triangle {
|
||||
long v1, v2, v3;
|
||||
long group;
|
||||
long unk;
|
||||
} typedef dat_triangle;
|
||||
|
||||
struct dat_object {
|
||||
long index;
|
||||
long name_offset, another_name_offset;
|
||||
long property_count;
|
||||
} typedef dat_object;
|
||||
|
||||
struct dat_property {
|
||||
long name_offset, type, value;
|
||||
} typedef dat_property;
|
||||
|
||||
struct dat_material {
|
||||
char *name;
|
||||
char *basetex;
|
||||
char var_count;
|
||||
char **var_names;
|
||||
char **var_vals;
|
||||
} typedef dat_material;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
class DATLoader : public FileLoader {
|
||||
public:
|
||||
DATLoader();
|
||||
~DATLoader();
|
||||
virtual int Open(char *base_path, char *zone_name, Archive *archive);
|
||||
virtual int Close();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "file.hpp"
|
||||
|
||||
int GetFile(uchar **buffer, int *buf_len, char *base_path, char *file_name, Archive *archive) {
|
||||
FILE *fp;
|
||||
char *temp;
|
||||
|
||||
if(base_path) {
|
||||
temp = new char[strlen(base_path) + strlen(file_name) + 2];
|
||||
sprintf(temp, "%s/%s", base_path, file_name);
|
||||
|
||||
fp = fopen(temp, "rb");
|
||||
|
||||
delete[] temp;
|
||||
|
||||
if(!fp)
|
||||
return 0;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
*buf_len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
*buffer = new uchar[*buf_len];
|
||||
fread(*buffer, 1, *buf_len, fp);
|
||||
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return archive->GetFile(file_name, buffer, buf_len);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef __OPENEQ_FILE__
|
||||
#define __OPENEQ_FILE__
|
||||
|
||||
#include "archive.hpp"
|
||||
|
||||
int GetFile(uchar **buffer, int *buf_len, char *base_path, char *file_name, Archive *archive);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef __OPENEQ_FL_API__
|
||||
#define __OPENEQ_FL_API__
|
||||
|
||||
#include "archive.hpp"
|
||||
#include "3d.hpp"
|
||||
|
||||
class FileLoader {
|
||||
public:
|
||||
FileLoader() {}
|
||||
virtual ~FileLoader() {}
|
||||
|
||||
virtual int Open(char *base_path, char *zone_name, Archive *archive) = 0;
|
||||
virtual int Close() = 0;
|
||||
|
||||
Content_3D model_data;
|
||||
protected:
|
||||
uchar *buffer;
|
||||
int buf_len;
|
||||
Archive *archive;
|
||||
|
||||
int status;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "global.hpp"
|
||||
|
||||
#define swapl
|
||||
#define swaps
|
||||
|
||||
uint16 GetUint16(uchar **buf) {
|
||||
uint16 ret = swaps(*((uint16 *) *buf));
|
||||
*buf += 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 GetUint32(uchar **buf) {
|
||||
uint32 ret = swapl(*((uint32 *) *buf));
|
||||
*buf += 4;
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __OPENEQ_GLOBALS__
|
||||
#define __OPENEQ_GLOBALS__
|
||||
|
||||
#ifdef WIN32
|
||||
#define Polygon Polygon_Win32
|
||||
#include <winsock.h>
|
||||
#undef Polygon
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned char uchar;
|
||||
typedef char int8;
|
||||
|
||||
uint16 GetUint16(uchar **buf);
|
||||
uint32 GetUint32(uchar **buf);
|
||||
|
||||
#define uint16(buf) \
|
||||
GetUint16((uchar **) &buf)
|
||||
#define uint32(buf) \
|
||||
GetUint32((uchar **) &buf)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
|
||||
List Placeable Objects in an S3D or EQG.
|
||||
By Derision, based on OpenEQ File Loaders by Daeken et al.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef short SHORT;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "types.h"
|
||||
#include "wld.hpp"
|
||||
|
||||
#include "archive.hpp"
|
||||
#include "pfs.hpp"
|
||||
|
||||
#include "file_loader.hpp"
|
||||
#include "zon.hpp"
|
||||
#include "ter.hpp"
|
||||
#include "zonv4.hpp"
|
||||
|
||||
|
||||
|
||||
bool ProcessZoneFile(const char *shortname);
|
||||
void ListPlaceable(FileLoader *fileloader, char *ZoneFileName);
|
||||
void ListPlaceableV4(FileLoader *fileloader, char *ZoneFileName);
|
||||
enum EQFileType { S3D, EQG, UNKNOWN };
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
printf("LISTOBJ: List Placeable Objects in .S3D or .EQG zone files.\n");
|
||||
|
||||
if(argc != 2) {
|
||||
printf("Usage: %s (zone short name)\n", argv[0]);
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(ProcessZoneFile(argv[1]));
|
||||
}
|
||||
|
||||
bool ProcessZoneFile(const char *shortname) {
|
||||
|
||||
char bufs[96];
|
||||
Archive *archive;
|
||||
FileLoader *fileloader;
|
||||
Zone_Model *zm;
|
||||
FILE *fff;
|
||||
EQFileType FileType = UNKNOWN;
|
||||
|
||||
sprintf(bufs, "%s.s3d", shortname);
|
||||
|
||||
archive = new PFSLoader();
|
||||
fff = fopen(bufs, "rb");
|
||||
if(fff != nullptr)
|
||||
FileType = S3D;
|
||||
else {
|
||||
sprintf(bufs, "%s.eqg", shortname);
|
||||
fff = fopen(bufs, "rb");
|
||||
if(fff != nullptr)
|
||||
FileType = EQG;
|
||||
}
|
||||
|
||||
if(FileType == UNKNOWN) {
|
||||
printf("Unable to locate %s.s3d or %s.eqg\n", shortname, shortname);
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(archive->Open(fff) == 0) {
|
||||
printf("Unable to open container file '%s'\n", bufs);
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool V4Zone = false;
|
||||
|
||||
switch(FileType) {
|
||||
case S3D:
|
||||
fileloader = new WLDLoader();
|
||||
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
|
||||
printf("Error reading WLD from %s\n", bufs);
|
||||
return(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case EQG:
|
||||
fileloader = new ZonLoader();
|
||||
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
|
||||
delete fileloader;
|
||||
fileloader = new Zonv4Loader();
|
||||
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
|
||||
printf("Error reading ZON/TER from %s\n", bufs);
|
||||
return(false);
|
||||
}
|
||||
V4Zone = true;
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
zm = fileloader->model_data.zone_model;
|
||||
|
||||
if(!V4Zone)
|
||||
ListPlaceable(fileloader, bufs);
|
||||
else
|
||||
ListPlaceableV4(fileloader, bufs);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void ListPlaceable(FileLoader *fileloader, char *ZoneFileName) {
|
||||
|
||||
for(int i = 0; i < fileloader->model_data.plac_count; ++i) {
|
||||
if(fileloader->model_data.placeable[i]->model==-1) continue;
|
||||
if(fileloader->model_data.models[fileloader->model_data.placeable[i]->model] == nullptr) continue;
|
||||
printf("Placeable Object %4d @ (%9.2f, %9.2f, %9.2f uses model %4d %s\n",i,
|
||||
fileloader->model_data.placeable[i]->y,
|
||||
fileloader->model_data.placeable[i]->x,
|
||||
fileloader->model_data.placeable[i]->z,
|
||||
fileloader->model_data.placeable[i]->model,
|
||||
fileloader->model_data.models[fileloader->model_data.placeable[i]->model]->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ListPlaceableV4(FileLoader *fileloader, char *ZoneFileName)
|
||||
{
|
||||
|
||||
float XOffset, YOffset, ZOffset;
|
||||
float RotX, RotY, RotZ;
|
||||
float XScale, YScale, ZScale;
|
||||
|
||||
|
||||
vector<ObjectGroupEntry>::iterator Iterator;
|
||||
|
||||
int OGNum = 0;
|
||||
|
||||
Iterator = fileloader->model_data.ObjectGroups.begin();
|
||||
|
||||
while(Iterator != fileloader->model_data.ObjectGroups.end())
|
||||
{
|
||||
printf("ObjectGroup Number: %i\n", OGNum++);
|
||||
|
||||
printf("ObjectGroup Coordinates: %8.3f, %8.3f, %8.3f\n",
|
||||
(*Iterator).x, (*Iterator).y, (*Iterator).z);
|
||||
|
||||
printf("Tile: %8.3f, %8.3f, %8.3f\n",
|
||||
(*Iterator).TileX, (*Iterator).TileY, (*Iterator).TileZ);
|
||||
|
||||
printf("ObjectGroup Rotations : %8.3f, %8.3f, %8.3f\n",
|
||||
(*Iterator).RotX, (*Iterator).RotY, (*Iterator).RotZ);
|
||||
|
||||
printf("ObjectGroup Scale : %8.3f, %8.3f, %8.3f\n",
|
||||
(*Iterator).ScaleX, (*Iterator).ScaleY, (*Iterator).ScaleZ);
|
||||
|
||||
list<int>::iterator ModelIterator;
|
||||
|
||||
ModelIterator = (*Iterator).SubObjects.begin();
|
||||
|
||||
while(ModelIterator != (*Iterator).SubObjects.end())
|
||||
{
|
||||
int SubModel = (*ModelIterator);
|
||||
|
||||
Model *model = fileloader->model_data.models[fileloader->model_data.placeable[SubModel]->model];
|
||||
|
||||
printf(" SubModel: %i [Model: %i, %s] ", SubModel, fileloader->model_data.placeable[SubModel]->model, model->name );
|
||||
printf("Default to include in map: %s\n", model->IncludeInMap ? "YES" : "NO");
|
||||
|
||||
XOffset = fileloader->model_data.placeable[SubModel]->x;
|
||||
YOffset = fileloader->model_data.placeable[SubModel]->y;
|
||||
ZOffset = fileloader->model_data.placeable[SubModel]->z;
|
||||
|
||||
printf(" Translations: %8.3f, %8.3f, %8.3f\n", XOffset, YOffset, ZOffset);
|
||||
printf(" Rotations : %8.3f, %8.3f, %8.3f\n", fileloader->model_data.placeable[SubModel]->rx,
|
||||
fileloader->model_data.placeable[SubModel]->ry, fileloader->model_data.placeable[SubModel]->rz);
|
||||
printf(" Scale : %8.3f, %8.3f, %8.3f\n", fileloader->model_data.placeable[SubModel]->scale[0],
|
||||
fileloader->model_data.placeable[SubModel]->scale[1], fileloader->model_data.placeable[SubModel]->scale[2]);
|
||||
|
||||
|
||||
RotX = fileloader->model_data.placeable[SubModel]->rx * 3.14159 / 180; // Convert from degrees to radians
|
||||
RotY = fileloader->model_data.placeable[SubModel]->ry * 3.14159 / 180;
|
||||
RotZ = fileloader->model_data.placeable[SubModel]->rz * 3.14159 / 180;
|
||||
|
||||
XScale = fileloader->model_data.placeable[SubModel]->scale[0];
|
||||
YScale = fileloader->model_data.placeable[SubModel]->scale[1];
|
||||
ZScale = fileloader->model_data.placeable[SubModel]->scale[2];
|
||||
|
||||
++ModelIterator;
|
||||
}
|
||||
printf("\n");
|
||||
Iterator++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef __OPENEQ_OCTREE__
|
||||
#define __OPENEQ_OCTREE__
|
||||
|
||||
#ifdef WIN32
|
||||
#define Polygon Polygon_win32
|
||||
#include <windows.h>
|
||||
#undef Polygon
|
||||
#endif
|
||||
|
||||
#include "3d_base.hpp"
|
||||
|
||||
class Octree_Node {
|
||||
public:
|
||||
Octree_Node();
|
||||
Octree_Node(int poly_count, Polygon **polys, Vertex **verts, int plac_count, Placeable **plac);
|
||||
Octree_Node(int poly_count, Polygon **polys, Vertex **verts, int plac_count, Placeable **plac, float min[3], float max[3]);
|
||||
~Octree_Node();
|
||||
void FindMinMax();
|
||||
void Split(char level);
|
||||
|
||||
float min[3], max[3];
|
||||
float x, y, z, size, sizes[3];
|
||||
|
||||
int poly_count;
|
||||
Vertex **verts;
|
||||
Polygon **polys;
|
||||
|
||||
int plac_count;
|
||||
Placeable **plac;
|
||||
|
||||
GLuint li;
|
||||
|
||||
Octree_Node *nodes[8];
|
||||
};
|
||||
|
||||
#define in_box(obj, x, y, z) \
|
||||
( \
|
||||
(x) >= (obj)->min[0] && (x) <= (obj)->max[0] && \
|
||||
(y) >= (obj)->min[1] && (y) <= (obj)->max[1] &&\
|
||||
(z) >= (obj)->min[2] && (z) <= (obj)->max[2] \
|
||||
)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,253 @@
|
||||
|
||||
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "pfs.hpp"
|
||||
|
||||
#pragma pack(1)
|
||||
//#define DEBUGPFS
|
||||
|
||||
struct struct_header {
|
||||
uint32 offset;
|
||||
char magicCookie[4];
|
||||
uint32 unknown;
|
||||
} typedef struct_header;
|
||||
|
||||
struct struct_directory_header {
|
||||
uint32 count;
|
||||
} typedef struct_directory_header;
|
||||
|
||||
struct struct_directory {
|
||||
uint32 crc, offset, size;
|
||||
} typedef struct_directory;
|
||||
|
||||
struct struct_data_block {
|
||||
uint32 deflen, inflen;
|
||||
} typedef struct_data_block;
|
||||
|
||||
struct struct_fn_header {
|
||||
uint32 fncount;
|
||||
} typedef struct_fn_header;
|
||||
|
||||
struct struct_fn_entry {
|
||||
uint32 fnlen;
|
||||
} typedef struct_fn_entry;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
inline void decompress(char *p, char *p2, int len, int uLen) {
|
||||
int status;
|
||||
z_stream d_stream;
|
||||
|
||||
d_stream.zalloc = (alloc_func)0;
|
||||
d_stream.zfree = (free_func)0;
|
||||
d_stream.opaque = (voidpf)0;
|
||||
|
||||
d_stream.next_in = (Bytef *) p;
|
||||
d_stream.avail_in = len;
|
||||
d_stream.next_out = (Bytef *) p2;
|
||||
d_stream.avail_out = uLen;
|
||||
|
||||
inflateInit(&d_stream);
|
||||
status = inflate(&d_stream, Z_NO_FLUSH);
|
||||
inflateEnd(&d_stream);
|
||||
}
|
||||
|
||||
inline void Lower(char *str) {
|
||||
while(*str) {
|
||||
if(*str >= 'A' && *str <= 'Z')
|
||||
*str += 'a' - 'A';
|
||||
++str;
|
||||
}
|
||||
}
|
||||
|
||||
PFSLoader::PFSLoader() {
|
||||
// Set the status of the loader that nothing is loaded.
|
||||
this->buffer = nullptr;
|
||||
this->buf_len = -1;
|
||||
this->status = 0;
|
||||
}
|
||||
|
||||
PFSLoader::~PFSLoader() {
|
||||
this->Close();
|
||||
}
|
||||
|
||||
int PFSLoader::Open(FILE *fp)
|
||||
{
|
||||
struct_header s3d_header;
|
||||
struct_directory_header s3d_dir_header;
|
||||
struct_directory s3d_dir;
|
||||
struct_data_block s3d_data;
|
||||
struct_fn_header *s3d_fn_header;
|
||||
struct_fn_entry *s3d_fn_entry;
|
||||
|
||||
uint32 *offsets;
|
||||
|
||||
char *temp, *temp2;
|
||||
int i, j, pos, inf, tmp, running = 0;
|
||||
|
||||
if(!fp)
|
||||
return 0;
|
||||
|
||||
fread(&s3d_header, sizeof(struct_header), 1, fp);
|
||||
|
||||
if(s3d_header.magicCookie[0] != 'P' || s3d_header.magicCookie[1] != 'F'
|
||||
|| s3d_header.magicCookie[2] != 'S' || s3d_header.magicCookie[3] != ' ')
|
||||
return 0;
|
||||
|
||||
this->fp = fp;
|
||||
|
||||
#ifdef DEBUGPFS
|
||||
printf("Offset: %d\n", s3d_header.offset);
|
||||
#endif
|
||||
|
||||
fseek(fp, s3d_header.offset, SEEK_SET);
|
||||
fread(&s3d_dir_header, sizeof(struct_directory_header), 1, fp);
|
||||
|
||||
this->count = s3d_dir_header.count - 1;
|
||||
this->filenames = new char *[s3d_dir_header.count];
|
||||
this->files = new uint32[s3d_dir_header.count - 1];
|
||||
offsets = new uint32[s3d_dir_header.count - 1];
|
||||
|
||||
for(i = 0; i < (int)s3d_dir_header.count; ++i)
|
||||
{
|
||||
fread(&s3d_dir, sizeof(struct_directory), 1, fp);
|
||||
|
||||
if(s3d_dir.crc == ntohl(0xC90A5861))
|
||||
{
|
||||
pos = ftell(fp);
|
||||
fseek(fp, s3d_dir.offset, SEEK_SET);
|
||||
temp = new char[s3d_dir.size];
|
||||
memset(temp, 0, s3d_dir.size);
|
||||
inf = 0;
|
||||
|
||||
while(inf < (int)s3d_dir.size)
|
||||
{
|
||||
fread(&s3d_data, sizeof(struct_data_block), 1, fp);
|
||||
temp2 = new char[s3d_data.deflen];
|
||||
fread(temp2, s3d_data.deflen, 1, fp);
|
||||
decompress(temp2, temp + inf, s3d_data.deflen, s3d_data.inflen);
|
||||
delete[] temp2;
|
||||
inf += s3d_data.inflen;
|
||||
}
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
s3d_fn_header = (struct_fn_header *) temp;
|
||||
pos = sizeof(struct_fn_header);
|
||||
for(j = 0; j < (int)s3d_fn_header->fncount; ++j)
|
||||
{
|
||||
s3d_fn_entry = (struct_fn_entry *) &temp[pos];
|
||||
this->filenames[j] = new char[s3d_fn_entry->fnlen + 1];
|
||||
this->filenames[j][s3d_fn_entry->fnlen] = 0;
|
||||
memcpy(this->filenames[j], &temp[pos + sizeof(struct_fn_entry)], s3d_fn_entry->fnlen);
|
||||
pos += sizeof(struct_fn_entry) + s3d_fn_entry->fnlen;
|
||||
}
|
||||
delete [] temp;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
this->files[running] = ftell(fp) - 12;
|
||||
offsets[running] = s3d_dir.offset;
|
||||
++running;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(i = s3d_dir_header.count - 2; i > 0; i--)
|
||||
{
|
||||
for(j = 0; j < i; j++)
|
||||
{
|
||||
if(offsets[j] > offsets[j+1])
|
||||
{
|
||||
tmp = offsets[j];
|
||||
offsets[j] = offsets[j + 1];
|
||||
offsets[j + 1] = tmp;
|
||||
tmp = this->files[j];
|
||||
this->files[j] = this->files[j + 1];
|
||||
this->files[j + 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] offsets;
|
||||
|
||||
this->status = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PFSLoader::Close()
|
||||
{
|
||||
if(this->status)
|
||||
{
|
||||
while(this->count > 0)
|
||||
{
|
||||
delete [] this->filenames[this->count - 1];
|
||||
--this->count;
|
||||
}
|
||||
delete[] this->filenames;
|
||||
delete[] this->files;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
this->buffer = nullptr;
|
||||
this->buf_len = -1;
|
||||
this->status = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *PFSLoader::FindExtension(const char *ext) {
|
||||
int i;
|
||||
|
||||
int elen = strlen(ext);
|
||||
|
||||
for(i = 0; i < this->count; ++i) {
|
||||
int flen = strlen(this->filenames[i]);
|
||||
if(flen <= elen)
|
||||
continue;
|
||||
if(!strcmp(this->filenames[i]+(flen-elen), ext))
|
||||
return(this->filenames[i]);
|
||||
}
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
int PFSLoader::GetFile(char *name, uchar **buf, int *len) {
|
||||
struct_directory s3d_dir;
|
||||
struct_data_block s3d_data;
|
||||
char *temp2;
|
||||
long inf;
|
||||
int i;
|
||||
Lower(name);
|
||||
|
||||
for(i = 0; i < this->count; ++i) {
|
||||
|
||||
// Derision: Added basic wildcard ability as .ZON filenames don't always match the EQG name
|
||||
if(!strcmp(this->filenames[i], name) ||
|
||||
((name[0]=='*') && !strcmp(this->filenames[i]+strlen(filenames[i])-strlen(name)+2, name+2))) {
|
||||
fseek(this->fp, this->files[i], SEEK_SET);
|
||||
fread(&s3d_dir, sizeof(struct_directory), 1, this->fp);
|
||||
fseek(this->fp, s3d_dir.offset, SEEK_SET);
|
||||
*buf = new uchar[s3d_dir.size];
|
||||
|
||||
inf = 0;
|
||||
while(inf < (int)s3d_dir.size) {
|
||||
fread(&s3d_data, sizeof(struct_data_block), 1, this->fp);
|
||||
temp2 = new char[s3d_data.deflen];
|
||||
fread(temp2, s3d_data.deflen, 1, this->fp);
|
||||
decompress(temp2, (char *) *buf + inf, s3d_data.deflen, s3d_data.inflen);
|
||||
delete [] temp2;
|
||||
inf += s3d_data.inflen;
|
||||
}
|
||||
|
||||
*len = inf;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef __OPENEQ_PFS__
|
||||
#define __OPENEQ_PFS__
|
||||
|
||||
#include <stdio.h>
|
||||
#include "global.hpp"
|
||||
#include "archive.hpp"
|
||||
|
||||
|
||||
class PFSLoader : public Archive {
|
||||
public:
|
||||
PFSLoader();
|
||||
~PFSLoader();
|
||||
|
||||
virtual int Open(FILE *fp);
|
||||
virtual int Close();
|
||||
|
||||
virtual int GetFile(char *name, uchar **buf, int *len);
|
||||
virtual const char *FindExtension(const char *ext);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef __EQCLIENT_S3D_H_
|
||||
#define __EQCLIENT_S3D_H_
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
|
||||
typedef struct struct_header {
|
||||
uint32 offset;
|
||||
char magicCookie[4];
|
||||
uint32 unknown;
|
||||
} struct_header;
|
||||
|
||||
typedef struct struct_directory_header {
|
||||
uint32 count;
|
||||
} struct_directory_header;
|
||||
|
||||
typedef struct struct_directory {
|
||||
uint32 crc, offset, size;
|
||||
} struct_directory;
|
||||
|
||||
typedef struct struct_data_block {
|
||||
uint32 deflen, inflen;
|
||||
} struct_data_block;
|
||||
|
||||
typedef struct struct_fn_header {
|
||||
uint32 fncount;
|
||||
} struct_fn_header;
|
||||
|
||||
typedef struct struct_fn_entry {
|
||||
uint32 fnlen;
|
||||
} struct_fn_entry;
|
||||
|
||||
typedef struct s3d_object {
|
||||
FILE *fp;
|
||||
long count;
|
||||
char **filenames;
|
||||
uint32 *files;
|
||||
} s3d_object;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int S3D_Init(s3d_object *obj, FILE *fp);
|
||||
size_t S3D_GetFile(s3d_object *obj, char *filename, uchar **out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
|
||||
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "file.hpp"
|
||||
#include "ter.hpp"
|
||||
//#define DEBUGTER
|
||||
|
||||
TERLoader::TERLoader() {
|
||||
this->buffer = nullptr;
|
||||
this->buf_len = -1;
|
||||
this->archive = nullptr;
|
||||
this->status = 0;
|
||||
}
|
||||
|
||||
TERLoader::~TERLoader() {
|
||||
this->Close();
|
||||
}
|
||||
|
||||
int TERLoader::Open(char *base_path, char *zone_name, Archive *archive) {
|
||||
|
||||
#ifdef DEBUGTER
|
||||
printf("TERLoader::Open %s, [%s]\n", base_path, zone_name);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
ter_header *thdr;
|
||||
ter_vertex *tver;
|
||||
ter_vertexV3 *tverV3;
|
||||
ter_triangle *ttri;
|
||||
uchar *ter_orig, *ter_tmp, *StartOfNameList;
|
||||
int model = 0;
|
||||
unsigned int i, j, mat_count = 0;
|
||||
|
||||
Zone_Model *zm;
|
||||
|
||||
material *mlist;
|
||||
|
||||
uchar *buffer;
|
||||
int buf_len, bone_count;
|
||||
|
||||
char *filename;
|
||||
|
||||
if(zone_name[strlen(zone_name) - 4] == '.')
|
||||
filename = zone_name;
|
||||
else {
|
||||
filename = new char[strlen(zone_name) + 5];
|
||||
sprintf(filename, "%s.ter", zone_name);
|
||||
}
|
||||
|
||||
if(!GetFile(&buffer, &buf_len, base_path, filename, archive)) {
|
||||
if(filename != zone_name)
|
||||
delete[] filename;
|
||||
return 0;
|
||||
}
|
||||
if(filename != zone_name)
|
||||
delete[] filename;
|
||||
|
||||
thdr = (ter_header *) buffer;
|
||||
|
||||
mlist = new material[thdr->mat_count];
|
||||
|
||||
ter_orig = buffer;
|
||||
|
||||
if(thdr->magic[0] != 'E' || thdr->magic[1] != 'Q' || thdr->magic[2] != 'G')
|
||||
return 0;
|
||||
|
||||
if(thdr->magic[3] == 'M') {
|
||||
model = 1;
|
||||
buffer += sizeof(ter_header);
|
||||
bone_count = *((uint32 *) buffer);
|
||||
buffer += sizeof(uint32);
|
||||
}
|
||||
else if(thdr->magic[3] == 'T')
|
||||
buffer += sizeof(ter_header);
|
||||
else
|
||||
return 0;
|
||||
|
||||
ter_tmp = buffer + thdr->list_len;
|
||||
|
||||
if(sizeof(ter_header) + thdr->list_len + (thdr->vert_count * sizeof(ter_vertex)) + (thdr->tri_count * sizeof(ter_triangle)) > (unsigned int)buf_len)
|
||||
return 0;
|
||||
|
||||
for(i = 0; i < thdr->mat_count; ++i) {
|
||||
mlist[i].name = nullptr;
|
||||
mlist[i].basetex = nullptr;
|
||||
}
|
||||
|
||||
StartOfNameList = buffer;
|
||||
buffer = buffer + thdr->list_len;
|
||||
#ifdef DEBUGTER
|
||||
printf("Offset is %X\n", buffer - ter_orig);
|
||||
#endif
|
||||
for(j=0; j< thdr->mat_count; j++) {
|
||||
struct ter_object *tobj = (struct ter_object *)buffer;
|
||||
buffer += sizeof(struct ter_object);
|
||||
for (unsigned int i=0; i<(unsigned int)tobj->property_count; i++) {
|
||||
struct ter_property *tprop = (struct ter_property *)buffer;
|
||||
buffer += sizeof(struct ter_property);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this->model_data.zone_model = new Zone_Model;
|
||||
zm = this->model_data.zone_model;
|
||||
|
||||
zm->vert_count = thdr->vert_count;
|
||||
zm->poly_count = thdr->tri_count;
|
||||
|
||||
zm->verts = new Vertex *[zm->vert_count];
|
||||
zm->polys = new Polygon *[zm->poly_count];
|
||||
|
||||
this->model_data.plac_count = 0;
|
||||
this->model_data.model_count = 0;
|
||||
|
||||
buffer = ter_orig + thdr->list_len + sizeof(ter_header);
|
||||
if(thdr->magic[3] == 'M') buffer = buffer + 4;
|
||||
#ifdef DEBUGTER
|
||||
printf("Starting offset is %8X\n", buffer-ter_orig);
|
||||
#endif
|
||||
for(unsigned int b=0; b<thdr->mat_count; b++) {
|
||||
unsigned long property_count = *((unsigned long *)(buffer+12));
|
||||
#ifdef DEBUGTER
|
||||
printf("Property count is %d\n", property_count); fflush(stdout);
|
||||
#endif
|
||||
buffer += 16;
|
||||
for (unsigned int a=0; a<property_count; a++)
|
||||
buffer += 12;
|
||||
}
|
||||
#ifdef DEBUGTER
|
||||
printf("Offset is %8X\n", buffer - ter_orig);
|
||||
#endif
|
||||
|
||||
|
||||
for(i = 0; i < (unsigned int)zm->vert_count; ++i) {
|
||||
if(thdr->version<3) {
|
||||
tver = (ter_vertex *) buffer;
|
||||
zm->verts[i] = new Vertex;
|
||||
zm->verts[i]->x = tver->x;
|
||||
zm->verts[i]->y = tver->y;
|
||||
zm->verts[i]->z = tver->z;
|
||||
zm->verts[i]->u = tver->u;
|
||||
zm->verts[i]->v = tver->v;
|
||||
buffer += sizeof(ter_vertex);
|
||||
}
|
||||
else {
|
||||
tverV3 = (ter_vertexV3 *) buffer;
|
||||
zm->verts[i] = new Vertex;
|
||||
zm->verts[i]->x = tverV3->x;
|
||||
zm->verts[i]->y = tverV3->y;
|
||||
zm->verts[i]->z = tverV3->z;
|
||||
zm->verts[i]->u = tverV3->u;
|
||||
zm->verts[i]->v = tverV3->v;
|
||||
buffer += sizeof(ter_vertexV3);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for(i = 0; i < (unsigned int)zm->poly_count; ++i) {
|
||||
ttri = (ter_triangle *) buffer;
|
||||
if(ttri->group == -1) {
|
||||
buffer += sizeof(ter_triangle);
|
||||
continue;
|
||||
}
|
||||
zm->polys[j] = new Polygon;
|
||||
/*
|
||||
zm->polys[j]->v1 = ttri->v1;
|
||||
zm->polys[j]->v2 = ttri->v2;
|
||||
zm->polys[j]->v3 = ttri->v3;
|
||||
*/
|
||||
|
||||
// Change the order of the vertices to keep the normals consistent with map files generated for S3Ds in prior versions of azone.
|
||||
|
||||
#ifndef KEEP_OLD_EQG_VERTEX_ORDER
|
||||
zm->polys[j]->v1 = ttri->v3;
|
||||
zm->polys[j]->v2 = ttri->v2;
|
||||
zm->polys[j]->v3 = ttri->v1;
|
||||
#else
|
||||
zm->polys[j]->v1 = ttri->v1;
|
||||
zm->polys[j]->v2 = ttri->v2;
|
||||
zm->polys[j]->v3 = ttri->v3;
|
||||
#endif
|
||||
zm->polys[j]->flags = ttri->unk;
|
||||
|
||||
|
||||
if(ttri->group == -1) {
|
||||
#ifdef DEBUGTER
|
||||
printf("TERLoader:: zm->poly[%d]->tex = mat_count%d\n", j, thdr->mat_count);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
zm->polys[j]->tex = thdr->mat_count;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUGTER
|
||||
printf("TERLoader:: zm->poly[%d]->tex = ttri->group %d, Unk=%d\n", j, ttri->group, ttri->unk);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
zm->polys[j]->tex = ttri->group;
|
||||
}
|
||||
|
||||
++j;
|
||||
buffer += sizeof(ter_triangle);
|
||||
}
|
||||
|
||||
zm->poly_count = j;
|
||||
|
||||
zm->tex_count = 0;
|
||||
|
||||
delete[] mlist;
|
||||
|
||||
delete [] ter_orig;
|
||||
|
||||
this->status = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int TERLoader::Close() {
|
||||
Zone_Model *zm = this->model_data.zone_model;
|
||||
int i;
|
||||
|
||||
//return 1;
|
||||
|
||||
if(!this->status)
|
||||
return 1;
|
||||
|
||||
for(i = 0; i < zm->vert_count; ++i)
|
||||
delete zm->verts[i];
|
||||
for(i = 0; i < zm->poly_count; ++i)
|
||||
delete zm->polys[i];
|
||||
|
||||
delete[] zm->verts;
|
||||
delete[] zm->polys;
|
||||
|
||||
delete this->model_data.zone_model;
|
||||
|
||||
status = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef __OPENEQ_TER__
|
||||
#define __OPENEQ_TER__
|
||||
|
||||
#include "global.hpp"
|
||||
#include "file_loader.hpp"
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct ter_header {
|
||||
char magic[4];
|
||||
unsigned long version, list_len, mat_count, vert_count, tri_count;
|
||||
} typedef ter_header;
|
||||
|
||||
struct ter_vertex {
|
||||
float x, y, z;
|
||||
float i, j, k;
|
||||
float u, v;
|
||||
} typedef ter_vertex;
|
||||
|
||||
struct ter_vertexV3 {
|
||||
float x, y, z;
|
||||
float i, j, k;
|
||||
long unk1;
|
||||
float unk2, unk3;
|
||||
float u, v;
|
||||
} typedef ter_vertexV3;
|
||||
|
||||
struct ter_triangle {
|
||||
long v1, v2, v3;
|
||||
long group;
|
||||
long unk;
|
||||
} typedef ter_triangle;
|
||||
|
||||
struct ter_object {
|
||||
long index;
|
||||
long name_offset, another_name_offset;
|
||||
long property_count;
|
||||
} typedef ter_object;
|
||||
|
||||
struct ter_property {
|
||||
long name_offset, type, value;
|
||||
} typedef ter_property;
|
||||
|
||||
struct material {
|
||||
char *name;
|
||||
char *basetex;
|
||||
char var_count;
|
||||
char **var_names;
|
||||
char **var_vals;
|
||||
} typedef material;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
class TERLoader : public FileLoader {
|
||||
public:
|
||||
TERLoader();
|
||||
~TERLoader();
|
||||
virtual int Open(char *base_path, char *zone_name, Archive *archive);
|
||||
virtual int Close();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef __EQCLIENT_TYPES_H_
|
||||
#define __EQCLIENT_TYPES_H_
|
||||
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned char uchar;
|
||||
typedef char int8;
|
||||
|
||||
#define null 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,758 @@
|
||||
|
||||
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
|
||||
|
||||
#include "wld.hpp"
|
||||
#include "file.hpp"
|
||||
#include "pfs.hpp"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
//#define DEBUGWLD
|
||||
|
||||
static uchar encarr[] = {0x95, 0x3A, 0xC5, 0x2A, 0x95, 0x7A, 0x95, 0x6A};
|
||||
|
||||
inline void decode(uchar *str, int len) { int i; for(i = 0; i < len; ++i) str[i] ^= encarr[i % 8]; }
|
||||
|
||||
|
||||
FRAG_CONSTRUCTOR(Data03) {
|
||||
int i, count, fnlen;
|
||||
Texture *tex;
|
||||
|
||||
count = uint32(buf);
|
||||
if(!count) count = 1;
|
||||
|
||||
tex = new Texture;
|
||||
tex->filenames = new char *[count];
|
||||
tex->frame_count = count;
|
||||
tex->current_frame = 0;
|
||||
tex->archive = nullptr;
|
||||
tex->flags = 0;
|
||||
|
||||
for(i = 0; i < count; ++i) {
|
||||
fnlen = uint16(buf);
|
||||
tex->filenames[i] = new char[fnlen];
|
||||
memcpy(tex->filenames[i], buf, fnlen);
|
||||
decode((uchar *) tex->filenames[i], fnlen);
|
||||
|
||||
//printf("fnlen is %d, %s\n", fnlen, tex->filenames[i]);
|
||||
// Derision: Not sure why this check is here, but need to check fnlen is >=18
|
||||
if(fnlen>=18) {
|
||||
if(tex->filenames[i][fnlen - 8] == '.')
|
||||
tex->filenames[i][fnlen - 17] = '\0';
|
||||
}
|
||||
|
||||
buf += fnlen;
|
||||
}
|
||||
this->frag = (void *) tex;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data04) {
|
||||
int flags, count, i;
|
||||
Texture *tex, *texref;
|
||||
|
||||
flags = uint32(buf);
|
||||
count = uint32(buf);
|
||||
|
||||
if(flags & (1 << 2))
|
||||
buf += 4;
|
||||
if(flags & (1 << 3))
|
||||
buf += 4;
|
||||
|
||||
if(count == 0 || count == 1)
|
||||
this->frag = wld->frags[uint32(buf) - 1]->frag;
|
||||
else {
|
||||
tex = new Texture;
|
||||
tex->frame_count = count;
|
||||
tex->current_frame = 0;
|
||||
tex->archive = nullptr;
|
||||
tex->filenames = new char *[count];
|
||||
tex->flags = 0;
|
||||
|
||||
for(i = 0; i < count; ++i) {
|
||||
texref = (Texture *) wld->frags[uint32(buf) - 1]->frag;
|
||||
tex->filenames[i] = texref->filenames[texref->frame_count - 1];
|
||||
}
|
||||
|
||||
this->frag = tex;
|
||||
}
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data05) {
|
||||
this->frag = wld->frags[uint32(buf) - 1]->frag;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data15) {
|
||||
struct_Data15 *hdr = (struct_Data15 *) buf;
|
||||
Placeable *plac = new Placeable;
|
||||
Placeable **pl;
|
||||
|
||||
plac->x = hdr->trans[0];
|
||||
plac->y = hdr->trans[1];
|
||||
plac->z = hdr->trans[2];
|
||||
|
||||
plac->rx = hdr->rot[2] / 512.f * 360.f;
|
||||
plac->ry = hdr->rot[1] / 512.f * 360.f;
|
||||
plac->rz = hdr->rot[0] / 512.f * 360.f;
|
||||
|
||||
plac->scale[0] = hdr->scale[2];
|
||||
plac->scale[1] = hdr->scale[1];
|
||||
plac->scale[2] = hdr->scale[1];
|
||||
|
||||
plac->model = atoi((const char*)&wld->sHash[-(int)hdr->ref]);
|
||||
|
||||
pl = new Placeable *[wld->model_data.plac_count + 1];
|
||||
memcpy(pl, wld->model_data.placeable, sizeof(Placeable *) * wld->model_data.plac_count);
|
||||
if(wld->model_data.plac_count)
|
||||
delete[] wld->model_data.placeable;
|
||||
pl[wld->model_data.plac_count] = plac;
|
||||
wld->model_data.placeable = pl;
|
||||
++wld->model_data.plac_count;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data1B) {
|
||||
struct_Data1B *data = (struct_Data1B *) buf;
|
||||
Light *light = new Light;
|
||||
this->frag = light;
|
||||
light->x = light->y = light->z = light->rad = 0;
|
||||
if(data->flags & (1 << 3)) {
|
||||
light->r = data->color[0];
|
||||
light->g = data->color[1];
|
||||
light->b = data->color[2];
|
||||
}
|
||||
else
|
||||
light->r = light->g = light->b = 1.0f;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data1C) {
|
||||
this->frag = wld->frags[uint32(buf) - 1]->frag;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data21) {
|
||||
|
||||
struct_Data21 *data;
|
||||
long count = *((long *) buf);
|
||||
long i;
|
||||
|
||||
wld->tree = (BSP_Node *) malloc(count * sizeof(BSP_Node));
|
||||
|
||||
// Build the BSP Tree
|
||||
//
|
||||
for(i = 0; i < count; ++i) {
|
||||
wld->tree[i].node_number=i;
|
||||
data = (struct_Data21 *) (buf + (i * sizeof(struct_Data21)) + 4);
|
||||
wld->tree[i].normal[0] = data->normal[0];
|
||||
wld->tree[i].normal[1] = data->normal[1];
|
||||
wld->tree[i].normal[2] = data->normal[2];
|
||||
wld->tree[i].splitdistance = data->splitdistance;
|
||||
wld->tree[i].region = data->region;
|
||||
wld->tree[i].left = data->node[0];
|
||||
wld->tree[i].right = data->node[1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data22) {
|
||||
|
||||
int pos;
|
||||
|
||||
uchar *data6area ;
|
||||
|
||||
struct_Data22 *data = (struct_Data22 *) buf;
|
||||
|
||||
pos = sizeof(struct_Data22) + (12 * data->size1) + (8 * data->size2);
|
||||
|
||||
|
||||
|
||||
|
||||
data6area = buf + pos;
|
||||
|
||||
if((data->size3!=0)||(data->size4!=0)) {
|
||||
printf("Size 3 and 4 not zero, we can't handle that yet\n");
|
||||
exit(1);
|
||||
}
|
||||
data6area = data6area + ((data->size5) * 7 * 4);
|
||||
|
||||
unsigned short d6size = *((unsigned short *) data6area);
|
||||
data6area = data6area + 2; // Move past d6 size
|
||||
data6area = data6area + d6size; // Move past RLE data ? Hopefully;
|
||||
|
||||
float f1, f2, f3, f4;
|
||||
|
||||
f1 = *((float *) data6area);
|
||||
f2 = *((float *) (data6area+4));
|
||||
f3 = *((float *) (data6area+8));
|
||||
f4 = *((float *) (data6area+12));
|
||||
|
||||
long Frag36Ref;
|
||||
if(data->flags==0x181) {
|
||||
Frag36Ref = *((long *) (data6area+20));
|
||||
//printf("Frag 36 reference?: %ld\n", *((long *) (data6area+20)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data29) {
|
||||
|
||||
long a,flags, numregions, lenstr;
|
||||
|
||||
struct_Data29 *data29 = (struct_Data29 *) malloc(sizeof(struct_Data29));
|
||||
data29->region_type = -1; // Start of by flagging type as unknown
|
||||
|
||||
if(!strncmp((char *) &wld->sHash[-frag_name], "WT", 2)) data29->region_type = 1; // Water
|
||||
else if(!strncmp((char *) &wld->sHash[-frag_name], "LA", 2)) data29->region_type = 2; // Lava
|
||||
else if(!strncmp((char *) &wld->sHash[-frag_name], "DRNTP", 5)) data29->region_type = 3; // Zone Line
|
||||
else if(!strncmp((char *) &wld->sHash[-frag_name], "DRP_", 4)) data29->region_type = 4; // PVP
|
||||
else if(!strncmp((char *) &wld->sHash[-frag_name], "SL", 2)) data29->region_type = 5; // Slippery/Slime ?
|
||||
else if(!strncmp((char *) &wld->sHash[-frag_name], "DRN", 3)) data29->region_type = 6; // Ice/Ice Water
|
||||
else if(!strncmp((char *) &wld->sHash[-frag_name], "VWA", 3)) data29->region_type = 7; // VWater ?
|
||||
|
||||
this->frag = (void *) data29;
|
||||
|
||||
flags = *buf;
|
||||
numregions = *((long *)(buf+4));
|
||||
data29->region_count = numregions ;
|
||||
data29->region_array = (long *)malloc(numregions * sizeof(long));
|
||||
for(a=0;a<numregions;a++) {
|
||||
data29->region_array[a] = *((long *)(buf+8+(a*4)));
|
||||
}
|
||||
lenstr = *((long *)(buf+8+(numregions*4)));
|
||||
data29->strlen=lenstr;
|
||||
if(lenstr==0) return;
|
||||
|
||||
data29->str = (char *)malloc(lenstr);
|
||||
|
||||
char *encstr;
|
||||
|
||||
encstr = (char *)buf+8+(++a*4);
|
||||
|
||||
decode((uchar *)encstr, lenstr);
|
||||
strcpy(data29->str, encstr);
|
||||
// printf(" data2 name is %s\n", data29->str);
|
||||
if(lenstr>=5)
|
||||
if(!strncmp(encstr,"WT",2)) data29->region_type = 1; // Water
|
||||
else if(!strncmp(encstr,"LA",2)) data29->region_type = 2; // Lava
|
||||
else if(!strncmp(encstr,"DRNTP",5)) data29->region_type = 3; // Zone Line ?
|
||||
else if(!strncmp(encstr,"DRP_",4)) data29->region_type = 4; //PVP
|
||||
else if(!strncmp(encstr,"SL",2)) data29->region_type = 5; // Slippery/Slime ?
|
||||
else if(!strncmp(encstr,"DRN",3)) data29->region_type = 6; // Ice/Ice Water ?
|
||||
else if(!strncmp(encstr,"VWN",3)) data29->region_type = 7; // Ice/Ice Water ?
|
||||
else data29->region_type = -2; // Flag this so that it doesn't get set to the default water or lava
|
||||
// later, because it is neither.
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data28) {
|
||||
// struct_Data28 *data = (struct_Data28 *) buf; // obviously unused for now.
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data30) {
|
||||
struct_Data30 *data;
|
||||
uint32 ref;
|
||||
Texture *tex;
|
||||
|
||||
data = (struct_Data30 *) buf;
|
||||
|
||||
buf += sizeof(struct_Data30);
|
||||
|
||||
if(!data->flags)
|
||||
buf += 8;
|
||||
|
||||
ref = uint32(buf);
|
||||
|
||||
if(!data->params1 || !ref) {
|
||||
tex = new Texture;
|
||||
tex->frame_count = 1;
|
||||
tex->current_frame = 0;
|
||||
tex->filenames = new char *[1];
|
||||
tex->filenames[0] = "collide.dds";
|
||||
tex->archive = nullptr;
|
||||
tex->flags = 1;
|
||||
this->frag = (void *) tex;
|
||||
return;
|
||||
}
|
||||
|
||||
tex = (Texture *) wld->frags[ref - 1]->frag;
|
||||
|
||||
if(data->params1 & (1 << 1) || data->params1 & (1 << 2) || data->params1 & (1 << 3) || data->params1 & (1 << 4))
|
||||
tex->flags = 1;
|
||||
else
|
||||
tex->flags = 0;
|
||||
|
||||
this->frag = (void *) tex;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data31) {
|
||||
TexRef *tr;
|
||||
int i, count;
|
||||
|
||||
buf += 4;
|
||||
count = uint32(buf);
|
||||
|
||||
tr = new TexRef;
|
||||
tr->tex_count = count;
|
||||
tr->tex = new Texture *[count];
|
||||
|
||||
for(i = 0; i < count; ++i)
|
||||
tr->tex[i] = (Texture *) wld->frags[uint32(buf) - 1]->frag;
|
||||
|
||||
this->frag = (void *) tr;
|
||||
}
|
||||
|
||||
FRAG_CONSTRUCTOR(Data36) {
|
||||
struct_Data36 *header = (struct_Data36 *) buf;
|
||||
Poly *p;
|
||||
TexCoordsNew *tex_new;
|
||||
TexCoordsOld *tex_old;
|
||||
VertexNormal *vn;
|
||||
Vert *v;
|
||||
|
||||
|
||||
|
||||
TexRef *tr;
|
||||
|
||||
Model *model;
|
||||
Vertex *vert;
|
||||
Polygon *poly;
|
||||
|
||||
float scale = 1.0f / (float) (1 << header->scale);
|
||||
|
||||
int i, j, pc;
|
||||
TexMap *tm;
|
||||
|
||||
float recip_255 = 1.0f / 256.0f, recip_127 = 1.0f / 127.0f;
|
||||
|
||||
buf += sizeof(struct_Data36);
|
||||
|
||||
model = new Model;
|
||||
model->vert_count = header->vertexCount;
|
||||
model->poly_count = header->PolygonsCount;
|
||||
model->verts = new Vertex *[model->vert_count];
|
||||
model->polys = new Polygon *[model->poly_count];
|
||||
tr = (TexRef *) wld->frags[header->fragment1 - 1]->frag;
|
||||
model->tex = tr->tex; // Reference to type 0x31 Texture List fragment
|
||||
model->tex_count = tr->tex_count;
|
||||
model->name = (char *) &wld->sHash[-frag_name];
|
||||
|
||||
#ifdef DEBUGWLD
|
||||
|
||||
printf("Frag 0x36, %4d Vertices, %4d Polys, %4d TexCoords, %4d Normals, %3d Colors, %3d Polytex, %3d VertexTex, Name %s\n",
|
||||
header->vertexCount, header->PolygonsCount, header->texCoordsCount, header->normalsCount, header->colorCount, header->PolygonTexCount, header->vertexTexCount, model->name);
|
||||
#endif
|
||||
|
||||
for(i = 0; i < header->vertexCount; ++i) {
|
||||
v = (Vert *) buf;
|
||||
|
||||
vert = model->verts[i] = new Vertex;
|
||||
|
||||
vert->x = header->centerX + v->x * scale;
|
||||
vert->y = header->centerY + v->y * scale;
|
||||
vert->z = header->centerZ + v->z * scale;
|
||||
#ifdef DEBUGWLD2
|
||||
printf(" Vertex %4d: X=%4.2f, Y=%4.2f, Z=%4.2f\n", i, vert->x, vert->y, vert->z);
|
||||
#endif
|
||||
|
||||
buf += sizeof(Vert);
|
||||
}
|
||||
|
||||
if(wld->old) {
|
||||
for(i = 0; i < header->texCoordsCount; ++i) {
|
||||
tex_old = (TexCoordsOld *) buf;
|
||||
vert = model->verts[i];
|
||||
|
||||
vert->u = (float) tex_old->tx * recip_255;
|
||||
vert->v = (float) tex_old->tz * recip_255;
|
||||
|
||||
#ifdef DEBUGWLD2
|
||||
printf(" TexCoord %4d: U=%4.2f, V=%4.2f\n", i, vert->u, vert->v);
|
||||
#endif
|
||||
|
||||
buf += sizeof(TexCoordsOld);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(i = 0; i < header->texCoordsCount; ++i) {
|
||||
tex_new = (TexCoordsNew *) buf;
|
||||
vert = model->verts[i];
|
||||
|
||||
vert->u = tex_new->tx;
|
||||
vert->v = tex_new->tz;
|
||||
|
||||
#ifdef DEBUGWLD2
|
||||
printf(" TexCoord %4d: U=%4.2f, V=%4.2f\n", i, vert->u, vert->v);
|
||||
#endif
|
||||
buf += sizeof(TexCoordsNew);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < header->normalsCount; ++i) {
|
||||
|
||||
if(i<header->vertexCount) {
|
||||
vn = (VertexNormal *) buf;
|
||||
vert = model->verts[i];
|
||||
|
||||
vert->i = (float) vn->nx * recip_127;
|
||||
vert->j = (float) vn->ny * recip_127;
|
||||
vert->k = (float) vn->nz * recip_127;
|
||||
}
|
||||
|
||||
buf += sizeof(VertexNormal);
|
||||
}
|
||||
|
||||
buf += 4 * header->colorCount;
|
||||
|
||||
for(i = 0; i < header->PolygonsCount; ++i) {
|
||||
p = (Poly *) buf;
|
||||
|
||||
poly = model->polys[i] = new Polygon;
|
||||
|
||||
poly->flags = p->flags;
|
||||
// Derision: 16/06/08
|
||||
// Previously, this was assigning v1=v1, v2=v3, v3=v2. This is different to how it was done
|
||||
// in the WLD loader in the stock azone, and has the effect of screwing up the normals,
|
||||
// Changed to keep things consistent with prior versions.
|
||||
poly->v1 = p->v1;
|
||||
poly->v2 = p->v2;
|
||||
poly->v3 = p->v3;
|
||||
#ifdef DEBUGWLD2
|
||||
printf("Frag36: Polygon: %5d Vertices: %5d, %5d, %5d\n", i, poly->v1, poly->v2, poly->v3);
|
||||
#endif
|
||||
buf += sizeof(Poly);
|
||||
}
|
||||
|
||||
buf += 4 * header->size6;
|
||||
|
||||
pc = 0;
|
||||
|
||||
// For each polygontex entry ...
|
||||
for(i = 0; i < header->PolygonTexCount; ++i) {
|
||||
tm = (TexMap *) buf;
|
||||
|
||||
for(j = 0; j < tm->polycount; ++j) {
|
||||
if(pc>=(model->poly_count)) {
|
||||
break; // Derision: Crashing here in acrylia because of this. TODO: Find root cause, for now, this lets zone load
|
||||
}
|
||||
// there are tm->polycount consecutive polys that use this tex
|
||||
model->polys[pc++]->tex = tm->tex;
|
||||
}
|
||||
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUGWLD
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
this->frag = (void *) model;
|
||||
}
|
||||
|
||||
WLDLoader::WLDLoader() {
|
||||
}
|
||||
|
||||
WLDLoader::~WLDLoader() {
|
||||
this->Close();
|
||||
}
|
||||
|
||||
int WLDLoader::Open(char *base_path, char *zone_name, Archive *archive) {
|
||||
uchar *buffer;
|
||||
int buf_len;
|
||||
int i, j, vc, pc, bc, mlen, *pmap;
|
||||
Zone_Model *zm;
|
||||
Model *m;
|
||||
|
||||
Archive *obj_archive;
|
||||
|
||||
char *filename, *model_name;
|
||||
|
||||
struct_wld_header *header;
|
||||
struct_wld_basic_frag *frag;
|
||||
|
||||
#ifdef DEBUGWLD
|
||||
printf("Zone: %s\n", zone_name);
|
||||
#endif
|
||||
this->model_data.zone_model = nullptr;
|
||||
|
||||
this->model_data.plac_count = 0;
|
||||
this->model_data.placeable = 0;
|
||||
|
||||
this->obj_loader = this->plac_loader = nullptr;
|
||||
|
||||
this->clear_plac = 0;
|
||||
|
||||
filename = new char[strlen(zone_name) + 5];
|
||||
sprintf(filename, "%s.wld", zone_name);
|
||||
|
||||
if(!GetFile(&buffer, &buf_len, nullptr, filename, archive)) {
|
||||
delete[] filename;
|
||||
return 0;
|
||||
}
|
||||
delete[] filename;
|
||||
|
||||
header = (struct_wld_header *) buffer;
|
||||
|
||||
if(header->magic != 0x54503d02)
|
||||
return 0;
|
||||
|
||||
buffer += sizeof(struct_wld_header);
|
||||
|
||||
this->sHash = buffer;
|
||||
decode(this->sHash, header->stringHashSize);
|
||||
buffer += header->stringHashSize;
|
||||
|
||||
if(header->version == 0x00015500)
|
||||
this->old = 1;
|
||||
else
|
||||
this->old = 0;
|
||||
|
||||
this->fragcount = header->fragmentCount;
|
||||
this->frags = new Fragment *[header->fragmentCount];
|
||||
|
||||
|
||||
for(i = 0; i < this->fragcount; ++i) {
|
||||
frag = (struct_wld_basic_frag *) buffer;
|
||||
|
||||
buffer += sizeof(struct_wld_basic_frag);
|
||||
|
||||
switch(frag->id) {
|
||||
case 0x03: FRAGMENT(Data03); break;
|
||||
case 0x04: FRAGMENT(Data04); break;
|
||||
case 0x05: FRAGMENT(Data05); break;
|
||||
case 0x15: FRAGMENT(Data15); break;
|
||||
case 0x1B: FRAGMENT(Data1B); break;
|
||||
case 0x1C: FRAGMENT(Data1C); break;
|
||||
case 0x21: FRAGMENT(Data21); break;
|
||||
case 0x22: FRAGMENT(Data22); break;
|
||||
case 0x29: FRAGMENT(Data29); break;
|
||||
case 0x28: FRAGMENT(Data28); break;
|
||||
case 0x30: FRAGMENT(Data30); break;
|
||||
case 0x31: FRAGMENT(Data31); break;
|
||||
case 0x36: FRAGMENT(Data36); break;
|
||||
|
||||
default: this->frags[i] = new Fragment; break;
|
||||
}
|
||||
|
||||
this->frags[i]->type = frag->id;
|
||||
this->frags[i]->name = frag->nameRef;
|
||||
|
||||
buffer += frag->size - 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if(!strcmp(&zone_name[strlen(zone_name) - 4], "_obj")) {
|
||||
this->model_data.plac_count = 0;
|
||||
this->model_data.model_count = 0;
|
||||
// for an obj_s3d file, find out how many placeabale objects there are (each 0x36 Frag is a placeable object in an obj_s3d file
|
||||
for(i = 0; i < this->fragcount; ++i) {
|
||||
if(this->frags[i]->type == 0x36)
|
||||
++this->model_data.model_count;
|
||||
}
|
||||
// allocate space for this many models
|
||||
this->model_data.models = new Model *[this->model_data.model_count];
|
||||
this->model_data.model_count = 0;
|
||||
for(i = 0; i < this->fragcount; ++i) {
|
||||
if(this->frags[i]->type == 0x36)
|
||||
this->model_data.models[this->model_data.model_count++] = (Model *) this->frags[i]->frag;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(&zone_name[strlen(zone_name) - 4], "_chr")) {
|
||||
}
|
||||
else if(!strcmp(zone_name, "objects")) {
|
||||
this->clear_plac = 1;
|
||||
}
|
||||
else {
|
||||
// We are procesing the zone mesh S3D
|
||||
zm = this->model_data.zone_model = new Zone_Model;
|
||||
zm->vert_count = 0;
|
||||
zm->poly_count = 0;
|
||||
for(i = 0; i < this->fragcount; ++i) {
|
||||
if(this->frags[i]->type != 0x36)
|
||||
continue;
|
||||
m = (Model *) this->frags[i]->frag;
|
||||
zm->vert_count += m->vert_count;
|
||||
zm->poly_count += m->poly_count;
|
||||
zm->tex_count = m->tex_count; // The texcount and tex fields are the same for every 0x36 frag in the zone mesh S3D
|
||||
zm->tex = m->tex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
zm->verts = new Vertex *[zm->vert_count];
|
||||
zm->polys = new Polygon *[zm->poly_count];
|
||||
|
||||
vc = pc = 0;
|
||||
|
||||
for(i = 0; i < this->fragcount; ++i) {
|
||||
if(this->frags[i]->type != 0x36)
|
||||
continue;
|
||||
m = (Model *) this->frags[i]->frag;
|
||||
bc = vc;
|
||||
// Copy the vertexes from the 0x36 frag into our zone model
|
||||
for(j = 0; j < m->vert_count; ++j)
|
||||
zm->verts[vc++] = m->verts[j];
|
||||
// Adjust the polygon vertices indices to match the indices in our zone model vertex array
|
||||
for(j = 0; j < m->poly_count; ++j) {
|
||||
m->polys[j]->v1 += bc;
|
||||
m->polys[j]->v2 += bc;
|
||||
m->polys[j]->v3 += bc;
|
||||
#ifdef DEBUGWLD
|
||||
printf("Polygon: %5d Vertices %5d, %5d, %5d\n", j,
|
||||
m->polys[j]->v1, m->polys[j]->v2, m->polys[j]->v3);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGWLD
|
||||
printf("Zone Frag36 No. %5d: Poly %5d V3 = %4.3f, %4.3f, %4.3f\n", i, j, zm->verts[m->polys[j]->v3]->x, zm->verts[m->polys[j]->v3]->y, zm->verts[m->polys[j]->v3]->z);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
zm->polys[pc++] = m->polys[j];
|
||||
}
|
||||
}
|
||||
|
||||
this->model_data.plac_count = 0;
|
||||
this->model_data.model_count = 0;
|
||||
|
||||
filename = new char[strlen(zone_name) + 10];
|
||||
sprintf(filename, "%s_obj.s3d",zone_name);
|
||||
|
||||
obj_archive = new PFSLoader;
|
||||
if(!obj_archive->Open(fopen(filename, "rb"))) {
|
||||
// printf("_obj.s3d file not found.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
delete[] filename;
|
||||
|
||||
filename = new char[strlen(zone_name) + 5];
|
||||
sprintf(filename, "%s_obj", zone_name);
|
||||
|
||||
this->obj_loader = new WLDLoader();
|
||||
this->obj_loader->Open(nullptr, filename, obj_archive);
|
||||
|
||||
delete[] filename;
|
||||
|
||||
this->model_data.model_count = this->obj_loader->model_data.model_count;
|
||||
this->model_data.models = this->obj_loader->model_data.models;
|
||||
|
||||
this->plac_loader = new WLDLoader();
|
||||
this->plac_loader->Open(nullptr, "objects", archive);
|
||||
|
||||
if(this->model_data.plac_count) {
|
||||
delete this->model_data.placeable[0];
|
||||
delete[] this->model_data.placeable;
|
||||
}
|
||||
|
||||
this->model_data.plac_count = this->plac_loader->model_data.plac_count;
|
||||
this->model_data.placeable = this->plac_loader->model_data.placeable;
|
||||
|
||||
|
||||
for(i = 0; i < this->model_data.plac_count; ++i) {
|
||||
mlen = strlen((char *) this->model_data.placeable[i]->model) - 8;
|
||||
model_name = new char[mlen + 12];
|
||||
memcpy(model_name, (char *) this->model_data.placeable[i]->model, mlen);
|
||||
model_name[mlen] = 0;
|
||||
sprintf(model_name, "%sDMSPRITEDEF", model_name);
|
||||
this->model_data.placeable[i]->model = -1;
|
||||
|
||||
for(j = 0; j < this->model_data.model_count; ++j) {
|
||||
if(!strcmp(this->model_data.models[j]->name, model_name)) {
|
||||
this->model_data.placeable[i]->model = j;
|
||||
// printf("Placeable object %d name is %s\n", j, model_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
delete[] model_name;
|
||||
}
|
||||
|
||||
for(i = 0; i < this->model_data.model_count; ++i) {
|
||||
for(j = 0; j < this->model_data.models[i]->tex_count; ++j)
|
||||
this->model_data.models[i]->tex[j]->archive = obj_archive;
|
||||
}
|
||||
|
||||
for(i = 0; i < this->model_data.model_count; ++i) {
|
||||
pmap = new int[this->model_data.models[i]->poly_count];
|
||||
memset(pmap, 0, sizeof(int) * this->model_data.models[i]->poly_count);
|
||||
for(j = 0; j < this->model_data.models[i]->tex_count; ++j) {
|
||||
filename = this->model_data.models[i]->tex[j]->filenames[0];
|
||||
for(bc = 0; bc < this->model_data.zone_model->tex_count; ++bc) {
|
||||
if(!strcmp(filename, this->model_data.zone_model->tex[bc]->filenames[0])) {
|
||||
for(pc = 0; pc < this->model_data.models[i]->poly_count; ++pc) {
|
||||
if(!pmap[pc] && this->model_data.models[i]->polys[pc]->tex == j) {
|
||||
this->model_data.models[i]->polys[pc]->tex = bc;
|
||||
pmap[pc] = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] pmap;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WLDLoader::Close() {
|
||||
int i, j;
|
||||
Zone_Model *zm = this->model_data.zone_model;
|
||||
Model *m;
|
||||
|
||||
return -1;
|
||||
|
||||
if(zm) {
|
||||
for(j = 0; j < zm->tex_count; ++j)
|
||||
delete zm->tex[j];
|
||||
delete[] zm->tex;
|
||||
|
||||
delete[] zm->verts;
|
||||
delete[] zm->polys;
|
||||
}
|
||||
|
||||
for(i = 0; i < this->fragcount; ++i) {
|
||||
if(this->frags[i]->type == 0x36) {
|
||||
m = (Model *) this->frags[i]->frag;
|
||||
|
||||
for(j = 0; j < m->vert_count; ++j)
|
||||
delete m->verts[j];
|
||||
for(j = 0; j < m->poly_count; ++j)
|
||||
delete m->polys[j];
|
||||
|
||||
if(!zm) {
|
||||
for(j = 0; j < m->tex_count; ++j)
|
||||
delete m->tex[j];
|
||||
delete[] m->tex;
|
||||
}
|
||||
|
||||
delete[] m->verts;
|
||||
delete[] m->polys;
|
||||
delete m;
|
||||
}
|
||||
else
|
||||
delete this->frags[i];
|
||||
}
|
||||
delete[] this->frags;
|
||||
|
||||
if(this->clear_plac) {
|
||||
// for(i = 0; i < this->model_data.plac_count; ++i)
|
||||
// delete[] this->model_data.placeable[i];
|
||||
}
|
||||
|
||||
delete[] this->model_data.placeable;
|
||||
|
||||
delete this->obj_loader;
|
||||
delete this->plac_loader;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef __OPENEQ_WLD__
|
||||
#define __OPENEQ_WLD__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include "file_loader.hpp"
|
||||
|
||||
#include "wld_structs.hpp"
|
||||
|
||||
#include "3d.hpp"
|
||||
|
||||
#define FRAGMENT(name) \
|
||||
this->frags[i] = new name(this, buffer, frag->size, frag->nameRef);
|
||||
|
||||
class TexRef {
|
||||
public:
|
||||
Texture **tex;
|
||||
int tex_count;
|
||||
};
|
||||
|
||||
class Fragment {
|
||||
public:
|
||||
Fragment() {}
|
||||
virtual ~Fragment() {}
|
||||
|
||||
int type, name;
|
||||
void *frag;
|
||||
};
|
||||
|
||||
class WLDLoader : public FileLoader {
|
||||
public:
|
||||
WLDLoader();
|
||||
~WLDLoader();
|
||||
|
||||
virtual int Open(char *base_path, char *zone_name, Archive *archive);
|
||||
virtual int Close();
|
||||
|
||||
int fragcount;
|
||||
Fragment **frags;
|
||||
BSP_Node *tree;
|
||||
|
||||
uchar *sHash;
|
||||
|
||||
char old;
|
||||
|
||||
WLDLoader *obj_loader;
|
||||
WLDLoader *plac_loader;
|
||||
|
||||
char clear_plac;
|
||||
};
|
||||
|
||||
#define FRAG_CLASS(name) \
|
||||
class name : public Fragment { \
|
||||
public: \
|
||||
name(WLDLoader *wld, uchar *buf, int len, int frag_name); \
|
||||
~name() {}; \
|
||||
}
|
||||
|
||||
#define FRAG_CONSTRUCTOR(name) \
|
||||
name::name(WLDLoader *wld, uchar *buf, int len, int frag_name)
|
||||
|
||||
#define FRAG_DECONSTRUCTOR(name) \
|
||||
name::~name()
|
||||
|
||||
FRAG_CLASS(Data03);
|
||||
FRAG_CLASS(Data04);
|
||||
FRAG_CLASS(Data05);
|
||||
FRAG_CLASS(Data15);
|
||||
FRAG_CLASS(Data1B);
|
||||
FRAG_CLASS(Data1C);
|
||||
FRAG_CLASS(Data21);
|
||||
FRAG_CLASS(Data22);
|
||||
FRAG_CLASS(Data29);
|
||||
FRAG_CLASS(Data28);
|
||||
FRAG_CLASS(Data30);
|
||||
FRAG_CLASS(Data31);
|
||||
FRAG_CLASS(Data36);
|
||||
|
||||
void DoubleLinkBSP(BSP_Node *tree, long node_number, long parent);
|
||||
long BSPMarkRegion(BSP_Node *tree, long node_number, long region, int region_type);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,137 @@
|
||||
#ifndef __OPENEQ_WLD_STRUCTS__
|
||||
#define __OPENEQ_WLD_STRUCTS__
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct struct_wld_header {
|
||||
long magic;
|
||||
long version;
|
||||
long fragmentCount;
|
||||
long header3;
|
||||
long header4;
|
||||
long stringHashSize;
|
||||
long header6;
|
||||
} typedef struct_wld_header;
|
||||
|
||||
struct struct_wld_basic_frag {
|
||||
long size;
|
||||
long id;
|
||||
long nameRef;
|
||||
} typedef struct_wld_basic_frag;
|
||||
|
||||
|
||||
struct struct_Data15 {
|
||||
uint32 ref, flags, fragment1;
|
||||
float trans[3], rot[3];
|
||||
float scale[3];
|
||||
uint32 fragment2, flags2;
|
||||
} typedef struct_Data15;
|
||||
|
||||
struct struct_Data36 {
|
||||
long flags;
|
||||
long fragment1;
|
||||
long fragment2;
|
||||
long fragment3;
|
||||
long fragment4;
|
||||
float centerX;
|
||||
float centerY;
|
||||
float centerZ;
|
||||
long params2[3]; // 48
|
||||
float maxDist;
|
||||
float minX;
|
||||
float minY;
|
||||
float minZ;
|
||||
float maxX;
|
||||
float maxY;
|
||||
float maxZ; // 24
|
||||
short int vertexCount;
|
||||
short int texCoordsCount;
|
||||
short int normalsCount;
|
||||
short int colorCount;
|
||||
short int PolygonsCount;
|
||||
short int size6;
|
||||
short int PolygonTexCount;
|
||||
short int vertexTexCount;
|
||||
short int size9;
|
||||
short int scale; // 20
|
||||
} typedef struct_Data36;
|
||||
|
||||
struct struct_Data10 {
|
||||
long flags, size1, fragment;
|
||||
} typedef struct_Data10;
|
||||
|
||||
struct struct_Data1B {
|
||||
uint32 flags, params1;
|
||||
uint32 params3b;
|
||||
float color[3];
|
||||
} typedef struct_Data1B;
|
||||
|
||||
struct struct_Data21 {
|
||||
float normal[3], splitdistance;
|
||||
long region, node[2];
|
||||
} typedef struct_Data21;
|
||||
|
||||
struct struct_Data22 {
|
||||
long flags, fragment1, size1, size2, params1, size3, size4, params2, size5, size6;
|
||||
} typedef struct_Data22;
|
||||
|
||||
struct struct_Data28 {
|
||||
uint32 flags;
|
||||
float x, y, z, rad;
|
||||
} typedef struct_Data28;
|
||||
|
||||
typedef struct struct_Data29 {
|
||||
long region_count;
|
||||
long *region_array;
|
||||
long strlen;
|
||||
char *str;
|
||||
int region_type; // We fill this in with -1 for unknown, 1 for water, 2 for lava
|
||||
} struct_Data29;
|
||||
|
||||
|
||||
struct struct_Data30 {
|
||||
uint32 flags, params1, params2;
|
||||
float params3[2];
|
||||
} typedef struct_Data30;
|
||||
|
||||
typedef struct BSP_Node {
|
||||
long node_number;
|
||||
float normal[3], splitdistance;
|
||||
long region;
|
||||
int special;
|
||||
long left, right;
|
||||
} BSP_Node;
|
||||
|
||||
|
||||
struct Vert {
|
||||
signed short int x, y, z;
|
||||
} typedef Vert;
|
||||
|
||||
struct TexCoordsNew {
|
||||
float tx, tz;
|
||||
} typedef TexCoordsNew;
|
||||
|
||||
struct TexCoordsOld {
|
||||
signed short int tx, tz;
|
||||
} typedef TexCoordsOld;
|
||||
|
||||
struct VertexNormal {
|
||||
signed char nx, ny, nz;
|
||||
} typedef VertexNormal;
|
||||
|
||||
struct VertexColor {
|
||||
char color[4];
|
||||
} typedef VertexColor;
|
||||
|
||||
struct Poly {
|
||||
short int flags, v1, v2, v3;
|
||||
} typedef Poly;
|
||||
|
||||
struct TexMap {
|
||||
uint16 polycount;
|
||||
uint16 tex;
|
||||
} typedef TexMap;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,433 @@
|
||||
|
||||
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "3d.hpp"
|
||||
#include "zon.hpp"
|
||||
//#define DEBUGEQG
|
||||
//#define DEBUGPLAC
|
||||
|
||||
ZonLoader::ZonLoader() {
|
||||
this->buffer = nullptr;
|
||||
this->buf_len = -1;
|
||||
this->archive = nullptr;
|
||||
this->status = 0;
|
||||
}
|
||||
|
||||
ZonLoader::~ZonLoader() {
|
||||
this->Close();
|
||||
}
|
||||
|
||||
int ZonLoader::Open(char *base_path, char *zone_name, Archive *archive) {
|
||||
uchar *buffer, *orig_buffer;
|
||||
int buf_len;
|
||||
|
||||
Texture **tex;
|
||||
int tex_count, tex_tmp, *tex_map;
|
||||
|
||||
int i, j, k, l;
|
||||
char **model_names;
|
||||
|
||||
char *filename;
|
||||
|
||||
uchar *zon_tmp, *zon_orig;
|
||||
|
||||
float rot_change = 180.0f / 3.14159f;
|
||||
// float rot_change = 1.0f;
|
||||
float base[3];
|
||||
|
||||
#ifdef DEBUGEQG
|
||||
printf("Attempting to load EQG %s\n", zone_name);
|
||||
#endif
|
||||
filename = new char[strlen(zone_name) + 5];
|
||||
//sprintf(filename, "%s.zon", zone_name);
|
||||
// Derision: .zon name is not always the same as the EQG base name. Added wildcard ability to the PFS GetFile
|
||||
// routine.
|
||||
sprintf(filename, "*.zon");
|
||||
#ifdef DEBUGEQG
|
||||
printf("Looking for ZON file %s\n", filename);
|
||||
archive->GetFile("*.zon", &buffer, &buf_len);
|
||||
#endif
|
||||
if(!archive->GetFile(filename, &buffer, &buf_len)) {
|
||||
#ifdef DEBUGEQG
|
||||
printf("Couldn't find ZON file\n");
|
||||
printf("%s\n", zone_name);
|
||||
#endif
|
||||
// Look in the filesystem for the .ZON file.
|
||||
char *FSZonName = new char[strlen(zone_name) + 6];
|
||||
sprintf(FSZonName, "%s.zon", zone_name);
|
||||
// Hack incoming for westkorlach zones because the zon filename for e.g. westkorlacha is westkorlachA
|
||||
if(!strncmp(FSZonName, "westkorlach", 11))
|
||||
FSZonName[11] = toupper(FSZonName[11]);
|
||||
printf(".ZON file not found inside EQG. Looking for %s in filesystem. ", FSZonName);
|
||||
FILE *FSZon = fopen(FSZonName, "rb");
|
||||
|
||||
delete [] FSZonName;
|
||||
|
||||
if(FSZon) {
|
||||
printf("Found.\n");
|
||||
fseek(FSZon, 0, SEEK_END);
|
||||
long FSZonSize = ftell(FSZon);
|
||||
fseek(FSZon, 0, SEEK_SET);
|
||||
// printf("File size is %d\n", FSZonSize);
|
||||
buffer = new uchar[FSZonSize];
|
||||
fread(buffer, FSZonSize, 1, FSZon);
|
||||
// printf("Read file\n");
|
||||
}
|
||||
else {
|
||||
printf("\n.ZON file not present inside EQG file. Did not find it in the filesystem either.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
delete[] filename;
|
||||
|
||||
orig_buffer = buffer;
|
||||
|
||||
zon_header *hdr = (zon_header *) buffer;
|
||||
zon_placeable *plac;
|
||||
|
||||
if(hdr->magic[0] != 'E' || hdr->magic[1] != 'Q' || hdr->magic[2] != 'G' || hdr->magic[3] != 'Z')
|
||||
return 0;
|
||||
|
||||
buffer += sizeof(zon_header);
|
||||
|
||||
// The original OpenEQ code I found assumed the first filename was the .TER file. This
|
||||
// is not always the case.
|
||||
//
|
||||
|
||||
#ifdef DEBUGEQG
|
||||
printf("Seeking .TER file\n");
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
uchar *StartOfModelNames = buffer;
|
||||
while(strcmp((char *)(buffer+strlen((char *)buffer))-3, "TER"))
|
||||
buffer += strlen((char *)buffer) + 1;
|
||||
|
||||
#ifdef DEBUGEQG
|
||||
printf("Found .TER file %s\n", (char *)buffer);
|
||||
#endif
|
||||
this->terloader.Open(nullptr, (char *) buffer, archive);
|
||||
buffer = StartOfModelNames;
|
||||
this->model_data.zone_model = terloader.model_data.zone_model;
|
||||
|
||||
// Derision:
|
||||
// After the ZON header, there is a list of strings like this (using guildhall.EQG as an example)
|
||||
// TER_GuildHall.TER
|
||||
// TER_GuildHall
|
||||
// OBJ_sun_frame.MOD
|
||||
// OBJ_sun_frame
|
||||
// OBJ_chandelier.MOD
|
||||
// OBJ_chandelier
|
||||
// OBJ_key_door_open_.MOD
|
||||
// OBJ_key_door_open_01
|
||||
// OBJ_key_door_open_02
|
||||
// OBJ_key_door_.MOD
|
||||
// OBJ_key_door_01
|
||||
// OBJ_key_door_02
|
||||
// OBJ_key_door_03
|
||||
//
|
||||
// This format appears to be Mesh (model) filename, followed by a list of objects that use that model.
|
||||
// So we have the zone model (ground mesh), i.e. the .TER file, which is used by object 'TER_Guildhall',
|
||||
// then a list of placeable models. It would appear that one .MOD file can be used by multiple objects,
|
||||
// i.e. the key_door_open and key_door models in the example above.
|
||||
//
|
||||
// After this list, there is a list of hdr->NumberOfModels longs, one for each Model. Each long is an offset into
|
||||
// the list above, pointing to the .MOD file for that model.
|
||||
|
||||
zon_orig = buffer;
|
||||
zon_tmp = buffer + hdr->list_len;
|
||||
|
||||
// Create an array of Model filenames and populate it using the offsets
|
||||
//
|
||||
buffer = zon_orig + hdr->list_len;
|
||||
model_names = new char *[hdr->NumberOfModels];
|
||||
for(int ModelNumber=0; ModelNumber< hdr->NumberOfModels; ModelNumber++) {
|
||||
long offset = *((long *)(buffer+ModelNumber*4));
|
||||
model_names[ModelNumber] = (char *)(zon_orig + offset);
|
||||
//
|
||||
// Derision: 23/06/08
|
||||
// dranikcatacombsa.eqg has a couple of model names with a left parenthesis where there should
|
||||
// be an underscore. E.g. OBP_DZ_Lbanner0)_00.MOD instead of OBP_DZ_Lbanner0__00.MOD
|
||||
// This is the only zone I have seen this in, but is the reason for the follow code to replace
|
||||
// the parenthesis with an underscore.
|
||||
//
|
||||
for(unsigned int i=0; i<strlen(model_names[ModelNumber]); i++)
|
||||
if(model_names[ModelNumber][i] == ')') {
|
||||
model_names[ModelNumber][i] = '_';
|
||||
printf("***** Replacing parenthesis with underscore in model name %s\n", model_names[ModelNumber]);
|
||||
}
|
||||
// printf("Model name %d is %s\n", ModelNumber, model_names[ModelNumber]);
|
||||
}
|
||||
this->model_data.model_count = hdr->NumberOfModels;
|
||||
#if defined(DEBUGEQG) || defined(DEBUGPLAC)
|
||||
printf("model_data.model_count is %d\n", this->model_data.model_count);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
this->model_data.models = new Model *[this->model_data.model_count];
|
||||
|
||||
|
||||
|
||||
// Skip over the
|
||||
buffer = zon_orig + hdr->list_len + hdr->NumberOfModels * 4;
|
||||
|
||||
this->model_data.plac_count = hdr->obj_count - 1;
|
||||
/*
|
||||
if(hdr->version > 1) {
|
||||
// Don't understand the complete format of version 2 zons
|
||||
this->model_data.plac_count = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef DEBUGPLAC
|
||||
printf(" Placeable count is %d\n", this->model_data.plac_count);
|
||||
#endif
|
||||
this->model_data.placeable = new Placeable *[this->model_data.plac_count];
|
||||
|
||||
plac = (zon_placeable *) buffer;
|
||||
base[0] = plac->x;
|
||||
base[1] = plac->y;
|
||||
base[2] = plac->z;
|
||||
|
||||
// printf("(%f %f %f) (%f %f %f)\n", plac->x, plac->y, plac->z, plac->rz, plac->ry, plac->rx);
|
||||
|
||||
buffer += sizeof(zon_placeable);
|
||||
|
||||
if(hdr->version > 1) {
|
||||
long UnknownSize = *((long *)(buffer));
|
||||
// printf("Unknown Size is %d\n", UnknownSize);
|
||||
buffer = buffer + 4 + (UnknownSize * 4);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUGEQG
|
||||
printf("TER.CPP:107 model_data.plac_count is %d\n", this->model_data.plac_count);
|
||||
#endif
|
||||
|
||||
|
||||
for(i = 0; i < this->model_data.plac_count; ++i) {
|
||||
plac = (zon_placeable *) buffer;
|
||||
|
||||
zon_tmp = zon_orig + plac->loc;
|
||||
|
||||
this->model_data.placeable[i] = new Placeable;
|
||||
this->model_data.placeable[i]->model = plac->id ;
|
||||
this->model_data.placeable[i]->x = plac->x;
|
||||
this->model_data.placeable[i]->y = plac->y;
|
||||
this->model_data.placeable[i]->z = plac->z;
|
||||
this->model_data.placeable[i]->rx = plac->rz * rot_change;
|
||||
this->model_data.placeable[i]->ry = plac->ry * rot_change;
|
||||
this->model_data.placeable[i]->rz = plac->rx * rot_change;
|
||||
|
||||
this->model_data.placeable[i]->scale[0] = plac->scale;
|
||||
this->model_data.placeable[i]->scale[1] = plac->scale;
|
||||
this->model_data.placeable[i]->scale[2] = plac->scale;
|
||||
#ifdef DEBUG_MODE
|
||||
printf("%s (%f %f %f) (%f %f %f) %f\n",
|
||||
zon_tmp,
|
||||
this->model_data.placeable[i]->x,
|
||||
this->model_data.placeable[i]->y,
|
||||
this->model_data.placeable[i]->z,
|
||||
this->model_data.placeable[i]->rx,
|
||||
this->model_data.placeable[i]->ry,
|
||||
this->model_data.placeable[i]->rz,
|
||||
this->model_data.placeable[i]->scale);
|
||||
#endif
|
||||
if(this->model_data.placeable[i]->model == -1) {
|
||||
printf("Unable to find model for offset %5ld\n", plac->loc);
|
||||
}
|
||||
|
||||
#ifdef DEBUGPLAC
|
||||
printf(" Placeable object %i Model no. %d at (%4.2f, %4.2f, %4.2f)\n", i, this->model_data.placeable[i]->model, plac->x,plac->y, plac->z);
|
||||
#endif
|
||||
buffer += sizeof(zon_placeable);
|
||||
if(hdr->version > 1) {
|
||||
long UnknownSize = *((long *)(buffer));
|
||||
buffer = buffer + 4 + (UnknownSize * 4);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
model_loaders = new TERLoader[this->model_data.model_count];
|
||||
|
||||
tex_count = this->model_data.zone_model->tex_count;
|
||||
#ifdef DEBUGEQG
|
||||
printf("zon.cpp line 154 zm tex count is %d\n", this->model_data.zone_model->tex_count);
|
||||
#endif
|
||||
|
||||
for(j = 0; j < this->model_data.model_count; ++j) {
|
||||
|
||||
// We have already loaded the zone mesh, so skip the .TER file when processing models.
|
||||
//
|
||||
if(!(strcmp(model_names[j]+strlen(model_names[j])-3, "ter"))) {
|
||||
// printf("Skipping .TER file at model number %d\n", j);
|
||||
this->model_data.models[j] = nullptr;
|
||||
continue;
|
||||
}
|
||||
// printf("Attempting to open MOD file %s\n", model_names[j]); fflush(stdout);
|
||||
if(model_loaders[j].Open(nullptr, model_names[j], archive)) {
|
||||
|
||||
this->model_data.models[j] = new Model;
|
||||
this->model_data.models[j]->vert_count = model_loaders[j].model_data.zone_model->vert_count;
|
||||
this->model_data.models[j]->poly_count = model_loaders[j].model_data.zone_model->poly_count;
|
||||
this->model_data.models[j]->tex_count = model_loaders[j].model_data.zone_model->tex_count;
|
||||
this->model_data.models[j]->verts = model_loaders[j].model_data.zone_model->verts;
|
||||
this->model_data.models[j]->polys = model_loaders[j].model_data.zone_model->polys;
|
||||
this->model_data.models[j]->tex = model_loaders[j].model_data.zone_model->tex;
|
||||
this->model_data.models[j]->name = new char[strlen(model_names[j])+1];
|
||||
strcpy(this->model_data.models[j]->name, model_names[j]);
|
||||
|
||||
tex_tmp = 1;
|
||||
// I think this is looking to see if the placeable model textures already exist in the zone model.
|
||||
//
|
||||
for(i = 0; i < this->model_data.models[j]->tex_count; ++i) {
|
||||
tex_tmp = 1; // Derision
|
||||
for(k = 0; k < this->model_data.zone_model->tex_count; ++k) {
|
||||
// printf(" Checking zm tex filename %s againt model filename %s\n", this->model_data.zone_model->tex[k]->filenames[0],
|
||||
// this->model_data.models[j]->tex[i]->filenames[0]);
|
||||
if((!this->model_data.zone_model->tex[k]->filenames[0] && !this->model_data.models[j]->tex[i]->filenames[0]) ||
|
||||
(this->model_data.zone_model->tex[k]->filenames[0] &&
|
||||
this->model_data.models[j]->tex[i]->filenames[0] &&
|
||||
!strcmp(this->model_data.zone_model->tex[k]->filenames[0], this->model_data.models[j]->tex[i]->filenames[0]))) {
|
||||
tex_tmp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(tex_tmp)
|
||||
++tex_count;
|
||||
else {
|
||||
for(k = 0; k < j; ++k) {
|
||||
if(!this->model_data.models[k]) {
|
||||
#ifdef DEBUGEQG
|
||||
printf("nullptr this->model_data.models[k])\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
for(l = 0; l < this->model_data.models[k]->tex_count; ++l) {
|
||||
if(this->model_data.models[k]->tex[l]->filenames[0] == this->model_data.models[j]->tex[i]->filenames[0] ||
|
||||
(this->model_data.models[k]->tex[l]->filenames[0] &&
|
||||
this->model_data.models[j]->tex[i]->filenames[0] &&
|
||||
!strcmp(this->model_data.models[k]->tex[l]->filenames[0], this->model_data.models[j]->tex[i]->filenames[0]))) {
|
||||
tex_tmp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tex_tmp)
|
||||
++tex_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->model_data.models[j] = nullptr;
|
||||
}
|
||||
|
||||
// printf("Tex count is %i %X\n", tex_count, tex_count);
|
||||
// Allocate a new Texture array
|
||||
tex_count = 0;
|
||||
tex_tmp = 1;
|
||||
// Set the first tex_count textures in the new Texture array to the textures from the zone model
|
||||
// For i in each model
|
||||
for(i = 0; i < this->model_data.model_count; ++i) {
|
||||
if(!this->model_data.models[i]) {
|
||||
#ifdef DEBUGEQG
|
||||
printf("nullptr this->model_data.models[i])\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
// For j = each texture in this model
|
||||
for(j = 0; j < this->model_data.models[i]->tex_count; ++j) {
|
||||
tex_tmp = 1; // Derision
|
||||
// for k = each texture in the zone model
|
||||
for(k = 0; k < tex_count; ++k) {
|
||||
// if the texture filenames are at the same address or, the texture filenames are the same, we set tex_tmp to 0
|
||||
if(tex[k]->filenames[0] == this->model_data.models[i]->tex[j]->filenames[0] ||
|
||||
(tex[k]->filenames[0] &&
|
||||
this->model_data.models[i]->tex[j]->filenames[0] &&
|
||||
!strcmp(tex[k]->filenames[0], this->model_data.models[i]->tex[j]->filenames[0]))) {
|
||||
tex_tmp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if tex_tmp is 0, i.e. this texture is not in the zone model, we add this texture to our new Texture array, at the end
|
||||
if(tex_tmp) {
|
||||
tex[tex_count] = this->model_data.models[i]->tex[j];
|
||||
++tex_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i = 0; i < this->model_data.model_count; ++i) {
|
||||
if(!this->model_data.models[i]) {
|
||||
#ifdef DEBUGEQG
|
||||
printf(">nullptr this->model_data.models[i])\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
tex_map = new int[this->model_data.models[i]->tex_count];
|
||||
|
||||
for(j = 0; j < this->model_data.models[i]->tex_count; ++j) {
|
||||
tex_map[j] = 0;
|
||||
for(k = 0; k < tex_count; ++k) {
|
||||
if(tex[k]->filenames[0] == this->model_data.models[i]->tex[j]->filenames[0] ||
|
||||
(tex[k]->filenames[0] &&
|
||||
this->model_data.models[i]->tex[j]->filenames[0] &&
|
||||
!strcmp(tex[k]->filenames[0], this->model_data.models[i]->tex[j]->filenames[0]))) {
|
||||
tex_map[j] = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] tex_map;
|
||||
}
|
||||
|
||||
delete [] model_names;
|
||||
|
||||
this->model_data.zone_model->tex = 0;
|
||||
this->model_data.zone_model->tex_count = 0;
|
||||
delete [] orig_buffer;
|
||||
|
||||
this->status = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ZonLoader::Close() {
|
||||
|
||||
int i;
|
||||
|
||||
if(!this->status)
|
||||
return 1;
|
||||
|
||||
this->terloader.Close();
|
||||
|
||||
for(i = 0; i < this->model_data.model_count; ++i)
|
||||
this->model_loaders[i].Close();
|
||||
|
||||
for(i = 0; i < this->model_data.model_count; ++i)
|
||||
{
|
||||
if(this->model_data.models[i])
|
||||
{
|
||||
delete [] this->model_data.models[i]->name;
|
||||
delete this->model_data.models[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < this->model_data.plac_count; ++i)
|
||||
delete this->model_data.placeable[i];
|
||||
|
||||
delete [] this->model_data.placeable;
|
||||
|
||||
delete [] this->model_data.models;
|
||||
|
||||
delete[] this->model_loaders;
|
||||
|
||||
status = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef __OPENEQ_ZON__
|
||||
#define __OPENEQ_ZON__
|
||||
|
||||
#include "ter.hpp"
|
||||
|
||||
/* Big thanks to jbb on the ZON stuff! */
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct zon_header {
|
||||
char magic[4]; // Constant at EQGZ
|
||||
long version; // Constant at 2
|
||||
long list_len; // Length of the list to follow.
|
||||
long NumberOfModels;
|
||||
long obj_count; // Placeable object count.
|
||||
long unk[2]; // Unknown.
|
||||
} typedef zon_header;
|
||||
|
||||
struct zon_placeable {
|
||||
long id;
|
||||
long loc;
|
||||
float x, y, z;
|
||||
float rx, ry, rz;
|
||||
float scale;
|
||||
} typedef zon_placeable;
|
||||
|
||||
struct zon_object {
|
||||
long offset;
|
||||
long id;
|
||||
} typedef zon_object;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
class ZonLoader : public FileLoader {
|
||||
public:
|
||||
ZonLoader();
|
||||
~ZonLoader();
|
||||
|
||||
virtual int Open(char *base_path, char *zone_name, Archive *archive);
|
||||
virtual int Close();
|
||||
|
||||
private:
|
||||
TERLoader terloader;
|
||||
TERLoader *model_loaders;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,255 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "3d.hpp"
|
||||
#include "zonv4.hpp"
|
||||
//#define DEBUGEQG
|
||||
//#define DEBUGPLAC
|
||||
|
||||
string GetToken(uchar *&Buffer, int &Position);
|
||||
|
||||
Zonv4Loader::Zonv4Loader()
|
||||
{
|
||||
this->buffer = nullptr;
|
||||
this->buf_len = -1;
|
||||
this->archive = nullptr;
|
||||
this->status = 0;
|
||||
}
|
||||
|
||||
Zonv4Loader::~Zonv4Loader()
|
||||
{
|
||||
this->Close();
|
||||
}
|
||||
|
||||
int Zonv4Loader::Open(char *base_path, char *zone_name, Archive *archive)
|
||||
{
|
||||
|
||||
uchar *buffer;
|
||||
int position;
|
||||
int buf_len;
|
||||
|
||||
Texture **tex;
|
||||
int tex_count, tex_tmp, *tex_map;
|
||||
|
||||
int i, j, k, l;
|
||||
char **model_names;
|
||||
|
||||
char *filename;
|
||||
|
||||
uchar *zon_tmp, *zon_orig;
|
||||
|
||||
float rot_change = 180.0f / 3.14159f;
|
||||
|
||||
float base[3];
|
||||
|
||||
printf("Attempting to load EQG %s\n", zone_name);
|
||||
|
||||
filename = new char[strlen(zone_name) + 5];
|
||||
|
||||
sprintf(filename, "*.zon");
|
||||
#ifdef DEBUGEQG
|
||||
printf("Looking for ZON file %s\n", filename);
|
||||
archive->GetFile("*.zon", &buffer, &buf_len);
|
||||
#endif
|
||||
if(!archive->GetFile(filename, &buffer, &buf_len))
|
||||
{
|
||||
printf("Couldn't find ZON file %s\n", zone_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
delete[] filename;
|
||||
|
||||
zonv4_header *hdr = (zonv4_header *) buffer;
|
||||
|
||||
zonv4_placeable *plac;
|
||||
|
||||
if(hdr->magic[0] != 'E' || hdr->magic[1] != 'Q' || hdr->magic[2] != 'T' || hdr->magic[3] != 'Z')
|
||||
return 0;
|
||||
#ifdef DEBUGEQG
|
||||
printf("Found V4 EQG.\n"); fflush(stdout);
|
||||
|
||||
printf("Seeking .DAT file\n");
|
||||
#endif
|
||||
buffer += sizeof(zonv4_header);
|
||||
|
||||
position = 0;
|
||||
|
||||
char ZonName[255];
|
||||
|
||||
while(position < buf_len)
|
||||
{
|
||||
string Token = GetToken(buffer, position);
|
||||
|
||||
if(Token == "*NAME")
|
||||
{
|
||||
Token = GetToken(buffer, position);
|
||||
#ifdef DEBUGEQG
|
||||
printf(".zon name is %s\n", Token.c_str());
|
||||
#endif
|
||||
sprintf(ZonName, "%s.dat", Token.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->datloader.Open(nullptr, ZonName, archive);
|
||||
|
||||
this->model_data.zone_model = datloader.model_data.zone_model;
|
||||
|
||||
model_loaders = new TERLoader[this->datloader.model_data.ModelNames.size() + 1];
|
||||
|
||||
this->model_data.models = new Model *[this->datloader.model_data.ModelNames.size() + 1];
|
||||
|
||||
this->model_data.placeable = new Placeable *[this->datloader.model_data.PlaceableList.size()];
|
||||
|
||||
for(unsigned int i = 0; i < this->datloader.model_data.ModelNames.size(); ++i)
|
||||
{
|
||||
char tmp[200];
|
||||
//printf("Opening %s.mod\n", this->datloader.model_data.ModelNames[i].c_str());
|
||||
sprintf(tmp, "%s.mod", this->datloader.model_data.ModelNames[i].c_str());
|
||||
|
||||
char *str = tmp;
|
||||
|
||||
while(*str) {
|
||||
if(*str >= 'A' && *str <= 'Z')
|
||||
*str += 'a' - 'A';
|
||||
++str;
|
||||
}
|
||||
|
||||
if(model_loaders[i].Open(nullptr, tmp, archive))
|
||||
{
|
||||
this->model_data.models[i] = new Model;
|
||||
this->model_data.models[i]->vert_count = model_loaders[i].model_data.zone_model->vert_count;
|
||||
this->model_data.models[i]->poly_count = model_loaders[i].model_data.zone_model->poly_count;
|
||||
this->model_data.models[i]->tex_count = model_loaders[i].model_data.zone_model->tex_count;
|
||||
this->model_data.models[i]->verts = model_loaders[i].model_data.zone_model->verts;
|
||||
this->model_data.models[i]->polys = model_loaders[i].model_data.zone_model->polys;
|
||||
this->model_data.models[i]->tex = model_loaders[i].model_data.zone_model->tex;
|
||||
this->model_data.models[i]->name = new char[100];
|
||||
strcpy(this->model_data.models[i]->name, tmp);
|
||||
|
||||
this->model_data.models[i]->IncludeInMap = true;
|
||||
|
||||
// Attempt to cut down on the .map file size by defaulting some objects to not be included. The user can
|
||||
// always change this in the azone.ini
|
||||
//
|
||||
// For example, taking out all the tak_braziers from elddar saves around 30MB
|
||||
//
|
||||
if(strstr(tmp, "tree") || strstr(tmp, "pine") || strstr(tmp, "palm") || strstr(tmp, "rock") ||
|
||||
strstr(tmp, "shrub") || strstr(tmp, "fern") || strstr(tmp, "bamboo") || strstr(tmp, "coral") ||
|
||||
strstr(tmp, "camp_bones") || strstr(tmp, "sponge") || strstr(tmp, "plant") || strstr(tmp, "shortplm") ||
|
||||
strstr(tmp, "tak_brazier") || strstr(tmp, "tak_banner") || strstr(tmp, "fung") || strstr(tmp, "bolete") ||
|
||||
strstr(tmp, "amanita") || strstr(tmp, "leopita"))
|
||||
{
|
||||
if(!strstr(tmp, "arch"))
|
||||
{
|
||||
this->model_data.models[i]->IncludeInMap = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unable to open model %s, but continuing.\n", tmp);
|
||||
this->model_data.models[i] = new Model;
|
||||
this->model_data.models[i]->IncludeInMap = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGPLAC
|
||||
printf("Placeable list:\n");
|
||||
|
||||
for(int i = 0; i < this->datloader.model_data.ObjectGroups.size(); ++i)
|
||||
{
|
||||
printf("ObjectGroup: %i\n", i);
|
||||
printf(" XYZ: %8.3f, %8.3f, %8.3f Tile: (%8.3f, %8.3f, %8.3f) Rots: (%8.3f, %8.3f, %8.3f) Scale: %8.3f\n",
|
||||
this->datloader.model_data.ObjectGroups[i].x,
|
||||
this->datloader.model_data.ObjectGroups[i].y,
|
||||
this->datloader.model_data.ObjectGroups[i].z,
|
||||
this->datloader.model_data.ObjectGroups[i].TileX,
|
||||
this->datloader.model_data.ObjectGroups[i].TileY,
|
||||
this->datloader.model_data.ObjectGroups[i].TileZ,
|
||||
this->datloader.model_data.ObjectGroups[i].RotX,
|
||||
this->datloader.model_data.ObjectGroups[i].RotY,
|
||||
this->datloader.model_data.ObjectGroups[i].RotZ,
|
||||
this->datloader.model_data.ObjectGroups[i].ScaleX);
|
||||
|
||||
list<int>::iterator ModelIterator;
|
||||
|
||||
ModelIterator = this->datloader.model_data.ObjectGroups[i].SubObjects.begin();
|
||||
|
||||
while(ModelIterator != this->datloader.model_data.ObjectGroups[i].SubObjects.end())
|
||||
{
|
||||
printf(" Uses Placeable: %i\n", (*ModelIterator));
|
||||
printf(" %s\n",
|
||||
this->datloader.model_data.ModelNames[this->datloader.model_data.PlaceableList[(*ModelIterator)].model].c_str());
|
||||
printf(" Model: %3i XYZ: (%8.3f, %8.3f, %8.3f) ROT: (%8.3f, %8.3f, %8.3f) SCALE: (%8.3f, %8.3f, %8.3f)\n",
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].model,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].x,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].y,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].z,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].rx,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].ry,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].rz,
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].scale[0],
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].scale[1],
|
||||
this->datloader.model_data.PlaceableList[(*ModelIterator)].scale[2]);
|
||||
|
||||
|
||||
++ModelIterator;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for(unsigned int i = 0; i < this->datloader.model_data.PlaceableList.size(); ++i)
|
||||
{
|
||||
this->model_data.placeable[i] = new Placeable;
|
||||
|
||||
this->model_data.placeable[i]->model = this->datloader.model_data.PlaceableList[i].model;
|
||||
|
||||
this->model_data.placeable[i]->x = this->datloader.model_data.PlaceableList[i].x;
|
||||
this->model_data.placeable[i]->y = this->datloader.model_data.PlaceableList[i].y;
|
||||
this->model_data.placeable[i]->z = this->datloader.model_data.PlaceableList[i].z;
|
||||
|
||||
this->model_data.placeable[i]->rx = this->datloader.model_data.PlaceableList[i].rx;
|
||||
this->model_data.placeable[i]->ry = this->datloader.model_data.PlaceableList[i].ry;
|
||||
this->model_data.placeable[i]->rz = this->datloader.model_data.PlaceableList[i].rz;
|
||||
|
||||
this->model_data.placeable[i]->scale[0] = this->datloader.model_data.PlaceableList[i].scale[0];
|
||||
this->model_data.placeable[i]->scale[1] = this->datloader.model_data.PlaceableList[i].scale[1];
|
||||
this->model_data.placeable[i]->scale[2] = this->datloader.model_data.PlaceableList[i].scale[2];
|
||||
}
|
||||
|
||||
this->model_data.ObjectGroups = this->datloader.model_data.ObjectGroups;
|
||||
|
||||
this->model_data.plac_count = this->datloader.model_data.PlaceableList.size();
|
||||
|
||||
this->model_data.model_count = this->datloader.model_data.ModelNames.size();
|
||||
|
||||
this->status = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int Zonv4Loader::Close()
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!this->status)
|
||||
return 1;
|
||||
|
||||
//TODO: Free up all the memory we used
|
||||
|
||||
this->datloader.Close();
|
||||
|
||||
for(i = 0; i < this->model_data.model_count; ++i)
|
||||
this->model_loaders[i].Close();
|
||||
|
||||
delete[] this->model_loaders;
|
||||
|
||||
this->status = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef __OPENEQ_ZONV4__
|
||||
#define __OPENEQ_ZONV4__
|
||||
|
||||
#include "dat.hpp"
|
||||
#include "ter.hpp"
|
||||
|
||||
/* Big thanks to jbb on the ZON stuff! */
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct zonv4_header {
|
||||
char magic[4]; // Constant at EQGZ
|
||||
} typedef zonv4_header;
|
||||
|
||||
struct zonv4_placeable {
|
||||
long id;
|
||||
long loc;
|
||||
float x, y, z;
|
||||
float rx, ry, rz;
|
||||
float scale;
|
||||
} typedef zonv4_placeable;
|
||||
|
||||
struct zonv4_object {
|
||||
long offset;
|
||||
long id;
|
||||
} typedef zonv4_object;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
class Zonv4Loader : public FileLoader {
|
||||
public:
|
||||
Zonv4Loader();
|
||||
~Zonv4Loader();
|
||||
|
||||
virtual int Open(char *base_path, char *zone_name, Archive *archive);
|
||||
virtual int Close();
|
||||
|
||||
private:
|
||||
DATLoader datloader;
|
||||
TERLoader *model_loaders;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
|
||||
PROJECT(PFSUtil)
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Debug")
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
IF(WIN32)
|
||||
ADD_DEFINITIONS(/D _CRT_SECURE_NO_WARNINGS)
|
||||
ENDIF(WIN32)
|
||||
|
||||
SET(ZLIB_ROOT, "${CMAKE_CURRENT_SOURCE_DIR}/zlib")
|
||||
FIND_PACKAGE(ZLIB REQUIRED)
|
||||
INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}")
|
||||
|
||||
|
||||
ADD_SUBDIRECTORY(Common)
|
||||
ADD_SUBDIRECTORY(PFSList)
|
||||
@@ -0,0 +1,17 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
|
||||
SET(common_sources
|
||||
Source/PFSArchive.cpp
|
||||
Source/Compression.cpp
|
||||
)
|
||||
|
||||
SET(common_headers
|
||||
Include/Archive.h
|
||||
Include/PFSArchive.h
|
||||
Include/PFSDataStructs.h
|
||||
Include/Compression.h
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(Include)
|
||||
|
||||
ADD_LIBRARY(Common ${common_sources} ${common_headers})
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef __AZONE_COMMON_ARCHIVE_H
|
||||
#define __AZONE_COMMON_ARCHIVE_H
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
class Archive {
|
||||
public:
|
||||
Archive() { }
|
||||
virtual ~Archive() { }
|
||||
|
||||
virtual bool Open(std::string filename) = 0;
|
||||
virtual bool Close() = 0;
|
||||
virtual bool Get(std::string filename, char** buffer, size_t& buffer_size) = 0;
|
||||
virtual bool Exists(std::string filename) = 0;
|
||||
virtual bool GetFiles(std::string ext, std::list<std::string>& files) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __AZONE_COMMON_COMPRESSION_H
|
||||
#define __AZONE_COMMON_COMPRESSION_H
|
||||
|
||||
#include <string>
|
||||
#include <zlib.h>
|
||||
|
||||
void decompress(const char* in, size_t in_len, char* out, size_t out_len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef __AZONE_COMMON_PFSARCHIVE_H
|
||||
#define __AZONE_COMMON_PFSARCHIVE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#ifdef WIN32
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "Archive.h"
|
||||
#include "PFSDataStructs.h"
|
||||
#include "Compression.h"
|
||||
|
||||
class PFSArchive : public Archive {
|
||||
public:
|
||||
PFSArchive();
|
||||
virtual ~PFSArchive();
|
||||
|
||||
virtual bool Open(std::string filename);
|
||||
virtual bool Close();
|
||||
virtual bool Get(std::string filename, char **buffer, size_t& buffer_size);
|
||||
virtual bool Exists(std::string filename);
|
||||
virtual bool GetFiles(std::string ext, std::list<std::string>& files);
|
||||
private:
|
||||
bool ReadIntoBuffer(std::string filename);
|
||||
std::vector<std::string> _filenames;
|
||||
std::vector<size_t> _files;
|
||||
char* _buffer;
|
||||
size_t _buffer_size;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef __AZONE_COMMON_PFSDATASTRUCTS_H
|
||||
#define __AZONE_COMMON_PFSDATASTRUCTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct PFSHeader {
|
||||
uint32_t offset;
|
||||
char magic[4];
|
||||
uint32_t unknown;
|
||||
};
|
||||
|
||||
struct PFSDirectoryHeader {
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
struct PFSDirectory {
|
||||
uint32_t crc, offset, size;
|
||||
};
|
||||
|
||||
struct PFSDataBlock {
|
||||
uint32_t deflate_length, inflate_length;
|
||||
};
|
||||
|
||||
struct PFSFilenameHeader {
|
||||
uint32_t filename_count;
|
||||
};
|
||||
|
||||
struct PFSFilenameEntry {
|
||||
uint32_t filename_length;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "Compression.h"
|
||||
|
||||
void decompress(const char* in, size_t in_len, char* out, size_t out_len) {
|
||||
int status;
|
||||
z_stream d_stream;
|
||||
|
||||
d_stream.zalloc = (alloc_func)0;
|
||||
d_stream.zfree = (free_func)0;
|
||||
d_stream.opaque = (voidpf)0;
|
||||
|
||||
d_stream.next_in = (Bytef*)in;
|
||||
d_stream.avail_in = in_len;
|
||||
d_stream.next_out = (Bytef*)out;
|
||||
d_stream.avail_out = out_len;
|
||||
|
||||
inflateInit(&d_stream);
|
||||
status = inflate(&d_stream, Z_NO_FLUSH);
|
||||
inflateEnd(&d_stream);
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
#include "PFSArchive.h"
|
||||
|
||||
#define BufferRead(x, y) x = (y*)&_buffer[position]; position += sizeof(y);
|
||||
#define BufferReadLength(x, y) memcpy(x, &_buffer[position], y); position += y;
|
||||
#define MAX_FILENAME_SIZE 1024
|
||||
|
||||
PFSArchive::PFSArchive()
|
||||
:_buffer(NULL), _buffer_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
PFSArchive::~PFSArchive() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool PFSArchive::Open(std::string filename)
|
||||
{
|
||||
if(!ReadIntoBuffer(filename)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
PFSHeader *header = NULL;
|
||||
PFSDirectoryHeader *directory_header = NULL;
|
||||
PFSDirectory *directory = NULL;
|
||||
PFSDataBlock *data_block = NULL;
|
||||
PFSFilenameHeader *filename_header = NULL;
|
||||
PFSFilenameEntry *filename_entry = NULL;
|
||||
size_t position = 0;
|
||||
|
||||
BufferRead(header, PFSHeader);
|
||||
|
||||
if(header->magic[0] != 'P' ||
|
||||
header->magic[1] != 'F' ||
|
||||
header->magic[2] != 'S' ||
|
||||
header->magic[3] != ' ')
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
position = header->offset;
|
||||
BufferRead(directory_header, PFSDirectoryHeader);
|
||||
|
||||
std::vector<uint32_t> offsets(directory_header->count, 0);
|
||||
_filenames.resize(directory_header->count);
|
||||
_files.resize(directory_header->count);
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
size_t running = 0;
|
||||
size_t temp_position = 0;
|
||||
size_t inflate = 0;
|
||||
char temp_buffer[32768];
|
||||
char temp_buffer2[32768];
|
||||
char temp_string[MAX_FILENAME_SIZE];
|
||||
for(; i < directory_header->count; ++i) {
|
||||
BufferRead(directory, PFSDirectory);
|
||||
if(directory->crc == ntohl(0xC90A5861)) {
|
||||
temp_position = position;
|
||||
position = directory->offset;
|
||||
memset(temp_buffer, 0, directory->size);
|
||||
inflate = 0;
|
||||
|
||||
while(inflate < directory->size) {
|
||||
BufferRead(data_block, PFSDataBlock);
|
||||
BufferReadLength(temp_buffer2, data_block->deflate_length);
|
||||
decompress(temp_buffer2, data_block->deflate_length, temp_buffer + inflate, data_block->inflate_length);
|
||||
inflate += data_block->inflate_length;
|
||||
}
|
||||
|
||||
position = temp_position;
|
||||
filename_header = (PFSFilenameHeader*)&temp_buffer[0];
|
||||
temp_position = sizeof(PFSFilenameHeader);
|
||||
|
||||
for(j = 0; j < filename_header->filename_count; ++j)
|
||||
{
|
||||
filename_entry = (PFSFilenameEntry*)&temp_buffer[temp_position];
|
||||
if(filename_entry->filename_length + 1 >= MAX_FILENAME_SIZE) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
temp_string[filename_entry->filename_length] = 0;
|
||||
memcpy(temp_string, &temp_buffer[temp_position + sizeof(PFSFilenameEntry)], filename_entry->filename_length);
|
||||
_filenames[j] = temp_string;
|
||||
temp_position += sizeof(PFSFilenameEntry) + filename_entry->filename_length;
|
||||
}
|
||||
} else {
|
||||
_files[running] = position - 12;
|
||||
offsets[running] = directory->offset;
|
||||
++running;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t temp = 0;
|
||||
for(i = directory_header->count - 2; i > 0; i--) {
|
||||
for(j = 0; j < i; j++) {
|
||||
if(offsets[j] > offsets[j + 1]) {
|
||||
temp = offsets[j];
|
||||
offsets[j] = offsets[j + 1];
|
||||
offsets[j + 1] = temp;
|
||||
temp = _files[j];
|
||||
_files[j] = _files[j + 1];
|
||||
_files[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PFSArchive::Close()
|
||||
{
|
||||
if(_buffer) {
|
||||
delete[] _buffer;
|
||||
_buffer = 0;
|
||||
_buffer_size = 0;
|
||||
_filenames.resize(0);
|
||||
_files.resize(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//I would love to get rid of the allocations in the while loop below but sadly
|
||||
//I can't predict the size of data blocks well enough to be able to and feel
|
||||
//comfortable with it (I could however reduce the number of times I need to
|
||||
//reallocate with a little clever logic which i think I will do
|
||||
bool PFSArchive::Get(std::string filename, char **buffer, size_t& buffer_size) {
|
||||
size_t sz = _filenames.size();
|
||||
for(size_t index = 0; index < sz; ++index) {
|
||||
if(!_filenames[index].compare(filename)) {
|
||||
PFSDirectory* directory = NULL;
|
||||
PFSDataBlock* data_block = NULL;
|
||||
char *temp = NULL;
|
||||
|
||||
size_t position = _files[index];
|
||||
BufferRead(directory, PFSDirectory);
|
||||
position = directory->offset;
|
||||
|
||||
*buffer = new char[directory->size];
|
||||
buffer_size = directory->size;
|
||||
|
||||
size_t inflate = 0;
|
||||
while(inflate < directory->size) {
|
||||
BufferRead(data_block, PFSDataBlock);
|
||||
temp = new char[data_block->deflate_length];
|
||||
|
||||
memcpy(temp, &_buffer[position], data_block->deflate_length);
|
||||
position += data_block->deflate_length;
|
||||
|
||||
decompress(temp, data_block->deflate_length, *buffer + inflate, data_block->inflate_length);
|
||||
delete[] temp;
|
||||
inflate += data_block->inflate_length;
|
||||
}
|
||||
buffer_size = inflate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PFSArchive::Exists(std::string filename) {
|
||||
size_t count = _filenames.size();
|
||||
for(size_t i = 0; i < count; ++i) {
|
||||
if(!_filenames[i].compare(filename.c_str()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PFSArchive::GetFiles(std::string ext, std::list<std::string>& files) {
|
||||
int elen = ext.length();
|
||||
bool all_files = !ext.compare("*");
|
||||
files.clear();
|
||||
|
||||
size_t count = _filenames.size();
|
||||
for(size_t i = 0; i < count; ++i) {
|
||||
int flen = _filenames[i].length();
|
||||
if(flen <= elen)
|
||||
continue;
|
||||
|
||||
if(!strcmp(_filenames[i].c_str() + (flen - elen), ext.c_str()) || all_files)
|
||||
files.push_back(_filenames[i]);
|
||||
}
|
||||
|
||||
return files.size() > 0;
|
||||
}
|
||||
|
||||
bool PFSArchive::ReadIntoBuffer(std::string filename) {
|
||||
FILE* f = fopen(filename.c_str(), "rb");
|
||||
if(!f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t total_size = ftell(f);
|
||||
rewind(f);
|
||||
|
||||
if(!total_size) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(_buffer) {
|
||||
delete[] _buffer;
|
||||
}
|
||||
|
||||
_buffer = new char[total_size];
|
||||
size_t bytes_read = fread(_buffer, 1, total_size, f);
|
||||
|
||||
if(bytes_read != total_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_buffer_size = total_size;
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
|
||||
SET(pfslist_sources
|
||||
Source/main.cpp
|
||||
)
|
||||
|
||||
SET(pfslist_headers
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(Include
|
||||
../Common/Include
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(PFSList ${pfslist_sources} ${pfslist_headers})
|
||||
|
||||
TARGET_LINK_LIBRARIES(PFSList Common ${ZLIB_LIBRARY} "Ws2_32.lib")
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEFINITIONS(/D _CONSOLE)
|
||||
SET_TARGET_PROPERTIES(PFSList PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
||||
ENDIF(MSVC)
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ../Build/PFSList)
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "PFSArchive.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(argc < 3) {
|
||||
printf("Usage: %s ext file1 [file2...]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(int i = 2; i < argc; ++i) {
|
||||
PFSArchive archive;
|
||||
if(!archive.Open(argv[i])) {
|
||||
printf("Error: couldn't open %s\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::list<std::string> files;
|
||||
if(!archive.GetFiles(argv[1], files)) {
|
||||
printf("Error: couldn't return the files with ext: %s\n", argv[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Files in %s:\n", argv[i]);
|
||||
std::list<std::string>::const_iterator iter = files.begin();
|
||||
while(iter != files.end()) {
|
||||
printf("%s\n", (*iter).c_str());
|
||||
iter++;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
archive.Close();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Simple utility to modify fields in player profile... far from complete. Right now just sets ldon points to 0 but going to expand it.
|
||||
@@ -0,0 +1,4 @@
|
||||
host=localhost
|
||||
user=root
|
||||
password=pass
|
||||
db=eq
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "player_profile_set", "player_profile_set\player_profile_set.vcproj", "{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,331 @@
|
||||
#include "misc_functions.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#define snprintf _snprintf
|
||||
#if (_MSC_VER < 1500)
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
char* strn0cpy(char* dest, const char* source, int32 size) {
|
||||
if (!dest)
|
||||
return 0;
|
||||
if (size == 0 || source == 0) {
|
||||
dest[0] = 0;
|
||||
return dest;
|
||||
}
|
||||
strncpy(dest, source, size);
|
||||
dest[size - 1] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
// String N w/null Copy Truncated?
|
||||
// return value =true if entire string(source) fit, false if it was truncated
|
||||
bool strn0cpyt(char* dest, const char* source, int32 size) {
|
||||
if (!dest)
|
||||
return 0;
|
||||
if (size == 0 || source == 0) {
|
||||
dest[0] = 0;
|
||||
return dest;
|
||||
}
|
||||
strncpy(dest, source, size);
|
||||
dest[size - 1] = 0;
|
||||
return (bool) (source[strlen(dest)] == 0);
|
||||
}
|
||||
|
||||
const char *MakeUpperString(const char *source) {
|
||||
static char str[128];
|
||||
if (!source)
|
||||
return NULL;
|
||||
MakeUpperString(source, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
void MakeUpperString(const char *source, char *target) {
|
||||
if (!source || !target) {
|
||||
*target=0;
|
||||
return;
|
||||
}
|
||||
while (*source)
|
||||
{
|
||||
*target = toupper(*source);
|
||||
target++;source++;
|
||||
}
|
||||
*target = 0;
|
||||
}
|
||||
|
||||
const char *MakeLowerString(const char *source) {
|
||||
static char str[128];
|
||||
if (!source)
|
||||
return NULL;
|
||||
MakeLowerString(source, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
void MakeLowerString(const char *source, char *target) {
|
||||
if (!source || !target) {
|
||||
*target=0;
|
||||
return;
|
||||
}
|
||||
while (*source)
|
||||
{
|
||||
*target = tolower(*source);
|
||||
target++;source++;
|
||||
}
|
||||
*target = 0;
|
||||
}
|
||||
|
||||
int MakeAnyLenString(char** ret, const char* format, ...) {
|
||||
int buf_len = 128;
|
||||
int chars = -1;
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
while (chars == -1 || chars >= buf_len) {
|
||||
safe_delete_array(*ret);
|
||||
if (chars == -1)
|
||||
buf_len *= 2;
|
||||
else
|
||||
buf_len = chars + 1;
|
||||
*ret = new char[buf_len];
|
||||
chars = vsnprintf(*ret, buf_len, format, argptr);
|
||||
}
|
||||
va_end(argptr);
|
||||
return chars;
|
||||
}
|
||||
|
||||
int32 AppendAnyLenString(char** ret, int32* bufsize, int32* strlen, const char* format, ...) {
|
||||
if (*bufsize == 0)
|
||||
*bufsize = 256;
|
||||
if (*ret == 0)
|
||||
*strlen = 0;
|
||||
int chars = -1;
|
||||
char* oldret = 0;
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
while (chars == -1 || chars >= (sint32)(*bufsize-*strlen)) {
|
||||
if (chars == -1)
|
||||
*bufsize += 256;
|
||||
else
|
||||
*bufsize += chars + 25;
|
||||
oldret = *ret;
|
||||
*ret = new char[*bufsize];
|
||||
if (oldret) {
|
||||
if (*strlen)
|
||||
memcpy(*ret, oldret, *strlen);
|
||||
safe_delete_array(oldret);
|
||||
}
|
||||
chars = vsnprintf(&(*ret)[*strlen], (*bufsize-*strlen), format, argptr);
|
||||
}
|
||||
va_end(argptr);
|
||||
*strlen += chars;
|
||||
return *strlen;
|
||||
}
|
||||
|
||||
int32 hextoi(char* num) {
|
||||
int len = strlen(num);
|
||||
if (len < 3)
|
||||
return 0;
|
||||
|
||||
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
|
||||
return 0;
|
||||
|
||||
int32 ret = 0;
|
||||
int mul = 1;
|
||||
for (int i=len-1; i>=2; i--) {
|
||||
if (num[i] >= 'A' && num[i] <= 'F')
|
||||
ret += ((num[i] - 'A') + 10) * mul;
|
||||
else if (num[i] >= 'a' && num[i] <= 'f')
|
||||
ret += ((num[i] - 'a') + 10) * mul;
|
||||
else if (num[i] >= '0' && num[i] <= '9')
|
||||
ret += (num[i] - '0') * mul;
|
||||
else
|
||||
return 0;
|
||||
mul *= 16;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64 hextoi64(char* num) {
|
||||
int len = strlen(num);
|
||||
if (len < 3)
|
||||
return 0;
|
||||
|
||||
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
|
||||
return 0;
|
||||
|
||||
int64 ret = 0;
|
||||
int mul = 1;
|
||||
for (int i=len-1; i>=2; i--) {
|
||||
if (num[i] >= 'A' && num[i] <= 'F')
|
||||
ret += ((num[i] - 'A') + 10) * mul;
|
||||
else if (num[i] >= 'a' && num[i] <= 'f')
|
||||
ret += ((num[i] - 'a') + 10) * mul;
|
||||
else if (num[i] >= '0' && num[i] <= '9')
|
||||
ret += (num[i] - '0') * mul;
|
||||
else
|
||||
return 0;
|
||||
mul *= 16;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool atobool(char* iBool) {
|
||||
if (!strcasecmp(iBool, "true"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "false"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "yes"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "no"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "on"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "off"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "enable"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "disable"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "enabled"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "disabled"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "y"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "n"))
|
||||
return false;
|
||||
if (atoi(iBool))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* solar: generate a random integer in the range low-high
|
||||
* this should be used instead of the rand()%limit method
|
||||
*/
|
||||
int MakeRandomInt(int low, int high)
|
||||
{
|
||||
if(low >= high)
|
||||
return(low);
|
||||
|
||||
return (rand()%(high-low+1) + (low));
|
||||
}
|
||||
|
||||
double MakeRandomFloat(double low, double high)
|
||||
{
|
||||
if(low >= high)
|
||||
return(low);
|
||||
|
||||
return (rand() / (double)RAND_MAX * (high - low) + low);
|
||||
}
|
||||
|
||||
// solar: removes the crap and turns the underscores into spaces.
|
||||
char *CleanMobName(const char *in, char *out)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for(i = j = 0; i < strlen(in); i++)
|
||||
{
|
||||
// convert _ to space.. any other conversions like this? I *think* this
|
||||
// is the only non alpha char that's not stripped but converted.
|
||||
if(in[i] == '_')
|
||||
{
|
||||
out[j++] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isalpha(in[i]) || (in[i] == '`')) // numbers, #, or any other crap just gets skipped
|
||||
out[j++] = in[i];
|
||||
}
|
||||
}
|
||||
out[j] = 0; // terimnate the string before returning it
|
||||
return out;
|
||||
}
|
||||
|
||||
const char *ConvertArray(int input, char *returnchar)
|
||||
{
|
||||
sprintf(returnchar, "%i" ,input);
|
||||
return returnchar;
|
||||
}
|
||||
|
||||
const char *ConvertArrayF(float input, char *returnchar)
|
||||
{
|
||||
sprintf(returnchar, "%0.2f", input);
|
||||
return returnchar;
|
||||
}
|
||||
|
||||
float EQ13toFloat(int d)
|
||||
{
|
||||
return ( float(d)/float(1<<2));
|
||||
}
|
||||
|
||||
float NewEQ13toFloat(int d)
|
||||
{
|
||||
return ( float(d)/float(1<<6));
|
||||
}
|
||||
|
||||
float EQ19toFloat(int d)
|
||||
{
|
||||
return ( float(d)/float(1<<3));
|
||||
}
|
||||
|
||||
int FloatToEQ13(float d)
|
||||
{
|
||||
return int(d*float(1<<2));
|
||||
}
|
||||
|
||||
int NewFloatToEQ13(float d)
|
||||
{
|
||||
return int(d*float(1<<6));
|
||||
}
|
||||
|
||||
int FloatToEQ19(float d)
|
||||
{
|
||||
return int(d*float(1<<3));
|
||||
}
|
||||
|
||||
/*
|
||||
Heading of 0 points in the pure positive Y direction
|
||||
|
||||
*/
|
||||
int FloatToEQH(float d)
|
||||
{
|
||||
return(int((360.0f - d) * float(1<<11)) / 360);
|
||||
}
|
||||
|
||||
float EQHtoFloat(int d)
|
||||
{
|
||||
return(360.0f - float((d * 360) >> 11));
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef MISCFUNCTIONS_H
|
||||
#define MISCFUNCTIONS_H
|
||||
|
||||
#include "types.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#ifndef ERRBUF_SIZE
|
||||
#define ERRBUF_SIZE 1024
|
||||
#endif
|
||||
|
||||
// These are helper macros for dealing with packets of variable length, typically those that contain
|
||||
// variable length strings where it is not convenient to use a fixed length struct.
|
||||
//
|
||||
#define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type);
|
||||
#define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1;
|
||||
#define VARSTRUCT_ENCODE_STRING(Buffer, String) sprintf(Buffer, String); Buffer += strlen(String) + 1;
|
||||
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1;
|
||||
#define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) *(Type *)Buffer = Value; Buffer += sizeof(Type);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MakeUpperString
|
||||
// i : source - allocated null-terminated string
|
||||
// return: pointer to static buffer with the target string
|
||||
const char *MakeUpperString(const char *source);
|
||||
const char *MakeLowerString(const char *source);
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MakeUpperString
|
||||
// i : source - allocated null-terminated string
|
||||
// io: target - allocated buffer, at least of size strlen(source)+1
|
||||
void MakeUpperString(const char *source, char *target);
|
||||
void MakeLowerString(const char *source, char *target);
|
||||
|
||||
|
||||
int MakeAnyLenString(char** ret, const char* format, ...);
|
||||
int32 AppendAnyLenString(char** ret, int32* bufsize, int32* strlen, const char* format, ...);
|
||||
int32 hextoi(char* num);
|
||||
int64 hextoi64(char* num);
|
||||
bool atobool(char* iBool);
|
||||
void CoutTimestamp(bool ms = true);
|
||||
char* strn0cpy(char* dest, const char* source, int32 size);
|
||||
// return value =true if entire string(source) fit, false if it was truncated
|
||||
bool strn0cpyt(char* dest, const char* source, int32 size);
|
||||
int MakeRandomInt(int low, int high);
|
||||
double MakeRandomFloat(double low, double high);
|
||||
char *CleanMobName(const char *in, char *out);
|
||||
const char *ConvertArray(int input, char *returnchar);
|
||||
const char *ConvertArrayF(float input, char *returnchar);
|
||||
float EQ13toFloat(int d);
|
||||
float NewEQ13toFloat(int d);
|
||||
float EQ19toFloat(int d);
|
||||
float EQHtoFloat(int d);
|
||||
int FloatToEQ13(float d);
|
||||
int NewFloatToEQ13(float d);
|
||||
int FloatToEQ19(float d);
|
||||
int FloatToEQH(float d);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#include "database.h"
|
||||
#include "main.h"
|
||||
#include "eq_player_structs.h"
|
||||
#include <vector>
|
||||
|
||||
extern std::vector<player_entry> player_list;
|
||||
|
||||
EQEmuDatabase::EQEmuDatabase(std::string ServerName, std::string DatabaseName, std::string DBUsername, std::string DBPassword) {
|
||||
SetServerName(ServerName);
|
||||
SetDatabaseName(DatabaseName);
|
||||
SetDBUsername(DBUsername);
|
||||
SetDBPassword(DBPassword);
|
||||
|
||||
_mysql = mysql_init(NULL);
|
||||
if(_mysql)
|
||||
{
|
||||
if (!mysql_real_connect(_mysql, GetServerName().c_str(), GetDBUsername().c_str(),
|
||||
GetDBPassword().c_str(), GetDatabaseName().c_str(), 0, NULL, 0))
|
||||
{
|
||||
cout << "MYSQL CONNECT FAILED: " << endl;
|
||||
cout << GetServerName() << endl;
|
||||
cout << GetDBUsername() << endl;
|
||||
cout << GetDBPassword() << endl;
|
||||
cout << GetDatabaseName() << endl;
|
||||
mysql_close(_mysql);
|
||||
_mysql = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EQEmuDatabase::~EQEmuDatabase()
|
||||
{
|
||||
if(_mysql)
|
||||
{
|
||||
mysql_close(_mysql);
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmuDatabase::GetPlayer(std::string name)
|
||||
{
|
||||
bool result = false;
|
||||
if(!_mysql)
|
||||
{
|
||||
cout << "NOT CONNECTED TO MYQSL: " << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char * mQuery = 0;
|
||||
MakeAnyLenString(&mQuery, "SELECT profile, id FROM character_ WHERE name='%s'", name.c_str());
|
||||
if (mysql_query(_mysql, mQuery)) {
|
||||
cout << "Query failed: " << mQuery << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
res = mysql_use_result(_mysql);
|
||||
if(res)
|
||||
{
|
||||
while ((row = mysql_fetch_row(res)) != NULL)
|
||||
{
|
||||
player_entry pe;
|
||||
pe.id = atoi(row[1]);
|
||||
pe.data = new char[sizeof(PlayerProfile_Struct)];
|
||||
memcpy(pe.data, row[0], sizeof(PlayerProfile_Struct));
|
||||
player_list.push_back(pe);
|
||||
|
||||
PlayerProfile_Struct *m_pp = (PlayerProfile_Struct*)pe.data;
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
delete[] mQuery;
|
||||
mQuery = 0;
|
||||
}
|
||||
|
||||
void EQEmuDatabase::GetPlayers()
|
||||
{
|
||||
bool result = false;
|
||||
if(!_mysql)
|
||||
{
|
||||
cout << "NOT CONNECTED TO MYQSL: " << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char * mQuery = 0;
|
||||
MakeAnyLenString(&mQuery, "SELECT profile, id FROM character_");
|
||||
if (mysql_query(_mysql, mQuery)) {
|
||||
cout << "Query failed: " << mQuery << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
res = mysql_use_result(_mysql);
|
||||
if(res)
|
||||
{
|
||||
while ((row = mysql_fetch_row(res)) != NULL)
|
||||
{
|
||||
player_entry pe;
|
||||
pe.id = atoi(row[1]);
|
||||
pe.data = new char[sizeof(PlayerProfile_Struct)];
|
||||
memcpy(pe.data, row[0], sizeof(PlayerProfile_Struct));
|
||||
player_list.push_back(pe);
|
||||
|
||||
PlayerProfile_Struct *m_pp = (PlayerProfile_Struct*)pe.data;
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
delete[] mQuery;
|
||||
mQuery = 0;
|
||||
}
|
||||
|
||||
void EQEmuDatabase::StorePlayer(int32 charid, char* data)
|
||||
{
|
||||
if(!_mysql)
|
||||
{
|
||||
cout << "NOT CONNECTED TO MYQSL: " << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
char *outbuffer = new char[2*sizeof(PlayerProfile_Struct) + 512];
|
||||
char *bptr = outbuffer;
|
||||
bptr += snprintf(bptr, 128, "UPDATE character_ SET profile='");
|
||||
bptr += mysql_real_escape_string(_mysql, bptr, (const char *) data, sizeof(PlayerProfile_Struct));
|
||||
snprintf(bptr, 128, "' WHERE id=%lu", charid);
|
||||
|
||||
if (mysql_query(_mysql, outbuffer)) {
|
||||
cout << "Query failed: " << outbuffer << endl;
|
||||
}
|
||||
|
||||
delete[] outbuffer;
|
||||
outbuffer = 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#if !defined(_L__EQDATAB__H)
|
||||
#define _L__EQDATAB__H
|
||||
|
||||
#include "misc_functions.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <mysql.h>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#pragma comment ( lib, "libmysql" )
|
||||
|
||||
class EQEmuDatabase {
|
||||
public:
|
||||
EQEmuDatabase(string serverName, string databaseName, string dbUsername, string dbPassword);
|
||||
~EQEmuDatabase();
|
||||
|
||||
bool Connected() { if(_mysql){ return true; }else{ return false; } }
|
||||
|
||||
void SetDBUsername(string dbUsername) { _dbUsername = dbUsername; };
|
||||
void SetDBPassword(string dbPassword) { _dbPassword = dbPassword; };
|
||||
void SetDatabaseName(string databaseName) { _databaseName = databaseName; };
|
||||
void SetServerName(string serverName) { _serverName = serverName; };
|
||||
string GetDBUsername() { return _dbUsername; };
|
||||
string GetDBPassword() { return _dbPassword; };
|
||||
string GetDatabaseName() { return _databaseName; };
|
||||
string GetServerName() { return _serverName; };
|
||||
|
||||
void GetPlayer(std::string name);
|
||||
void GetPlayers();
|
||||
void StorePlayer(int32 charid, char* data);
|
||||
|
||||
private:
|
||||
string _dbUsername;
|
||||
string _dbPassword;
|
||||
string _databaseName;
|
||||
string _serverName;
|
||||
MYSQL *_mysql;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
#ifndef EQEMU_STRING_H
|
||||
#define EQEMU_STRING_H
|
||||
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
|
||||
namespace EQEmuString
|
||||
{
|
||||
|
||||
std::string ToUpper(std::string in_string)
|
||||
{
|
||||
std::string out_string = in_string;
|
||||
for(unsigned int i = 0; i < in_string.size(); ++i)
|
||||
{
|
||||
out_string[i] = std::toupper(in_string[i]);
|
||||
}
|
||||
return out_string;
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "ini.h"
|
||||
|
||||
INIParser::INIParser(const char *filename)
|
||||
{
|
||||
memset(file, 0, 128);
|
||||
if(strlen(filename) > 128)
|
||||
{
|
||||
strncpy(file, filename, 128);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(file, filename, strlen(filename));
|
||||
}
|
||||
Parse();
|
||||
}
|
||||
|
||||
INIParser::~INIParser()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void INIParser::Parse()
|
||||
{
|
||||
FILE *fp;
|
||||
if(fp = fopen(file, "r"))
|
||||
{
|
||||
char Option[255], Param[255];
|
||||
while(!feof(fp))
|
||||
{
|
||||
ReadLine(fp, Option, Param);
|
||||
AddOption(std::string(Option), std::string(Param));
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void INIParser::ReadLine(FILE *fp, char *Option, char *Param)
|
||||
{
|
||||
typedef enum ReadingState { ReadingOption, ReadingParameter };
|
||||
|
||||
ReadingState State = ReadingOption;
|
||||
|
||||
int StrIndex = 0;
|
||||
char ch;
|
||||
|
||||
strcpy(Option, "");
|
||||
strcpy(Param, "");
|
||||
|
||||
while(true) {
|
||||
ch = fgetc(fp);
|
||||
if((ch=='#')&&(StrIndex==0)) { // Discard comment lines beginning with a hash
|
||||
while((ch!=EOF)&&(ch!='\n'))
|
||||
ch = fgetc(fp);
|
||||
|
||||
continue;
|
||||
}
|
||||
if(ch=='\r') continue;
|
||||
if((ch==EOF)||(ch=='\n')) {
|
||||
switch(State) {
|
||||
case ReadingOption: {
|
||||
Option[StrIndex]='\0';
|
||||
break;
|
||||
}
|
||||
case ReadingParameter: {
|
||||
Param[StrIndex] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if(ch=='=') {
|
||||
if(State==ReadingOption) {
|
||||
Option[StrIndex] = '\0';
|
||||
State = ReadingParameter;
|
||||
StrIndex = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch(State) {
|
||||
case ReadingOption: {
|
||||
Option[StrIndex++]=tolower(ch);
|
||||
break;
|
||||
}
|
||||
case ReadingParameter: {
|
||||
Param[StrIndex++]=ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!strcmp(Param,"true")) strcpy(Param,"1");
|
||||
if(!strcmp(Param,"false")) strcpy(Param,"0");
|
||||
}
|
||||
|
||||
void INIParser::AddOption(std::string option, std::string param)
|
||||
{
|
||||
for(unsigned int x = 0; x < options.size(); ++x)
|
||||
{
|
||||
if(options[x].option == option)
|
||||
return;
|
||||
}
|
||||
|
||||
iniData d;
|
||||
d.option = option;
|
||||
d.param = param;
|
||||
options.push_back(d);
|
||||
}
|
||||
|
||||
std::string INIParser::GetOption(std::string option)
|
||||
{
|
||||
for(unsigned int x = 0; x < options.size(); ++x)
|
||||
{
|
||||
if(options[x].option == option)
|
||||
return options[x].param;
|
||||
}
|
||||
return std::string("Not Found");
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef INI__H
|
||||
#define INI__H
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
struct iniData
|
||||
{
|
||||
std::string option;
|
||||
std::string param;
|
||||
};
|
||||
|
||||
class INIParser
|
||||
{
|
||||
public:
|
||||
INIParser(const char *filename);
|
||||
~INIParser();
|
||||
void Parse();
|
||||
void ReadLine(FILE *fp, char *Option, char *Param);
|
||||
|
||||
void AddOption(std::string option, std::string param);
|
||||
std::string GetOption(std::string option);
|
||||
|
||||
|
||||
protected:
|
||||
char file[128];
|
||||
std::vector<iniData> options;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "eq_player_structs.h"
|
||||
#include "database.h"
|
||||
#include "ini.h"
|
||||
#include "main.h"
|
||||
#include "eqemu_string.h"
|
||||
|
||||
EQEmuDatabase *emu_db;
|
||||
std::vector<player_entry> player_list;
|
||||
|
||||
//player_profile_set [SET/VIEW] [Field] [Name/*]
|
||||
//ex: player_profile_set VIEW LDON_MMC Jess
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
INIParser *ini = new INIParser("database.ini");
|
||||
std::string host = ini->GetOption("host");
|
||||
std::string user = ini->GetOption("user");
|
||||
std::string pass = ini->GetOption("password");
|
||||
std::string datab = ini->GetOption("db");
|
||||
|
||||
if(argc != 5)
|
||||
{
|
||||
std::cout << "Usage: player_profile_set [SET/VIEW] [Field] [Value] [Name/*]" << std::endl;
|
||||
std::cout << "Ex: player_profile_set VIEW LDON_MMC 0 Jess" << std::endl;
|
||||
std::cout << "Would view the number of LDoN MMC points earned by Jess" << std::endl << std::endl;
|
||||
std::cout << "Ex: player_profile_set SET LDON_TOTAL 0 *" << std::endl;
|
||||
std::cout << "Would view the number of LDoN MMC points earned by All players to 0" << std::endl;
|
||||
delete ini;
|
||||
ini = 0;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string program_action = argv[1];
|
||||
std::string program_field = argv[2];
|
||||
std::string program_value = argv[3];
|
||||
std::string player_name = argv[4];
|
||||
program_action = EQEmuString::ToUpper(program_action);
|
||||
program_field = EQEmuString::ToUpper(program_field);
|
||||
|
||||
emu_db = new EQEmuDatabase(host.c_str(), datab.c_str(), user.c_str(), pass.c_str());
|
||||
if(!emu_db->Connected())
|
||||
{
|
||||
delete ini;
|
||||
ini = 0;
|
||||
delete emu_db;
|
||||
emu_db = 0;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(player_name == "*")
|
||||
emu_db->GetPlayers();
|
||||
else
|
||||
emu_db->GetPlayer(player_name);
|
||||
|
||||
std::vector<player_entry>::iterator iter = player_list.begin();
|
||||
|
||||
while(iter != player_list.end())
|
||||
{
|
||||
player_entry pe = (*iter);
|
||||
PlayerProfile_Struct *m_pp = (PlayerProfile_Struct*)pe.data;
|
||||
|
||||
if(program_action == "SET")
|
||||
{
|
||||
m_pp->ldon_points_available = 0;
|
||||
m_pp->ldon_points_guk = 0;
|
||||
m_pp->ldon_points_mir = 0;
|
||||
m_pp->ldon_points_mmc = 0;
|
||||
m_pp->ldon_points_ruj = 0;
|
||||
m_pp->ldon_points_tak = 0;
|
||||
emu_db->StorePlayer(pe.id, pe.data);
|
||||
}
|
||||
else if(program_action == "VIEW")
|
||||
{
|
||||
std::cout << m_pp->name << std::endl;
|
||||
std::cout << m_pp->ldon_points_available << std::endl;
|
||||
std::cout << m_pp->ldon_points_guk << std::endl;
|
||||
std::cout << m_pp->ldon_points_mir << std::endl;
|
||||
std::cout << m_pp->ldon_points_mmc << std::endl;
|
||||
std::cout << m_pp->ldon_points_ruj << std::endl;
|
||||
std::cout << m_pp->ldon_points_tak << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unknown action specified" << std::endl;
|
||||
}
|
||||
delete[] pe.data;
|
||||
pe.data = 0;
|
||||
iter++;
|
||||
}
|
||||
player_list.clear();
|
||||
|
||||
delete ini;
|
||||
ini = 0;
|
||||
delete emu_db;
|
||||
emu_db = 0;
|
||||
|
||||
std::cout << "Press enter to exit...";
|
||||
std::cin.get();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
std::string ConvertFieldToValue(PlayerProfile_Struct *m_pp, std::string field)
|
||||
{
|
||||
if(!m_pp)
|
||||
{
|
||||
return std::string("Unable to convert field to value");
|
||||
}
|
||||
|
||||
std::stringstream ss(std::stringstream::out | std::stringstream::in);
|
||||
|
||||
if(field == "LASTNAME")
|
||||
{
|
||||
ss << m_pp->last_name;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
if(field == "GENDER")
|
||||
{
|
||||
ss << m_pp->gender;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
if(field == "RACE")
|
||||
{
|
||||
ss << m_pp->race;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
if(field == "CLASS")
|
||||
{
|
||||
ss << m_pp->class_;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
return std::string("Unable to convert field to value");
|
||||
}
|
||||
|
||||
void ConvertValueToField(PlayerProfile_Struct *m_pp, std::string field, std::string value)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef EQ_MAIN_H
|
||||
#define EQ_MAIN_H
|
||||
|
||||
#include "types.h"
|
||||
#include "eq_player_structs.h"
|
||||
|
||||
struct player_entry
|
||||
{
|
||||
int32 id;
|
||||
char *data;
|
||||
};
|
||||
|
||||
std::string ConvertFieldToValue(PlayerProfile_Struct *m_pp, std::string field);
|
||||
void ConvertValueToField(PlayerProfile_Struct *m_pp, std::string field, std::string value);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,233 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="player_profile_set"
|
||||
ProjectGUID="{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}"
|
||||
RootNamespace="player_profile_set"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\database.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ini.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\main.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\MiscFunctions.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\database.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\eq_player_structs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\eqemu_string.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ini.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\main.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\MiscFunctions.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\types.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,110 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
// TODO: If we require signed or unsigned we should the s and u types..
|
||||
|
||||
typedef unsigned char int8;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short int16;
|
||||
typedef unsigned int int32;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef signed char sint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed short sint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed int sint32;
|
||||
|
||||
#ifdef WIN32
|
||||
#if defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64
|
||||
typedef unsigned __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef signed __int64 sint64;
|
||||
#else
|
||||
#error __int64 not supported
|
||||
#endif
|
||||
#else
|
||||
typedef unsigned long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
typedef signed long long sint64;
|
||||
//typedef __u64 int64;
|
||||
//typedef __u64 uint64;
|
||||
//typedef __s64 sint64;
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef enum { true, false } bool;
|
||||
#endif
|
||||
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
|
||||
typedef const char Const_char; //for perl XS
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#if (_MSC_VER < 1500)
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
typedef void ThreadReturnType;
|
||||
// #define THREAD_RETURN(x) return;
|
||||
#define THREAD_RETURN(x) _endthread(); return;
|
||||
#else
|
||||
typedef void* ThreadReturnType;
|
||||
// typedef int SOCKET;
|
||||
#define THREAD_RETURN(x) return(x);
|
||||
#endif
|
||||
|
||||
#define safe_delete(d) if(d) { delete d; d=0; }
|
||||
#define safe_delete_array(d) if(d) { delete[] d; d=0; }
|
||||
#define L32(i) ((int32) i)
|
||||
#define H32(i) ((int32) (i >> 32))
|
||||
#define L16(i) ((int16) i)
|
||||
|
||||
#ifndef WIN32
|
||||
// More WIN32 compatability
|
||||
typedef unsigned long DWORD;
|
||||
typedef unsigned char BYTE;
|
||||
typedef char CHAR;
|
||||
typedef unsigned short WORD;
|
||||
typedef float FLOAT;
|
||||
typedef FLOAT *PFLOAT;
|
||||
typedef BYTE *PBYTE,*LPBYTE;
|
||||
typedef int *PINT,*LPINT;
|
||||
typedef WORD *PWORD,*LPWORD;
|
||||
typedef long *LPLONG, LONG;
|
||||
typedef DWORD *PDWORD,*LPDWORD;
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT,*PUINT,*LPUINT;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#define DLLFUNC extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define DLLFUNC extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user