added source folders
This commit is contained in:
1 parent
f23521f720
commit
cfdc19df45
145 files changed
+54574
No files matched your search
@@ -0,0 +1,55 @@
|
||||
// Props to ExJam for this code :D
|
||||
|
||||
class CIntStb
|
||||
{
|
||||
public:
|
||||
CIntStb() : rows(0) {}
|
||||
CIntStb(char* filename) : rows(0){ LoadSTB(filename); }
|
||||
~CIntStb(){ CleanUp(); }
|
||||
|
||||
int LoadSTB( char* filename ){
|
||||
FILE* fh;
|
||||
char tmpfield[512];
|
||||
unsigned dataoffset = 0;
|
||||
unsigned short fieldlen = 0;
|
||||
|
||||
if ( (fh = fopen( filename, "rb" )) != 0 ) {
|
||||
Log( MSG_ERROR, "Could not load STB '%s'", filename );
|
||||
return 1;
|
||||
}else{
|
||||
fseek( fh, 4, SEEK_SET );
|
||||
fread( &dataoffset, 4, 1, fh );
|
||||
fread( &rowcount, 4, 1, fh );
|
||||
fread( &fieldcount, 4, 1, fh );
|
||||
|
||||
rowcount--;
|
||||
fieldcount--;
|
||||
|
||||
fseek( fh, dataoffset, SEEK_SET );
|
||||
int* tmp = new int[rowcount*fieldcount];
|
||||
rows = new int*[rowcount];
|
||||
for(dword i = 0; i < rowcount; i++ ) rows[i] = &tmp[i*fieldcount];
|
||||
for(dword j = 0; j < rowcount*fieldcount; j++) {
|
||||
fread( &fieldlen, 2, 1, fh );
|
||||
fread( tmpfield, 1, fieldlen, fh );
|
||||
tmpfield[fieldlen]=0;
|
||||
tmp[j] = atoi( tmpfield );
|
||||
}
|
||||
fclose( fh );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dword rowcount;
|
||||
dword fieldcount;
|
||||
int** rows;
|
||||
|
||||
private:
|
||||
void CleanUp(){
|
||||
if(rows != NULL){
|
||||
delete [] rows[0];
|
||||
delete [] rows;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
//Made by Caali
|
||||
|
||||
#define __CARRAY_HPP__
|
||||
|
||||
/* Includes */
|
||||
#include <memory.h>
|
||||
|
||||
/* Variable type definitions */
|
||||
typedef size_t CARRAY_SIZE;
|
||||
|
||||
/* Defines */
|
||||
#ifndef NULL
|
||||
# ifdef __cplusplus
|
||||
# define NULL 0
|
||||
# else
|
||||
# define NULL (void*)0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* A basic CArray class. It is being used because C++ has no function to get the actual size in memory of a pointer. */
|
||||
template <typename T>
|
||||
class CRoseArray
|
||||
{
|
||||
private:
|
||||
CARRAY_SIZE arraysize;
|
||||
public:
|
||||
T* arr;
|
||||
CRoseArray( CARRAY_SIZE arrsize )
|
||||
{
|
||||
this->arr = NULL;
|
||||
this->arraysize = 0;
|
||||
this->arr = new T[arrsize];
|
||||
if( this->arr != NULL )
|
||||
{
|
||||
this->arraysize = arrsize;
|
||||
Clean( );
|
||||
}
|
||||
}
|
||||
|
||||
~CRoseArray( )
|
||||
{
|
||||
if( this->arr != NULL )
|
||||
{
|
||||
delete[] this->arr;
|
||||
this->arraysize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void resize( CARRAY_SIZE newsize )
|
||||
{
|
||||
if( this->arr == NULL ) return;
|
||||
T* tmp = new T[(size_t)(this->arraysize)];
|
||||
CARRAY_SIZE tmpsize = this->arraysize;
|
||||
memcpy( tmp, this->arr, (size_t)(this->arraysize*sizeof(T)) );
|
||||
delete[] this->arr;
|
||||
this->arr = new T[(size_t)(newsize)];
|
||||
if( this->arr != NULL )
|
||||
{
|
||||
memcpy( this->arr, tmp, (size_t)(tmpsize * sizeof(T)) );
|
||||
delete[] tmp;
|
||||
this->arraysize = newsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] tmp;
|
||||
this->arraysize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Clean( )
|
||||
{
|
||||
if( this->arr != NULL )
|
||||
{
|
||||
for( CARRAY_SIZE i = 0; i < this->arraysize; i++ )
|
||||
{
|
||||
this->arr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CARRAY_SIZE size()
|
||||
{
|
||||
return this->arraysize;
|
||||
}
|
||||
CARRAY_SIZE absSize()
|
||||
{
|
||||
return (this->arraysize*sizeof(T));
|
||||
}
|
||||
inline CRoseArray& operator = ( const CRoseArray& otherarr )
|
||||
{
|
||||
if( arr != NULL ) delete[] arr;
|
||||
arraysize = otherarr.arraysize;
|
||||
for( CARRAY_SIZE i = 0; i<size(); i++ ){
|
||||
arr[i] = otherarr.arr[i];
|
||||
}
|
||||
}
|
||||
inline bool operator == ( const CRoseArray& otherarr )
|
||||
{
|
||||
if( size() == otherarr.size() )
|
||||
{
|
||||
if( arr == NULL && otherarr.arr == NULL )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( CARRAY_SIZE i = 0; i<size(); i++ )
|
||||
{
|
||||
if( arr[i] != otherarr.arr[i] ) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator != ( const CRoseArray& otherarr )
|
||||
{
|
||||
return !(this == otherarr);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,941 @@
|
||||
//Made by Caali
|
||||
|
||||
#define __CROSEFILE_HPP__
|
||||
|
||||
/* Includes */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef __CARRAY_HPP__
|
||||
#include "CRoseArray.hpp"
|
||||
#endif
|
||||
|
||||
/* MS Visual C++ Deprecation control defines */
|
||||
#ifdef _MSC_VER
|
||||
# ifdef _CRT_SECURE_NO_DEPRECATE
|
||||
# define CFILE_NODEPRECATE
|
||||
# endif
|
||||
#else
|
||||
# define CFILE_NODEPRECATE
|
||||
#endif
|
||||
|
||||
//Debug:
|
||||
//#define CFILE_NOUNICODE
|
||||
|
||||
/* Various defines */
|
||||
#define CFILE_MAXLINELENGHT 255
|
||||
#define CFILE_UNICODE_HEADER 0xFEFF
|
||||
|
||||
/* Variable type declarations */
|
||||
/* ETC */
|
||||
typedef bool CFILE_BOOLEAN;
|
||||
typedef size_t CFILE_SIZE;
|
||||
|
||||
/* Unsigned */
|
||||
typedef unsigned long long int CFILE_ULONGLONG;
|
||||
typedef unsigned long int CFILE_ULONG;
|
||||
typedef unsigned int CFILE_UINT;
|
||||
typedef unsigned short int CFILE_USHORT;
|
||||
typedef unsigned char CFILE_UCHAR;
|
||||
|
||||
/* Signed */
|
||||
typedef signed long long int CFILE_SLONGLONG;
|
||||
typedef signed long int CFILE_SLONG;
|
||||
typedef signed int CFILE_SINT;
|
||||
typedef signed short int CFILE_SSHORT;
|
||||
typedef signed char CFILE_SCHAR;
|
||||
typedef char CFILE_CHAR;
|
||||
|
||||
/* File types */
|
||||
typedef enum
|
||||
{
|
||||
FT_NONE,
|
||||
FT_BINARY,
|
||||
FT_ASCII,
|
||||
FT_UNICODE
|
||||
} FILETYPE;
|
||||
/* File open modes */
|
||||
typedef enum
|
||||
{
|
||||
FM_NONE = 0,
|
||||
FM_READ = (1<<0),
|
||||
FM_WRITE = (1<<1),
|
||||
FM_CREATEIFDOESNTEXIST = (1<<2),
|
||||
FM_BINARY = (1<<3),
|
||||
FM_UNICODE = (1<<4),
|
||||
FM_READWRITE = (FM_READ | FM_WRITE),
|
||||
FM_RW = (FM_READWRITE | FM_CREATEIFDOESNTEXIST)
|
||||
} FILEMODE;
|
||||
|
||||
/* File errors */
|
||||
typedef enum
|
||||
{
|
||||
FE_SUCCESS = 0, //No error
|
||||
FE_EOF, //CFile::EndOfFile( ) == true
|
||||
FE_NOFILEOPENED, //fh == NULL
|
||||
FE_NORIGHTSFORACTION, //Like when trying to read when only opening in write mode
|
||||
FE_INTERNALERROR, //CFile-internal errors, supposed to destruct the CFile now!
|
||||
FE_UNICODENOTALLOWED, //#ifdef CFILE_NOUNICODE and file is unicode
|
||||
FE_UNABLETOOPENFILE //fopen( ) == NULL
|
||||
} FILEERROR;
|
||||
|
||||
/* The CFile class */
|
||||
class CRoseFile
|
||||
{
|
||||
private:
|
||||
/** The current filetype
|
||||
*/
|
||||
FILETYPE ftype;
|
||||
/** The last error occured
|
||||
*/
|
||||
FILEERROR flasterr;
|
||||
/** The current file open mode bitfield
|
||||
*/
|
||||
CFILE_CHAR fmode;
|
||||
/** Function to throw an error
|
||||
@param
|
||||
err: A FILEERROR
|
||||
*/
|
||||
void DoError( FILEERROR err )
|
||||
{
|
||||
flasterr = err;
|
||||
}
|
||||
/** Converts the bitfield file open mode to c standart ASCII open modes
|
||||
@param
|
||||
mode: A byte with the bitfield
|
||||
@result
|
||||
string with the ASCII string
|
||||
*/
|
||||
CFILE_CHAR* ConvertBitFieldFileModeToASCIIFileMode( CFILE_SCHAR mode )
|
||||
{
|
||||
CFILE_CHAR* result = new CFILE_CHAR[30];
|
||||
CFILE_UCHAR len = 0;
|
||||
for( CFILE_CHAR i = 0; i<30; i++ ) result[i] = 0x00;
|
||||
if( (mode & FM_READWRITE) == FM_READWRITE )
|
||||
{
|
||||
if( (mode & FM_CREATEIFDOESNTEXIST) == FM_CREATEIFDOESNTEXIST )
|
||||
{
|
||||
result[0] = 'w';
|
||||
result[1] = '+';
|
||||
len = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[0] = 'r';
|
||||
result[1] = '+';
|
||||
len = 2;
|
||||
}
|
||||
}
|
||||
else if( (mode & FM_READ) == FM_READ )
|
||||
{
|
||||
result[0] = 'r';
|
||||
len = 1;
|
||||
}
|
||||
else if( (mode & FM_WRITE) == FM_WRITE )
|
||||
{
|
||||
result[0] = 'w';
|
||||
len = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoError( FE_INTERNALERROR );
|
||||
delete[] result;
|
||||
return NULL;
|
||||
}
|
||||
if( (mode & FM_BINARY) == FM_BINARY )
|
||||
{
|
||||
result[len] = 'b';
|
||||
len++;
|
||||
}
|
||||
if( (mode & FM_UNICODE) == FM_UNICODE )
|
||||
{
|
||||
printf( (CFILE_CHAR*)result, 30, "%s, ccs=UNICODE", (CFILE_CHAR*)result );
|
||||
len += 13;
|
||||
}
|
||||
result[len] = 0x00;
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** The current filehandle
|
||||
*/
|
||||
FILE* fh;
|
||||
/** Contructor
|
||||
*/
|
||||
CRoseFile( )
|
||||
{
|
||||
fh = NULL;
|
||||
ftype = FT_NONE;
|
||||
fmode = FM_NONE;
|
||||
flasterr = FE_SUCCESS;
|
||||
}
|
||||
/** Contructor opening a file after contructing
|
||||
@param
|
||||
fname: A string with the filename
|
||||
@param
|
||||
mode: A bitfield using the FILETYPE enumerator to specify the fopen mode
|
||||
*/
|
||||
CRoseFile( CFILE_CHAR* fname, CFILE_CHAR mode )
|
||||
{
|
||||
fh = NULL;
|
||||
ftype = FT_NONE;
|
||||
fmode = FM_NONE;
|
||||
flasterr = FE_SUCCESS;
|
||||
Open( fname, mode );
|
||||
}
|
||||
|
||||
//Destructors
|
||||
~CRoseFile( )
|
||||
{
|
||||
if( fh != NULL ) Close( );
|
||||
}
|
||||
|
||||
/** Opens a file
|
||||
@param
|
||||
fname: A string with the filename
|
||||
@param
|
||||
mode: A bitfield using the FILETYPE enumerator to specify the fopen mode
|
||||
@result
|
||||
Boolean indicating if Open successed or failed
|
||||
@note
|
||||
If there is already an opened file, CFile will close it and open the new file
|
||||
*/
|
||||
CFILE_BOOLEAN Open( CFILE_CHAR* fname, CFILE_CHAR mode )
|
||||
{
|
||||
if( fh != NULL ) Close( );
|
||||
fmode = mode;
|
||||
CFILE_CHAR* fasciimode = ConvertBitFieldFileModeToASCIIFileMode( fmode );
|
||||
if( fasciimode == NULL )
|
||||
{
|
||||
DoError( FE_INTERNALERROR );
|
||||
return false;
|
||||
}
|
||||
if( (fmode & FM_BINARY) == FM_BINARY )
|
||||
{
|
||||
ftype = FT_BINARY;
|
||||
}
|
||||
#ifndef CFILE_NODEPRECATE
|
||||
if( fopen_s( &fh, fname, fasciimode ) == 0 )
|
||||
{
|
||||
#else
|
||||
if( ( fh = fopen( fname, fasciimode ) ) != NULL )
|
||||
{
|
||||
#endif
|
||||
delete[] fasciimode;
|
||||
//Check if unicode or ascii
|
||||
if( ftype != FT_BINARY )
|
||||
{
|
||||
CFILE_USHORT buf;
|
||||
Read( &buf, sizeof( buf ), 1 );
|
||||
if( buf == CFILE_UNICODE_HEADER )
|
||||
{
|
||||
#ifndef CFILE_NOUNICODE
|
||||
fmode |= FM_UNICODE;
|
||||
Close( );
|
||||
CFILE_CHAR* fasciimode = ConvertBitFieldFileModeToASCIIFileMode( fmode );
|
||||
//fasciimode = ConvertBitFieldFileModeToASCIIFileMode( fmode );
|
||||
if( fasciimode == NULL )
|
||||
{
|
||||
DoError( FE_INTERNALERROR );
|
||||
return false;
|
||||
}
|
||||
#ifndef CFILE_NODEPRECATE
|
||||
fopen_s( &fh, fname, fasciimode );
|
||||
#else
|
||||
fh = fopen( fname, fasciimode );
|
||||
#endif
|
||||
SetAbsPos( 2 );
|
||||
ftype = FT_UNICODE;
|
||||
#else
|
||||
DoError( FE_UNICODENOTALLOWED );
|
||||
Close( );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAbsPos( 0 );
|
||||
ftype = FT_ASCII;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAbsPos( 0 );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoError( FE_UNABLETOOPENFILE );
|
||||
fh = NULL;
|
||||
delete[] fasciimode;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Closes the current open file
|
||||
*/
|
||||
void Close( )
|
||||
{
|
||||
if( fh != 0 )
|
||||
{
|
||||
DoError( FE_SUCCESS );
|
||||
fclose( fh );
|
||||
fh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CFILE_BOOLEAN IsOpen( )
|
||||
{
|
||||
return (fh != NULL)?(true):(false);
|
||||
}
|
||||
|
||||
/** Returns if the file has been opened in read mode
|
||||
@result
|
||||
Boolean indicating if the current file has been opened in read mode
|
||||
*/
|
||||
CFILE_BOOLEAN IsRead( )
|
||||
{
|
||||
return ((fmode & FM_READ) == FM_READ)?(true):(false);
|
||||
}
|
||||
/** Returns if the file has been opened in write mode
|
||||
@result
|
||||
Boolean indicating if the current file has been opened in write mode
|
||||
*/
|
||||
CFILE_BOOLEAN IsWrite( )
|
||||
{
|
||||
return ((fmode & FM_WRITE) == FM_WRITE)?(true):(false);
|
||||
}
|
||||
/** Returns filehandle
|
||||
@result
|
||||
Returns the current filehandle
|
||||
*/
|
||||
FILE* FileHandle( )
|
||||
{
|
||||
return fh;
|
||||
}
|
||||
/** Returns filetype
|
||||
@result
|
||||
returns the current filetype
|
||||
*/
|
||||
FILETYPE FileType( )
|
||||
{
|
||||
return ftype;
|
||||
}
|
||||
/** Returns last error
|
||||
@result
|
||||
Returns the last error occured
|
||||
*/
|
||||
FILEERROR GetLastError( )
|
||||
{
|
||||
return flasterr;
|
||||
}
|
||||
|
||||
/** Moves the file position to a custom point
|
||||
@param
|
||||
offset: Indicates how many bytes to move from origin
|
||||
@param
|
||||
origin: SEEK_SET -> File start | SEEK_CUR -> Current position | SEEK_END -> Last byte in file
|
||||
@result
|
||||
Boolean indicating if the seek process has successed
|
||||
@note
|
||||
Offset can be negative, too.
|
||||
*/
|
||||
CFILE_BOOLEAN Seek( CFILE_SLONG offset, signed int origin )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return false;
|
||||
}
|
||||
if( fseek( fh, offset, origin ) == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/** Moves the file position to an absolute position from the file start
|
||||
@param
|
||||
offset: Indicates how many bytes to move from SEEK_SET
|
||||
@result
|
||||
Boolean indicating if the seek process has successed
|
||||
@note
|
||||
Offset MUST NOT be negative, else it will not do anything
|
||||
*/
|
||||
CFILE_BOOLEAN SetAbsPos( CFILE_SLONG offset )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return false;
|
||||
}
|
||||
if( offset < 0 )
|
||||
{
|
||||
DoError( FE_INTERNALERROR );
|
||||
return false;
|
||||
}
|
||||
return Seek(offset,SEEK_SET);
|
||||
}
|
||||
/** Moves the file position to the start of the file
|
||||
@result
|
||||
Boolean indicating if the rewinding process has successed
|
||||
@note
|
||||
This function checks if the file has been opened in unicode mode, and if so, it sets the pointer to 2,
|
||||
the start of the file AFTER the unicode file header
|
||||
*/
|
||||
CFILE_BOOLEAN GoToStart( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return false;
|
||||
}
|
||||
if( ftype == FT_ASCII || ftype == FT_BINARY )
|
||||
{
|
||||
return SetAbsPos( 0 );
|
||||
}
|
||||
else if( ftype == FT_UNICODE )
|
||||
{
|
||||
return SetAbsPos( 2 );
|
||||
}
|
||||
DoError( FE_INTERNALERROR );
|
||||
return false;
|
||||
}
|
||||
/** Tells the current position in the file
|
||||
@result
|
||||
Signed long indicating the absolute offset from SEEK_SET
|
||||
*/
|
||||
CFILE_SLONG Tell( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return EOF;
|
||||
}
|
||||
return ftell( fh );
|
||||
}
|
||||
/** Checks if the file position is set after the end of the file
|
||||
@result
|
||||
Boolean indicating if the file pointer is at the end of the file
|
||||
*/
|
||||
CFILE_BOOLEAN EndOfFile( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return true;
|
||||
}
|
||||
return (feof( fh )==0)?(false):(true);
|
||||
}
|
||||
/** Moves the file position to a custom point
|
||||
@result
|
||||
Unsigned long indicating the size of the file in bytes
|
||||
*/
|
||||
CFILE_ULONG FileSize( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
CFILE_SLONG tmp_offset = Tell( );
|
||||
if( tmp_offset < 0 ) return 0;
|
||||
Seek( 0, SEEK_END );
|
||||
CFILE_SLONG result = Tell( );
|
||||
SetAbsPos( tmp_offset );
|
||||
return result;
|
||||
}
|
||||
/** Reads from the file starting at the current position
|
||||
@param
|
||||
buf: A pointer to a buffer where the data will be stored
|
||||
@param
|
||||
element_size: The size of each block being read
|
||||
@param
|
||||
element_count: The number of blocks being read
|
||||
@result
|
||||
Unsigned int indicating the number of bytes read
|
||||
*/
|
||||
CFILE_UINT Read( void* buf, CFILE_SIZE element_size, CFILE_SIZE element_count = 1 )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
return (CFILE_UINT)( fread( buf, element_size, element_count, fh ) );
|
||||
}
|
||||
/** Reads from the file starting at [offset] relative to [origin]
|
||||
@param
|
||||
buf: A pointer to a buffer where the data will be stored
|
||||
@param
|
||||
element_size: The size of each block being read
|
||||
@param
|
||||
element_count: The number of blocks being read
|
||||
@param
|
||||
offset: The offset to start reading from, relative to [origin]
|
||||
@param
|
||||
origin: Where offset is relative to, SEEK_SET -> Beginning of file | SEEK_CUR -> Current position | SEEK_END -> End of file
|
||||
@result
|
||||
Unsigned int indicating the number of bytes read
|
||||
*/
|
||||
CFILE_UINT ReadFrom( void* buf, CFILE_UINT element_size, CFILE_UINT element_count, CFILE_SLONG offset, signed int origin = SEEK_SET )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
if( !Seek( offset, origin ) ) return 0;
|
||||
return (CFILE_UINT)( Read( buf, element_size, element_count ) );
|
||||
}
|
||||
/** Reads from the file starting at from and ending at to
|
||||
@param
|
||||
buf: A pointer to a buffer where the data will be stored
|
||||
@param
|
||||
from: The offset to start reading from, absolute, aka relative to SEEK_SET
|
||||
@param
|
||||
to: The offset to end reading at, absolute, aka relative to SEEK_SET
|
||||
@result
|
||||
Unsigned int indicating the number of bytes read
|
||||
@note
|
||||
If (to-from) > the size of buf, it throws an exception (-> access violation), so check it before calling this function!
|
||||
*/
|
||||
CFILE_UINT ReadFromTo( void* buf, CFILE_SLONG from, CFILE_SLONG to )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
if( to < from ) return 0;
|
||||
if( !SetAbsPos( from ) ) return 0;
|
||||
return (CFILE_UINT)( Read( buf, (to-from), 1 ) );
|
||||
}
|
||||
/** Reads one byte and returns it as signed char
|
||||
@result
|
||||
char with the byte read
|
||||
*/
|
||||
CFILE_CHAR GetC( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return EOF;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return EOF;
|
||||
}
|
||||
if( ftype == FT_ASCII || ftype == FT_BINARY )
|
||||
{
|
||||
return (CFILE_CHAR)( fgetc( fh ) );
|
||||
}
|
||||
else if( ftype == FT_UNICODE )
|
||||
{
|
||||
#ifndef CFILE_NOUNICODE
|
||||
CFILE_CHAR buf;
|
||||
wchar_t buffer;
|
||||
buffer = fgetwc( fh );
|
||||
#ifndef CFILE_NODEPRECATE
|
||||
size_t tmp;
|
||||
wcstombs_s( &tmp, &buf, (size_t)(sizeof(buf)), &buffer, 1 );
|
||||
#else
|
||||
wcstombs( &buf, &buffer, 1 );
|
||||
#endif
|
||||
return (CFILE_CHAR)buf;
|
||||
#else
|
||||
DoError( FE_UNICODENOTALLOWED );
|
||||
return EOF;
|
||||
#endif
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/** Reads from the file starting at from and ending at to
|
||||
@param
|
||||
buf: A pointer to a buffer where the data will be stored
|
||||
@param
|
||||
max_count: The maximum number of bytes to read
|
||||
@result
|
||||
string with the string read
|
||||
@note
|
||||
GetS either reads up to [max_count] bytes or until the end of one line has been reached. (0x0D 0x0A)
|
||||
@note
|
||||
If the file is opened in binary mode, GetS throws an error and does nothing
|
||||
*/
|
||||
CFILE_CHAR* GetS( CRoseArray<CFILE_CHAR>* buf, CFILE_UINT max_count )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return NULL;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return NULL;
|
||||
}
|
||||
if( ftype == FT_ASCII )
|
||||
{
|
||||
fgets( buf->arr, max_count, fh );
|
||||
return NULL;
|
||||
}
|
||||
else if( ftype == FT_UNICODE )
|
||||
{
|
||||
#ifndef CFILE_NOUNICODE
|
||||
wchar_t* buffer = new wchar_t[max_count];
|
||||
fgetws( buffer, max_count, fh );
|
||||
#ifndef CFILE_NODEPRECATE
|
||||
size_t tmp;
|
||||
wcstombs_s( &tmp, buf->arr, (size_t)(buf->absSize()), buffer, max_count );
|
||||
#else
|
||||
wcstombs( buf->arr, buffer, max_count );
|
||||
#endif
|
||||
return NULL;
|
||||
#else
|
||||
DoError( FE_UNICODENOTALLOWED );
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
DoError( FE_INTERNALERROR );
|
||||
return NULL;
|
||||
}
|
||||
/** Reads one line
|
||||
@result
|
||||
string with the line read
|
||||
@note
|
||||
If the file is opened in binary mode, the call to GetS throws an error and does nothing
|
||||
*/
|
||||
CFILE_CHAR* ReadLn( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return NULL;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return NULL;
|
||||
}
|
||||
if( EndOfFile( ) )
|
||||
{
|
||||
DoError( FE_INTERNALERROR );
|
||||
return NULL;
|
||||
}
|
||||
CRoseArray<CFILE_CHAR>* result = new CRoseArray<CFILE_CHAR>( CFILE_MAXLINELENGHT );
|
||||
result->Clean( );
|
||||
if( GetS( result, CFILE_MAXLINELENGHT ) == NULL )
|
||||
{
|
||||
CFILE_CHAR* res = new CFILE_CHAR[ (size_t)( result->size() ) ];
|
||||
for( CFILE_UINT i = 0;i<result->size(); i++ ) res[i] = 0x00;
|
||||
memcpy( res, result->arr, (size_t)(result->size()*sizeof(CFILE_CHAR)) );
|
||||
for( CFILE_UINT i = 0;i<CFILE_MAXLINELENGHT; i++ )
|
||||
{
|
||||
if( (CFILE_UCHAR)res[i] == 0x0D || (CFILE_UCHAR)res[i] == 0x0A )
|
||||
{
|
||||
if( (CFILE_ULONG)Tell( ) >= FileSize( ) - 2 )
|
||||
{
|
||||
delete result;
|
||||
delete[] res;
|
||||
return NULL;
|
||||
}
|
||||
res[i] = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete result;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoError( FE_INTERNALERROR );
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/** Template to read different types
|
||||
@<param>
|
||||
typename
|
||||
@result
|
||||
typename: the value being read
|
||||
*/
|
||||
template<typename T> T Get( )
|
||||
{
|
||||
T result;
|
||||
Read( &result, sizeof( T ), 1 );
|
||||
return result;
|
||||
}
|
||||
/*template<typename T> CVector2F Get( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return CVector2F(0,0);
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return CVector2F(0,0);
|
||||
}
|
||||
CVector2F result;
|
||||
Read( &result, sizeof( CVector2F ), 1 );
|
||||
return result;
|
||||
} */
|
||||
/** Reads the whole file into the memory
|
||||
@result
|
||||
string: pointer to the memory section, NULL on error
|
||||
@note
|
||||
The current file position pointer DOES NOT get affected by this function!
|
||||
*/
|
||||
/*string ReadFileToMemory( )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsRead( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
CFILE_SLONG curpos = Tell( );
|
||||
SetAbsPos( 0 );
|
||||
string mem = new char[(CFILE_SIZE)(FileSize( ))];
|
||||
if( mem == NULL ) //not enough RAM
|
||||
{
|
||||
SetAbsPos( curpos );
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( CFILE_UINT i = 0; i < FileSize( ); i++ ) mem[i] = 0x00;
|
||||
Read( mem, (CFILE_SIZE)(FileSize( )) );
|
||||
SetAbsPos( curpos );
|
||||
return mem;
|
||||
/*
|
||||
if( Read( mem, (CFILE_SIZE)(FileSize( )) ) != FileSize( ) )
|
||||
{
|
||||
delete[] mem;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAbsPos( curpos );
|
||||
return mem;
|
||||
}
|
||||
*
|
||||
}
|
||||
}*/
|
||||
|
||||
/** Writes to the file
|
||||
@param
|
||||
ptr: A pointer to a buffer where the data will be read to write from
|
||||
@param
|
||||
element_size: The size of one block being written
|
||||
@param
|
||||
element_count: The number of blocks being written
|
||||
@result
|
||||
unsigned int indicating the number of bytes being written
|
||||
*/
|
||||
CFILE_UINT Write( void* ptr, CFILE_SIZE element_size, CFILE_SIZE element_count=1 )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsWrite( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
return (CFILE_UINT)( fwrite( ptr, (size_t)( element_size ), (size_t)( element_count ), fh ) );
|
||||
}
|
||||
/** Writes to the file starting at [offset] bytes relative to [origin]
|
||||
@param
|
||||
ptr: A pointer to a buffer where the data will be read to write from
|
||||
@param
|
||||
element_size: The size of one block being written
|
||||
@param
|
||||
element_count: The number of blocks being written
|
||||
@param
|
||||
offset: The offset to start writing from, relative to [origin]
|
||||
@param
|
||||
origin: The position offset is relative to, SEEK_SET -> Start of file | SEEK_CUR -> Current position | SEEK_END -> End of file
|
||||
@result
|
||||
unsigned int indicating the number of bytes being written
|
||||
*/
|
||||
CFILE_UINT WriteFrom( void* ptr, CFILE_SIZE element_size, CFILE_SIZE element_count, CFILE_SLONG offset, signed int origin )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsWrite( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
if( !Seek( offset, origin ) ) return 0;
|
||||
return (CFILE_UINT)( Write( ptr, element_size, element_count ) );
|
||||
}
|
||||
/** Writes to the file, from [from] to [to]
|
||||
@param
|
||||
ptr: A pointer to a buffer where the data will be read to write from
|
||||
@param
|
||||
from: The absolute (aka relative to SEEK_SET) offset to start writing from
|
||||
@param
|
||||
to: The absolute (aka relative to SEEK_SET) offset to stop writing at
|
||||
@result
|
||||
unsigned int indicating the number of bytes being written
|
||||
@note
|
||||
If (to-from) > the size of ptr, it throws an exception, so check it before calling this function!
|
||||
*/
|
||||
CFILE_UINT WriteFromTo( void* ptr, CFILE_SLONG from, CFILE_SLONG to )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsWrite( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
if( to < from ) return 0;
|
||||
if( !SetAbsPos( from ) ) return 0;
|
||||
return (CFILE_UINT)( Write( ptr, (to-from), 1 ) );
|
||||
}
|
||||
/** Writes one byte to the file, as char
|
||||
@param
|
||||
chr: The byte to be written
|
||||
@result
|
||||
signed char: If success, it returns the char being written, else it returns EOF
|
||||
*/
|
||||
CFILE_SCHAR PutC( CFILE_SCHAR chr )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return EOF;
|
||||
}
|
||||
if( !IsWrite( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return EOF;
|
||||
}
|
||||
if( ftype == FT_ASCII || ftype == FT_BINARY )
|
||||
{
|
||||
return fputc( chr, fh );
|
||||
}
|
||||
else if( ftype == FT_UNICODE )
|
||||
{
|
||||
#ifndef CFILE_NOUNICODE
|
||||
wchar_t buffer;
|
||||
#ifndef CFILE_NODEPRECATE
|
||||
size_t tmp;
|
||||
mbstowcs_s( &tmp, &buffer, 1, (CFILE_CHAR*)(&chr), 1 );
|
||||
#else
|
||||
mbstowcs( &buffer, (CFILE_CHAR*)(&chr), 1 );
|
||||
#endif
|
||||
return (CFILE_SCHAR)(fputwc( buffer, fh ));
|
||||
#else
|
||||
DoError( FE_UNICODENOTALLOWED );
|
||||
return EOF;
|
||||
#endif
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/** Writes a string
|
||||
@param
|
||||
str: A string to the string to be written
|
||||
@result
|
||||
boolean indicating if writing the string has worked
|
||||
@note
|
||||
If the file is opened in binary mode, it throws an error and does nothing
|
||||
*/
|
||||
CFILE_BOOLEAN PutS( CRoseArray<CFILE_CHAR>* str )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return false;
|
||||
}
|
||||
if( !IsWrite( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return false;
|
||||
}
|
||||
if( ftype == FT_ASCII )
|
||||
{
|
||||
return (fputs( str->arr, fh )!=EOF)?(true):(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef CFILE_NOUNICODE
|
||||
wchar_t* buffer = new wchar_t[ (size_t)(str->size()) ];
|
||||
#ifndef CFILE_NODEPRECATE
|
||||
size_t tmp;
|
||||
mbstowcs_s( &tmp, buffer, (size_t)(str->size()), str->arr, (size_t)(str->size()) );
|
||||
#else
|
||||
mbstowcs( buffer, str->arr, str->size() );
|
||||
#endif
|
||||
return (fputws( buffer, fh )!=EOF)?(true):(false);
|
||||
#else
|
||||
DoError( FE_UNICODENOTALLOWED );
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
DoError( FE_INTERNALERROR );
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Template to write different types
|
||||
@<param>
|
||||
typename
|
||||
@param
|
||||
typename val: the value to be written
|
||||
@param
|
||||
cnt: times val will be written
|
||||
@result
|
||||
typename: If success, it returns the value being written, else it returns 0
|
||||
*/
|
||||
template<typename T> T Put( T val, CFILE_UINT cnt=1 )
|
||||
{
|
||||
if( fh == NULL )
|
||||
{
|
||||
DoError( FE_NOFILEOPENED );
|
||||
return 0;
|
||||
}
|
||||
if( !IsWrite( ) )
|
||||
{
|
||||
DoError( FE_NORIGHTSFORACTION );
|
||||
return 0;
|
||||
}
|
||||
return (Write( &val, sizeof( val ), cnt ) != 0)?(val):(0);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
// Props to ExJam for this code :D
|
||||
|
||||
class CStrStb
|
||||
{
|
||||
public:
|
||||
CStrStb():_Data(0){}
|
||||
CStrStb(const char* filename) : _Data(0){ LoadSTB(filename); }
|
||||
~CStrStb(){CleanUp();}
|
||||
|
||||
bool LoadSTB(const char* path)
|
||||
{
|
||||
CleanUp();
|
||||
|
||||
CRoseFile* fh = new CRoseFile((CFILE_CHAR*) path, FM_READ | FM_BINARY);
|
||||
if(!fh->IsOpen()){
|
||||
delete fh;
|
||||
return false;
|
||||
} // if is open
|
||||
|
||||
fh->Seek(4, SEEK_CUR);
|
||||
dword offset = fh->Get<dword>();
|
||||
|
||||
_Rows = fh->Get<dword>();
|
||||
_Columns = fh->Get<dword>();
|
||||
|
||||
_Rows--;
|
||||
_Columns--;
|
||||
|
||||
fh->SetAbsPos(offset);
|
||||
_Data = new char**[_Rows];
|
||||
for(dword i = 0; i < _Rows; i++)
|
||||
_Data[i] = new char*[_Columns];
|
||||
|
||||
for(dword i = 0; i < _Rows; i++){
|
||||
for(dword j = 0; j < _Columns; j++){
|
||||
dword len = fh->Get<word>();
|
||||
if(len == 0){
|
||||
_Data[i][j] = NULL;
|
||||
continue;
|
||||
} // if len
|
||||
_Data[i][j] = new char[len+1];
|
||||
fh->Read(_Data[i][j], len, 1);
|
||||
_Data[i][j][len] = 0;
|
||||
} // for j
|
||||
} // for i
|
||||
|
||||
fh->Close();
|
||||
delete fh;
|
||||
return true;
|
||||
} // bool
|
||||
|
||||
char* Data(dword Row, dword Column){
|
||||
if(Row > _Rows) return NULL;
|
||||
if(Column > _Columns) return NULL;
|
||||
|
||||
return _Data[Row][Column];
|
||||
}
|
||||
|
||||
dword Rows(){ return _Rows; }
|
||||
dword Columns(){ return _Columns; }
|
||||
|
||||
private:
|
||||
void CleanUp(){
|
||||
if(_Data != NULL){
|
||||
for(dword i = 0; i < _Rows; i++){
|
||||
for(dword j = 0; j < _Columns; j++){
|
||||
delete [] _Data[i][j];
|
||||
}
|
||||
delete [] _Data[i];
|
||||
}
|
||||
delete [] _Data;
|
||||
}
|
||||
_Rows = 0;
|
||||
_Columns = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
dword _Rows;
|
||||
dword _Columns;
|
||||
|
||||
char*** _Data;
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,242 @@
|
||||
// Props to ExJam for this code :D Ported to OSpRose by Drakia
|
||||
#pragma once
|
||||
#define QUESTREWD(reward) int QUEST_REWD_ ## reward (class CWorldServer* server, class CPlayer* client, byte* raw)
|
||||
typedef int (*fpQuestRewd)(class CWorldServer*, class CPlayer*, byte*);
|
||||
#define GETREWDDATA(rewd) STR_REWD_ ## rewd * data = (STR_REWD_ ## rewd *)raw
|
||||
|
||||
QUESTREWD(000);QUESTREWD(001);QUESTREWD(002);
|
||||
QUESTREWD(003);QUESTREWD(004);QUESTREWD(005);
|
||||
QUESTREWD(006);QUESTREWD(007);QUESTREWD(008);
|
||||
QUESTREWD(009);QUESTREWD(010);QUESTREWD(011);
|
||||
QUESTREWD(012);QUESTREWD(013);QUESTREWD(014);
|
||||
QUESTREWD(015);QUESTREWD(016);QUESTREWD(017);
|
||||
QUESTREWD(018);QUESTREWD(019);QUESTREWD(020);
|
||||
QUESTREWD(021);QUESTREWD(022);QUESTREWD(023);
|
||||
QUESTREWD(024);QUESTREWD(025);QUESTREWD(026);
|
||||
QUESTREWD(027);QUESTREWD(028);QUESTREWD(029);
|
||||
QUESTREWD(030);QUESTREWD(050);
|
||||
|
||||
struct STR_REWD_000 {
|
||||
dword iQuestSN;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_REWD_001 {
|
||||
dword uiItemSN;
|
||||
union {
|
||||
byte btOp;
|
||||
word nOp;
|
||||
};
|
||||
word nDupCNT;
|
||||
byte btPartyOpt;
|
||||
};
|
||||
|
||||
struct STR_REWD_002
|
||||
{
|
||||
dword iDataCnt;
|
||||
STR_QUEST_DATA* CheckData;
|
||||
};
|
||||
|
||||
struct STR_REWD_003
|
||||
{
|
||||
dword iDataCnt; //pos 0x00
|
||||
dword iType; //pos 0x04
|
||||
dword iValue; //pos 0x08
|
||||
byte btOp; //pos 0x0c
|
||||
//this (below original code) is just plain wrong
|
||||
//dword iDataCnt;
|
||||
//STR_ABIL_DATA* CheckData;
|
||||
//byte btPartyOpt;
|
||||
};
|
||||
|
||||
struct STR_REWD_004 {
|
||||
dword iDataCnt;
|
||||
STR_QUEST_DATA* CheckData;
|
||||
};
|
||||
|
||||
struct STR_REWD_005
|
||||
{
|
||||
byte btTarget; // pos 0x00
|
||||
//union
|
||||
//{
|
||||
// byte btEquation; // pos 0x02 apparently should be 0x01
|
||||
// word nEquation;
|
||||
//};
|
||||
byte btEquation; // pos 0x01
|
||||
word nEquation; // pos 0x02
|
||||
int iValue; // pos 0x04
|
||||
dword iItemSN; // pos 0x06
|
||||
union
|
||||
{
|
||||
byte btPartyOpt; // pos 0x0a
|
||||
word nPartyOpt;
|
||||
};
|
||||
word nItemOpt; // pos 0x0c
|
||||
};
|
||||
|
||||
struct STR_REWD_006 {
|
||||
dword iPercentOfHP;
|
||||
dword iPercentOfMP;
|
||||
byte btPartyOpt;
|
||||
};
|
||||
|
||||
struct STR_REWD_007 {
|
||||
dword iZoneSN;
|
||||
dword iX;
|
||||
dword iY;
|
||||
byte btPartyOpt;
|
||||
};
|
||||
|
||||
struct STR_REWD_008 {
|
||||
dword iMonsterSN;
|
||||
dword iHowMany;
|
||||
union {
|
||||
byte btWho;
|
||||
int iWho;
|
||||
};
|
||||
dword iZoneSN;
|
||||
dword iX;
|
||||
dword iY;
|
||||
dword iRange;
|
||||
dword iTeamNo;
|
||||
};
|
||||
|
||||
struct STR_REWD_009 {
|
||||
word shNameLen;
|
||||
string szNextTriggerSN;
|
||||
};
|
||||
|
||||
struct STR_REWD_010 {
|
||||
};
|
||||
|
||||
struct STR_REWD_011
|
||||
{
|
||||
union
|
||||
{
|
||||
byte btWho;
|
||||
word usWho;
|
||||
};
|
||||
word nVarNo;
|
||||
dword iValue;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_REWD_012 {
|
||||
union
|
||||
{
|
||||
byte btMsgType;
|
||||
int iMsgType;
|
||||
};
|
||||
dword iStrID;
|
||||
};
|
||||
|
||||
struct STR_REWD_013 {
|
||||
union {
|
||||
byte btWho;
|
||||
int iWho;
|
||||
};
|
||||
dword iSec;
|
||||
word nNameLength;
|
||||
string szTriggerName;
|
||||
dword m_HashNextTrigger;
|
||||
};
|
||||
|
||||
struct STR_REWD_014
|
||||
{
|
||||
union
|
||||
{
|
||||
byte btOp;
|
||||
int iOp;
|
||||
};
|
||||
dword iSkillNo;
|
||||
};
|
||||
|
||||
struct STR_REWD_015 {
|
||||
word nSN;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_REWD_016 {
|
||||
word nGroupSN;
|
||||
};
|
||||
|
||||
struct STR_REWD_017 {
|
||||
};
|
||||
|
||||
struct STR_REWD_018 {
|
||||
dword iStrID;
|
||||
word nCnt;
|
||||
string Data;
|
||||
};
|
||||
|
||||
struct STR_REWD_019
|
||||
{
|
||||
word nZoneNo; //pos 0x00
|
||||
word nTeamNo; //pos 0x02
|
||||
word nTriggerLength; //pos 0x04 This is definitely NOT the length of the following name. PY
|
||||
string TriggerName; //pos 0x06 + nTriggerlength more bytes. Name always appears to be 17 bytes long
|
||||
//dword m_HashTrigger;
|
||||
word m_HashTrigger; //pos 0x17 only has 2 bytes not 4. PY
|
||||
};
|
||||
|
||||
struct STR_REWD_020
|
||||
{
|
||||
byte btNoType;
|
||||
};
|
||||
|
||||
struct STR_REWD_021 {
|
||||
dword iX;
|
||||
dword iY;
|
||||
};
|
||||
|
||||
struct STR_REWD_022 {
|
||||
word nZonNo;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_REWD_023
|
||||
{
|
||||
};
|
||||
|
||||
struct STR_REWD_024 {
|
||||
int iMONEY;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_REWD_025 {
|
||||
short nPOINT;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_REWD_026 {
|
||||
word nSkillNo;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_REWD_027 {
|
||||
short nCONT;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_REWD_028 {
|
||||
dword iRange;
|
||||
word nZoneNo;
|
||||
dword iX;
|
||||
dword iY;
|
||||
};
|
||||
|
||||
struct STR_REWD_029 {
|
||||
word strLen;
|
||||
string LuaName;
|
||||
};
|
||||
|
||||
struct STR_REWD_030 //reset skills
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct STR_REWD_050 //respawn NPC after time delay
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,771 @@
|
||||
// Props to ExJam for this code :D Ported to OSpRose by Drakia
|
||||
#include "../WorldServer.h"
|
||||
|
||||
//Check Quest
|
||||
QUESTCOND(000)
|
||||
{
|
||||
GETCONDDATA(000);
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check quest: %i", data->iQuestSN);
|
||||
for(dword i = 0; i < 10; i++)
|
||||
{
|
||||
if(client->quest.quests[i].QuestID == data->iQuestSN)
|
||||
{
|
||||
client->CheckQuest = i;
|
||||
client->ActiveQuest = data->iQuestSN;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Quest - Found!");
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
}
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Quest - Not Found!");
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Check Quest Variable
|
||||
QUESTCOND(001)
|
||||
{
|
||||
// int iDataCnt pos 0x00
|
||||
// dword iType pos 0x02
|
||||
// short m_wVarNO pos 0x02
|
||||
// word m_wVarTYPE pos 0x04
|
||||
// word nValue pos 0x06
|
||||
// byte btOp pos 0x08
|
||||
GETCONDDATA(001);
|
||||
int retVal = 1;
|
||||
if( client->questdebug )server->SendPM(client, "Data Count for this quest %i",data->iDataCnt);
|
||||
for(int i = 0; i < data->iDataCnt; i++)
|
||||
{
|
||||
dword address = i * sizeof(STR_QUEST_DATA);
|
||||
address += (dword)data;
|
||||
address += 4;
|
||||
STR_QUEST_DATA* curQst = (STR_QUEST_DATA*)address;
|
||||
word nValue = curQst->nValue;
|
||||
word tempValue = client->GetQuestVar(curQst->m_wVarTYPE, curQst->m_wVarNO);
|
||||
//word tempValue = client->quest.quests[curQst->m_wVarTYPE].Variables[curQst->m_wVarNO];
|
||||
//retVal = OperateValues<word>(curQst->btOp, &tempValue, curQst->nValue);
|
||||
switch(curQst->btOp)
|
||||
{
|
||||
case 0:
|
||||
retVal = (tempValue == curQst->nValue);
|
||||
break;
|
||||
case 1:
|
||||
retVal = (tempValue > curQst->nValue);
|
||||
break;
|
||||
case 2:
|
||||
retVal = (tempValue >= curQst->nValue);
|
||||
break;
|
||||
case 3:
|
||||
retVal = (tempValue < curQst->nValue);
|
||||
break;
|
||||
case 4:
|
||||
retVal = (tempValue <= curQst->nValue);
|
||||
break;
|
||||
case 10:
|
||||
retVal = (tempValue != curQst->nValue);
|
||||
break;
|
||||
default:
|
||||
retVal = 0;
|
||||
Log( MSG_DEBUG, "QuestCond 001 bad value for btOp %i",curQst->btOp );
|
||||
break;
|
||||
}
|
||||
if( client->questdebug )
|
||||
{
|
||||
server->SendPM(client, "is %i < %i ? retval %i",tempValue, curQst->nValue, retVal);
|
||||
server->SendPM(client, "Check Quest Var[%04x][%i] - %i (Op: %i)", curQst->m_wVarTYPE, curQst->m_wVarNO, curQst->nValue, curQst->btOp);
|
||||
}
|
||||
if(retVal == 0) return QUEST_FAILURE;
|
||||
}
|
||||
return (retVal == 0)?QUEST_FAILURE:QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Quest Variable
|
||||
QUESTCOND(002)
|
||||
{
|
||||
return QUEST_COND_001(server, client, raw);
|
||||
}
|
||||
|
||||
//Check Stats
|
||||
QUESTCOND(003)
|
||||
{
|
||||
//dword iDataCnt; pos 0x00
|
||||
//dword iType; pos 0x04
|
||||
//dword iValue; pos 0x08
|
||||
//byte btOp; pos 0x0c
|
||||
GETCONDDATA(003);
|
||||
for(int i = 0; i < data->iDataCnt; i++)
|
||||
{
|
||||
dword address = i * 0x0C;
|
||||
address += (dword)data;
|
||||
address += 4;
|
||||
STR_ABIL_DATA* curAbil = (STR_ABIL_DATA*)address;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Stat[%i] %i (Op: %i)", curAbil->iType, curAbil->iValue, curAbil->btOp);
|
||||
int tempValue;
|
||||
switch( curAbil->iType )
|
||||
{
|
||||
case sGender:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->CharInfo->Sex, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sJob:
|
||||
tempValue = client->CharInfo->Job / 100;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Job Tempvalue = %i", tempValue);
|
||||
//if(!OperateValues<int>(curAbil->btOp, (int*)&tempValue, curAbil->iValue))
|
||||
if(!OperateValues<int>(curAbil->btOp, &tempValue, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sUnion: // Unions aren't implemented? - Drakia
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Union_s->unionvar[0], curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sStrength:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Str, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sDexterity:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Dex, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sIntelligence:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Int, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sConcentration:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Con, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sCharm:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Cha, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sSensibility:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Sen, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sLevel:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Stats->Level, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sStatPoints:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->CharInfo->StatPoints, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sMoney:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->CharInfo->Zulies, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sEXPRate:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Stats->xprate, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
default:
|
||||
Log(MSG_WARNING, "QuestCond 003: Type Unknown: '%i'", curAbil->iType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Items
|
||||
QUESTCOND(004)
|
||||
{
|
||||
GETCONDDATA(004);
|
||||
for(int i = 0; i < data->iDataCnt; i++)
|
||||
{
|
||||
dword address = i * 0x10;
|
||||
address += (dword)data;
|
||||
address += 4;
|
||||
STR_ITEM_DATA* curItem = (STR_ITEM_DATA*)address;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Item - [Slot:%i][Type:%i]", curItem->iWhere, curItem->uiItemSN);
|
||||
// Check quest items for a specific amount
|
||||
if (curItem->iWhere == 13) // it's a quest item
|
||||
{
|
||||
// Ok, check the current Check'd quest.
|
||||
if (client->CheckQuest < 0) return QUEST_SUCCESS;
|
||||
unsigned int j = client->CheckQuest;
|
||||
bool Hasitem = false;
|
||||
bool FoundItem = false;
|
||||
for (unsigned int k = 0; k < 5; k++) //5 quest item slots
|
||||
{
|
||||
if (client->quest.quests[j].Items[k].itemnum == (curItem->uiItemSN % 1000))
|
||||
{
|
||||
FoundItem = true;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Operate - btOp: %i Val1: %i Val2: %i", curItem->btOp, client->quest.quests[j].Items[k].count, curItem->iRequestCnt);
|
||||
if(OperateValues<int>(curItem->btOp, (int*)(&client->quest.quests[j].Items[k].count), curItem->iRequestCnt))
|
||||
Hasitem = true;
|
||||
}
|
||||
}
|
||||
if(FoundItem == false) // didn't find any of the item in any of the quest slots
|
||||
{
|
||||
for (unsigned int k = 0; k < 5; k++) //Find the first empty slot
|
||||
{
|
||||
if (client->quest.quests[j].Items[k].count == 0 && Hasitem == false)
|
||||
{
|
||||
// Since the item doesn't exist, treat it as if there's 0 of them.
|
||||
int tempInt = 0;
|
||||
if(OperateValues<int>(curItem->btOp, &tempInt, curItem->iRequestCnt))
|
||||
Hasitem = true;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Requested item is not found. Comparing first empty slot instead");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Hasitem == false)
|
||||
{
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Requested item is not present. Returning quest failure");
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//item slot is not 13
|
||||
// Check equipped items for a specific item? - Drakia
|
||||
if(curItem->uiItemSN == 0 && curItem->iWhere != 0)
|
||||
{
|
||||
int itemHead = client->items[curItem->iWhere].itemtype;
|
||||
if(!OperateValues<int>(curItem->btOp, &itemHead, curItem->uiItemSN))
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "QuestCond 004 Returning Quest Success");
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Party
|
||||
QUESTCOND(005)
|
||||
{
|
||||
//byte btIsLeader pos 0x00
|
||||
//int iLevel pos 0x02
|
||||
//byte btReversed pos 0x04
|
||||
GETCONDDATA(005);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Near Point
|
||||
QUESTCOND(006)
|
||||
{
|
||||
//int iZoneSN; pos 0x00
|
||||
//int iX; pos 0x04
|
||||
//int iY; pos 0x08
|
||||
//int iZ; pos 0x0c
|
||||
//int iRadius; pos 0x10
|
||||
GETCONDDATA(006);
|
||||
client->UpdatePosition();
|
||||
if(data->iZoneSN != 0)
|
||||
{
|
||||
if(client->Position->Map != data->iZoneSN)
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
float dx = client->Position->current.x - (float)(data->iX / 100);
|
||||
float dy = client->Position->current.y - (float)(data->iY / 100);
|
||||
float distance = sqrt((dx*dx) + (dy*dy));
|
||||
return (distance < data->iRadius)?QUEST_SUCCESS:QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//World Time
|
||||
QUESTCOND(007)
|
||||
{
|
||||
//dword ulTime pos 0x00
|
||||
//dword ulEndTime pos 0x04
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Quest Time
|
||||
QUESTCOND(008)
|
||||
{
|
||||
//dword ulTime pos 0x00
|
||||
//byte btOp pos 0x04
|
||||
GETCONDDATA(008);
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "QuestTime - ulTime: %i btOp: %i", data->ulTime, data->btOp);
|
||||
if (client->CheckQuest < 0) return QUEST_FAILURE; // Not checking a quest, don't return success
|
||||
long int Time = 0;
|
||||
if (server->STB_QUEST.rows[client->quest.quests[client->CheckQuest].QuestID][1] > 0)
|
||||
{
|
||||
Time += client->quest.quests[client->CheckQuest].StartTime; // Start time
|
||||
Time += server->STB_QUEST.rows[client->quest.quests[client->CheckQuest].QuestID][1] * 10; // Time to finish
|
||||
Time -= time(NULL); // Current time
|
||||
if (Time < 0) Time = 0; // Time is up
|
||||
Time /= 10; // Divide to get 10's of seconds
|
||||
}
|
||||
if (!OperateValues<dword>(data->btOp, (dword*)&Time, data->ulTime))
|
||||
return QUEST_FAILURE;
|
||||
else
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Skill
|
||||
QUESTCOND(009)
|
||||
{
|
||||
//int iSkillSN1 pos 0x00
|
||||
//int iSkillSN2 pos 0x02
|
||||
//byte btOp pos 0x04
|
||||
GETCONDDATA(009);
|
||||
// Line not needed, never used - Drakia
|
||||
//int checkVal = (data->btOp)?QUEST_SUCCESS:QUEST_FAILURE;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Skill: %i", data->iSkillSN1);
|
||||
bool s1 = false;
|
||||
bool s2 = false;
|
||||
for(dword i = 0; i < 30; i++)
|
||||
{
|
||||
if(client->bskills[i] == data->iSkillSN1)
|
||||
s1 = true;
|
||||
if(client->bskills[i] == data->iSkillSN2)
|
||||
s2 = true;
|
||||
if(client->askill[i] == data->iSkillSN1)
|
||||
s1 = true;
|
||||
if(client->askill[i] == data->iSkillSN2)
|
||||
s2 = true;
|
||||
if(client->pskill[i] == data->iSkillSN1)
|
||||
s1 = true;
|
||||
if(client->pskill[i] == data->iSkillSN2)
|
||||
s2 = true;
|
||||
}
|
||||
if(data->btOp == 0)
|
||||
{
|
||||
if(s1 == false && s2 == false)
|
||||
return QUEST_SUCCESS; //true if player does not have either skill
|
||||
else
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(s1 == true || s2 == true)
|
||||
return QUEST_SUCCESS; //true if player has either skill
|
||||
else
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
//Log(MSG_DEBUG,"Questcond 009 btOp is neither 0 nor 1.");
|
||||
//return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Unknown
|
||||
QUESTCOND(010)
|
||||
{
|
||||
GETCONDDATA(010);
|
||||
//byte btLowPcnt; pos 0x00
|
||||
//byte btHighPcnt; pos 0x01
|
||||
// I think this is a percentage chance range.
|
||||
// might be something to do with the item count though???
|
||||
|
||||
//int randv = GServer->RandNumber(0,100);
|
||||
//if(randv >= data->btLowPcnt && randv <= data->btHighPcnt)return QUEST_SUCCESS;
|
||||
|
||||
// problem is that this is only called in quest triggers from the client where it has already
|
||||
// passed the random number test.
|
||||
// we need to always return true or some quests will never finish
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Object Variable
|
||||
QUESTCOND(011)
|
||||
{
|
||||
|
||||
//byte btWho pos 0x00
|
||||
//word nVarNo pos 0x02
|
||||
//int iValue pos 0x04
|
||||
//byte btOp pos 0x09
|
||||
//if(entity->_EntityType != ENTITY_NPC) return QUEST_FAILURE;
|
||||
GETCONDDATA(011);
|
||||
/*
|
||||
if(data->btWho == 0)
|
||||
{
|
||||
CNpc* thisNpc = reinterpret_cast<CNpc*>(entity);
|
||||
thisNpc = thisNpc->SelectedNpc;
|
||||
if(thisNpc == NULL) return QUEST_FAILURE;
|
||||
|
||||
short VarValue = thisNpc->ObjVar.GetVar(data->nVarNo);
|
||||
if(OperateValues(data->btOp, &VarValue, (short)data->iValue)) return QUEST_SUCCESS;
|
||||
}*/
|
||||
if(data->btWho == 0)
|
||||
{
|
||||
|
||||
if(data->nVarNo > 19) return AI_FAILURE;
|
||||
int refVal = GServer->ObjVar[client->NPCvar][data->nVarNo];
|
||||
int tempval = 0;
|
||||
switch( data->btOp )
|
||||
{
|
||||
case 0:
|
||||
if(refVal == data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
if(refVal > data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 2:
|
||||
if(refVal >= data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 3:
|
||||
if(refVal < data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 4:
|
||||
if(refVal <= data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 10:
|
||||
if(refVal != data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
Log(MSG_WARNING,"Unknown btOp in QuestCond 011");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//check Proximity and Trigger in Zone
|
||||
QUESTCOND(012)
|
||||
{
|
||||
GETCONDDATA(012);
|
||||
//word iZone; pos 0x00
|
||||
//dword ulZone; pos 0x00
|
||||
//int iX; pos 0x04
|
||||
//int iY; pos 0x06
|
||||
//int iEventID; pos 0x08
|
||||
//dword m_HashEventOBJ; pos 0x08
|
||||
//this should be easy enough - PY
|
||||
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Select NPC
|
||||
QUESTCOND(013)
|
||||
{
|
||||
//int iNpcNo pos 0x00
|
||||
GETCONDDATA(013);
|
||||
// dammit!!!! This darn function is set up to use the CCharacter class so I can't use entity (CCharacter)
|
||||
// This is going to be a serious pain in the ass
|
||||
// OK so we now have a temporary player structure so we shuold be able to do this.
|
||||
|
||||
//Log(MSG_DEBUG,"Setting NPC ref number AICOND(017). NPC Ref = %i",data->iNpcNo);
|
||||
//CMonster* monster = reinterpret_cast<CMonster*>(entity);
|
||||
//if(monster == NULL) return AI_FAILURE;
|
||||
//monster->thisnpc->refNPC = data->iNpcNo; // sets the reference variable for the correct ObjVar
|
||||
//Log(MSG_DEBUG,"Set NPC ref number %i successfully", monster->thisnpc->refNPC);
|
||||
//not sure this is going to work properly for an NPC.
|
||||
//NPC only exists as a temporary entity so refNPC may be lost after it returns from here.
|
||||
|
||||
|
||||
/*if(entity->_EntityType != ENTITY_NPC) return QUEST_FAILURE;
|
||||
|
||||
CNpc* thisNpc = reinterpret_cast<CNpc*>(entity);
|
||||
std::map<dword, CNpc*>::iterator triggerITR = server->NpcList.find(data->iNpcNo);
|
||||
if(triggerITR == server->NpcList.end()){
|
||||
thisNpc->SelectedNpc = NULL;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
thisNpc->SelectedNpc = triggerITR->second;
|
||||
*/
|
||||
client->NPCvar = data->iNpcNo;
|
||||
//Actually that was kind of easy.. lol - PY
|
||||
|
||||
//return QUEST_SUCCESS;
|
||||
// More NPC specific stuff
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Quest Flag
|
||||
QUESTCOND(014)
|
||||
{
|
||||
GETCONDDATA(014);
|
||||
//word nSN; pos 0x00
|
||||
//byte btOp; pos 0x02
|
||||
bool dataOp = (data->btOp)?true:false;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check QFlag[%i] == %i", data->nSN, data->btOp);
|
||||
if(client->quest.GetFlag(data->nSN) == dataOp)
|
||||
{
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Quest cond 014 (check quest flag) returned Success");
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Quest cond 014 (check quest flag) returned Failure");
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
//Party member count between X and Y - PY
|
||||
QUESTCOND(015)
|
||||
{
|
||||
|
||||
//word nNumber1 pos 0x00
|
||||
//word nNumber2 pos 0x02
|
||||
GETCONDDATA(015);
|
||||
|
||||
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Zone Time
|
||||
QUESTCOND(016)
|
||||
{
|
||||
|
||||
//byte btWho pos 0x00
|
||||
//dword ulWho pos 0x00
|
||||
//dword ulTime pos 0x04
|
||||
//dword ulEndTime pos 0x08
|
||||
GETCONDDATA(016);
|
||||
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//NPC & Obj Variables?
|
||||
QUESTCOND(017)
|
||||
{
|
||||
//dword iNpcNo pos 0x00
|
||||
//word nVarNo pos 0x04
|
||||
//word unused pos 0x06
|
||||
//dword iNpcNo pos 0x08
|
||||
//word nVarNo pos 0x0c
|
||||
//word unused pos 0x0e
|
||||
//byte btOp pos 0x0f
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Time on Date
|
||||
QUESTCOND(018)
|
||||
{
|
||||
//Returns SUCCESS if the system time of the server is between the defined start and end times. Else returns FAILURE.
|
||||
//Allows for time dependent quests
|
||||
//byte btDate; pos 0x00
|
||||
//byte btHour1; pos 0x01
|
||||
//byte btMin1; pos 0x02
|
||||
//byte btHour2; pos 0x03
|
||||
//byte btMin2; pos 0x04
|
||||
GETCONDDATA(018);
|
||||
SYSTEMTIME sTIME;
|
||||
GetLocalTime(&sTIME);
|
||||
|
||||
if(data->btDate != 0)
|
||||
{
|
||||
if(sTIME.wDay != data->btDate)
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
word wMin = ((sTIME.wHour * 60) + sTIME.wMinute);
|
||||
word wFrom = (data->btHour1 * 60) + data->btMin1;
|
||||
word wTo = (data->btHour2 * 60) + data->btMin2;
|
||||
if(wMin >= wFrom && wMin <= wTo)
|
||||
return QUEST_SUCCESS;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Time on Day
|
||||
QUESTCOND(019)
|
||||
{
|
||||
//byte btWeekDay; pos 0x00
|
||||
//byte btHour1; pos 0x01
|
||||
//byte btMin1; pos 0x02
|
||||
//byte btHour2; pos 0x03
|
||||
//byte btMin2; pos 0x04
|
||||
GETCONDDATA(019);
|
||||
SYSTEMTIME sTIME;
|
||||
GetLocalTime(&sTIME);
|
||||
if(data->btWeekDay != 0)
|
||||
{
|
||||
if(sTIME.wDayOfWeek != data->btWeekDay)
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
word wMin = ((sTIME.wHour * 60) + sTIME.wMinute);
|
||||
word wFrom = (data->btHour1 * 60) + data->btMin1;
|
||||
word wTo = (data->btHour2 * 60) + data->btMin2;
|
||||
if(wMin >= wFrom && wMin <= wTo)
|
||||
return QUEST_SUCCESS;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Unknown
|
||||
QUESTCOND(020)
|
||||
{
|
||||
//int iNo1 pos 0x00
|
||||
//int iNo2 pos 0x02
|
||||
GETCONDDATA(020);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Unknown
|
||||
QUESTCOND(021)
|
||||
{
|
||||
// byte btSelObjType pos 0x00
|
||||
// byte iRadius pos 0x04
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Server/Channel
|
||||
QUESTCOND(022)
|
||||
{
|
||||
//word nX pos 0x00
|
||||
//word nY pos 0x02
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//In Clan?
|
||||
QUESTCOND(023)
|
||||
{
|
||||
//byte btReg pos 0x00
|
||||
GETCONDDATA(023);
|
||||
int Clanid = client->Clan->clanid;
|
||||
if(data->btReg == 0)
|
||||
{
|
||||
if(Clanid == 0)return QUEST_SUCCESS;
|
||||
else return QUEST_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Clanid != 0)return QUEST_SUCCESS;
|
||||
else return QUEST_FAILURE;
|
||||
}
|
||||
//btReg should only ever be 1 or 0 but just in case......
|
||||
//return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Clan Position
|
||||
QUESTCOND(024)
|
||||
{
|
||||
//check my current rank in the clan against data->nPOS using btOP
|
||||
GETCONDDATA(024);
|
||||
//word nPOS; pos 0x00
|
||||
//byte btOP; pos 0x02
|
||||
int myRank = client->Clan->clanrank;
|
||||
switch(data->btOP)
|
||||
{
|
||||
case 0:
|
||||
if(myRank == data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
if(myRank > data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 2:
|
||||
if(myRank >= data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 3:
|
||||
if(myRank < data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 4:
|
||||
if(myRank <= data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 10:
|
||||
if(myRank != data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Clan Contribution
|
||||
QUESTCOND(025)
|
||||
{
|
||||
//word nCONT pos 0x00
|
||||
//byte btOP pos 0x02
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Grade
|
||||
QUESTCOND(026)
|
||||
{
|
||||
//possibly compare client's current clan grade with data->nGRD using data->btOp?
|
||||
GETCONDDATA(026);
|
||||
//word nGRD;
|
||||
//byte btOP;
|
||||
int myGrade = client->Clan->grade;
|
||||
switch(data->btOP)
|
||||
{
|
||||
case 0:
|
||||
if(myGrade == data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
if(myGrade > data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 2:
|
||||
if(myGrade >= data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 3:
|
||||
if(myGrade < data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 4:
|
||||
if(myGrade <= data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 10:
|
||||
if(myGrade != data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Clan Points
|
||||
QUESTCOND(027)
|
||||
{
|
||||
//word nPOINT pos 0x00
|
||||
//byte btOP pos 0x02
|
||||
GETCONDDATA(027);
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "QUEST - Clan Points");
|
||||
switch(data->btOP)
|
||||
{
|
||||
case 0x01:
|
||||
BEGINPACKET( pak, 0x7e0 );
|
||||
ADDBYTE ( pak, 0x5C ); //action to update clan points (charserver)
|
||||
ADDWORD ( pak, client->Clan->clanid);
|
||||
ADDWORD ( pak, client->clientid );
|
||||
ADDDWORD ( pak, client->Clan->CP );
|
||||
ADDWORD ( pak, 0x00);
|
||||
GServer->SendISCPacket( &pak );
|
||||
break;
|
||||
//default:
|
||||
//break;
|
||||
}
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Funds
|
||||
QUESTCOND(028)
|
||||
{
|
||||
//word iMONEY; pos 0x00
|
||||
//byte btOP; pos 0x02
|
||||
GETCONDDATA(027);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Members
|
||||
QUESTCOND(029)
|
||||
{
|
||||
//word nMemberCNT; pos 0x00
|
||||
//byte btOP; pos 0x02
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Skills
|
||||
QUESTCOND(030)
|
||||
{
|
||||
//word nSkill1; pos 0x00
|
||||
//word nSkill2; pos 0x02
|
||||
//byte btOP; pos 0x05
|
||||
GETCONDDATA(030);
|
||||
//not sure what to do here. Looks like we compare something with two skill ids
|
||||
if( client->questdebug )server->SendPM(client, "Clan skills. Skill1: %i Skill2 %i btOP: %i",data->nSkill1,data->nSkill2,data->btOP);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,763 @@
|
||||
// Props to ExJam for this code :D Ported to OSpRose by Drakia
|
||||
#include "../WorldServer.h"
|
||||
|
||||
//Check Quest
|
||||
QUESTCOND(000)
|
||||
{
|
||||
GETCONDDATA(000);
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check quest: %i", data->iQuestSN);
|
||||
for(dword i = 0; i < 10; i++)
|
||||
{
|
||||
if(client->quest.quests[i].QuestID == data->iQuestSN)
|
||||
{
|
||||
client->CheckQuest = i;
|
||||
client->ActiveQuest = data->iQuestSN;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Quest # %i Found!", data->iQuestSN);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
}
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Quest - Not Found!");
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Check Quest Variable
|
||||
QUESTCOND(001)
|
||||
{
|
||||
// int iDataCnt pos 0x00
|
||||
// dword iType pos 0x02
|
||||
// short m_wVarNO pos 0x02
|
||||
// word m_wVarTYPE pos 0x04
|
||||
// word nValue pos 0x06
|
||||
// byte btOp pos 0x08
|
||||
GETCONDDATA(001);
|
||||
int retVal = 1;
|
||||
if( client->questdebug )server->SendPM(client, "Data Count for this quest %i",data->iDataCnt);
|
||||
for(int i = 0; i < data->iDataCnt; i++)
|
||||
{
|
||||
dword address = i * sizeof(STR_QUEST_DATA);
|
||||
address += (dword)data;
|
||||
address += 4;
|
||||
STR_QUEST_DATA* curQst = (STR_QUEST_DATA*)address;
|
||||
word nValue = curQst->nValue;
|
||||
word tempValue = client->GetQuestVar(curQst->m_wVarTYPE, curQst->m_wVarNO);
|
||||
//word tempValue = client->quest.quests[curQst->m_wVarTYPE].Variables[curQst->m_wVarNO];
|
||||
//retVal = OperateValues<word>(curQst->btOp, &tempValue, curQst->nValue);
|
||||
switch(curQst->btOp)
|
||||
{
|
||||
case 0:
|
||||
retVal = (tempValue == curQst->nValue);
|
||||
break;
|
||||
case 1:
|
||||
retVal = (tempValue > curQst->nValue);
|
||||
break;
|
||||
case 2:
|
||||
retVal = (tempValue >= curQst->nValue);
|
||||
break;
|
||||
case 3:
|
||||
retVal = (tempValue < curQst->nValue);
|
||||
break;
|
||||
case 4:
|
||||
retVal = (tempValue <= curQst->nValue);
|
||||
break;
|
||||
case 10:
|
||||
retVal = (tempValue != curQst->nValue);
|
||||
break;
|
||||
default:
|
||||
retVal = 0;
|
||||
Log( MSG_DEBUG, "QuestCond 001 bad value for btOp %i",curQst->btOp );
|
||||
break;
|
||||
}
|
||||
if( client->questdebug )
|
||||
{
|
||||
server->SendPM(client, "is %i < %i ? retval %i",tempValue, curQst->nValue, retVal);
|
||||
server->SendPM(client, "Check Quest Var[%04x][%i] - %i (Op: %i)", curQst->m_wVarTYPE, curQst->m_wVarNO, curQst->nValue, curQst->btOp);
|
||||
}
|
||||
if(retVal == 0) return QUEST_FAILURE;
|
||||
}
|
||||
return (retVal == 0)?QUEST_FAILURE:QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Quest Variable
|
||||
QUESTCOND(002)
|
||||
{
|
||||
return QUEST_COND_001(server, client, raw);
|
||||
}
|
||||
|
||||
//Check Stats
|
||||
QUESTCOND(003)
|
||||
{
|
||||
//dword iDataCnt; pos 0x00
|
||||
//dword iType; pos 0x04
|
||||
//dword iValue; pos 0x08
|
||||
//byte btOp; pos 0x0c
|
||||
GETCONDDATA(003);
|
||||
for(int i = 0; i < data->iDataCnt; i++)
|
||||
{
|
||||
dword address = i * 0x0C;
|
||||
address += (dword)data;
|
||||
address += 4;
|
||||
STR_ABIL_DATA* curAbil = (STR_ABIL_DATA*)address;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Stat[%i] %i (Op: %i)", curAbil->iType, curAbil->iValue, curAbil->btOp);
|
||||
int tempValue;
|
||||
switch( curAbil->iType )
|
||||
{
|
||||
case sGender:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->CharInfo->Sex, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sJob:
|
||||
tempValue = client->CharInfo->Job / 100;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Job Tempvalue = %i", tempValue);
|
||||
//if(!OperateValues<int>(curAbil->btOp, (int*)&tempValue, curAbil->iValue))
|
||||
if(!OperateValues<int>(curAbil->btOp, &tempValue, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sUnion: // Unions aren't implemented? - Drakia
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Union_s->unionvar[0], curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sStrength:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Str, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sDexterity:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Dex, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sIntelligence:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Int, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sConcentration:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Con, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sCharm:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Cha, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sSensibility:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Attr->Sen, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sLevel:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Stats->Level, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sStatPoints:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->CharInfo->StatPoints, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sMoney:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->CharInfo->Zulies, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
case sEXPRate:
|
||||
if(!OperateValues<int>(curAbil->btOp, (int*)&client->Stats->xprate, curAbil->iValue))
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
default:
|
||||
Log(MSG_WARNING, "QuestCond 003: Type Unknown: '%i'", curAbil->iType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Items
|
||||
QUESTCOND(004)
|
||||
{
|
||||
GETCONDDATA(004);
|
||||
for(int i = 0; i < data->iDataCnt; i++)
|
||||
{
|
||||
dword address = i * 0x10;
|
||||
address += (dword)data;
|
||||
address += 4;
|
||||
STR_ITEM_DATA* curItem = (STR_ITEM_DATA*)address;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Item - [Slot:%i][Type:%i]", curItem->iWhere, curItem->uiItemSN);
|
||||
// Check quest items for a specific amount
|
||||
if (curItem->iWhere == 13) // it's a quest item
|
||||
{
|
||||
// Ok, check the current Check'd quest.
|
||||
if (client->CheckQuest < 0) return QUEST_SUCCESS;
|
||||
unsigned int j = client->CheckQuest;
|
||||
bool Hasitem = false;
|
||||
bool FoundItem = false;
|
||||
for (unsigned int k = 0; k < 5; k++) //5 quest item slots
|
||||
{
|
||||
if (client->quest.quests[j].Items[k].itemnum == (curItem->uiItemSN % 1000))
|
||||
{
|
||||
FoundItem = true;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Operate - btOp: %i Val1: %i Val2: %i", curItem->btOp, client->quest.quests[j].Items[k].count, curItem->iRequestCnt);
|
||||
if(OperateValues<int>(curItem->btOp, (int*)(&client->quest.quests[j].Items[k].count), curItem->iRequestCnt))
|
||||
Hasitem = true;
|
||||
}
|
||||
}
|
||||
if(FoundItem == false) // didn't find any of the item in any of the quest slots
|
||||
{
|
||||
for (unsigned int k = 0; k < 5; k++) //Find the first empty slot
|
||||
{
|
||||
if (client->quest.quests[j].Items[k].count == 0 && Hasitem == false)
|
||||
{
|
||||
// Since the item doesn't exist, treat it as if there's 0 of them.
|
||||
int tempInt = 0;
|
||||
if(OperateValues<int>(curItem->btOp, &tempInt, curItem->iRequestCnt))
|
||||
Hasitem = true;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Requested item is not found. Comparing first empty slot instead");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Hasitem == false)
|
||||
{
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Requested item is not present. Returning quest failure");
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
}
|
||||
else //this needs to be recoded. It doesn't do a damn thing right now WTF?
|
||||
{
|
||||
//item slot is not 13
|
||||
// Check equipped items for a specific item? - Drakia
|
||||
if(curItem->uiItemSN == 0 && curItem->iWhere != 0)
|
||||
{
|
||||
int itemHead = client->items[curItem->iWhere].itemtype;
|
||||
if(!OperateValues<int>(curItem->btOp, &itemHead, curItem->uiItemSN))
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "QuestCond 004 Returning Quest Success");
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Party
|
||||
QUESTCOND(005)
|
||||
{
|
||||
//byte btIsLeader pos 0x00
|
||||
//int iLevel pos 0x04
|
||||
//byte btReversed pos 0x08
|
||||
GETCONDDATA(005);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Near Point
|
||||
QUESTCOND(006)
|
||||
{
|
||||
//int iZoneSN; pos 0x00
|
||||
//int iX; pos 0x04
|
||||
//int iY; pos 0x08
|
||||
//int iZ; pos 0x0c
|
||||
//int iRadius; pos 0x10
|
||||
GETCONDDATA(006);
|
||||
client->UpdatePosition();
|
||||
if(data->iZoneSN != 0)
|
||||
{
|
||||
if(client->Position->Map != data->iZoneSN)
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
float dx = client->Position->current.x - (float)(data->iX / 100);
|
||||
float dy = client->Position->current.y - (float)(data->iY / 100);
|
||||
float distance = sqrt((dx*dx) + (dy*dy));
|
||||
return (distance < data->iRadius)?QUEST_SUCCESS:QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//World Time
|
||||
QUESTCOND(007)
|
||||
{
|
||||
//dword ulTime pos 0x00
|
||||
//dword ulEndTime pos 0x04
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Quest Time
|
||||
QUESTCOND(008)
|
||||
{
|
||||
//dword ulTime pos 0x00
|
||||
//byte btOp pos 0x04
|
||||
GETCONDDATA(008);
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "QuestTime - ulTime: %i btOp: %i", data->ulTime, data->btOp);
|
||||
if (client->CheckQuest < 0) return QUEST_FAILURE; // Not checking a quest, don't return success
|
||||
long int Time = 0;
|
||||
if (server->STB_QUEST.rows[client->quest.quests[client->CheckQuest].QuestID][1] > 0)
|
||||
{
|
||||
Time += client->quest.quests[client->CheckQuest].StartTime; // Start time
|
||||
Time += server->STB_QUEST.rows[client->quest.quests[client->CheckQuest].QuestID][1] * 10; // Time to finish
|
||||
Time -= time(NULL); // Current time
|
||||
if (Time < 0) Time = 0; // Time is up
|
||||
Time /= 10; // Divide to get 10's of seconds
|
||||
}
|
||||
if (!OperateValues<dword>(data->btOp, (dword*)&Time, data->ulTime))
|
||||
return QUEST_FAILURE;
|
||||
else
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Skill
|
||||
QUESTCOND(009)
|
||||
{
|
||||
//int iSkillSN1 pos 0x00
|
||||
//int iSkillSN2 pos 0x02
|
||||
//byte btOp pos 0x04
|
||||
GETCONDDATA(009);
|
||||
// Line not needed, never used - Drakia
|
||||
//int checkVal = (data->btOp)?QUEST_SUCCESS:QUEST_FAILURE;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check Skill: %i", data->iSkillSN1);
|
||||
bool s1 = false;
|
||||
bool s2 = false;
|
||||
for(dword i = 0; i < 30; i++)
|
||||
{
|
||||
if(client->bskills[i] == data->iSkillSN1)
|
||||
s1 = true;
|
||||
if(client->bskills[i] == data->iSkillSN2)
|
||||
s2 = true;
|
||||
if(client->askill[i] == data->iSkillSN1)
|
||||
s1 = true;
|
||||
if(client->askill[i] == data->iSkillSN2)
|
||||
s2 = true;
|
||||
if(client->pskill[i] == data->iSkillSN1)
|
||||
s1 = true;
|
||||
if(client->pskill[i] == data->iSkillSN2)
|
||||
s2 = true;
|
||||
}
|
||||
if(data->btOp == 0)
|
||||
{
|
||||
if(s1 == false && s2 == false)
|
||||
return QUEST_SUCCESS; //true if player does not have either skill
|
||||
else
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(s1 == true || s2 == true)
|
||||
return QUEST_SUCCESS; //true if player has either skill
|
||||
else
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
//Log(MSG_DEBUG,"Questcond 009 btOp is neither 0 nor 1.");
|
||||
//return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//random number in range
|
||||
QUESTCOND(010)
|
||||
{
|
||||
GETCONDDATA(010);
|
||||
//byte btLowPcnt; pos 0x00
|
||||
//byte btHighPcnt; pos 0x01
|
||||
int randv = GServer->RandNumber(0,100);
|
||||
if(randv >= data->btLowPcnt && randv <= data->btHighPcnt)return QUEST_SUCCESS;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Object Variable
|
||||
QUESTCOND(011)
|
||||
{
|
||||
|
||||
//byte btWho pos 0x00
|
||||
//word nVarNo pos 0x02
|
||||
//int iValue pos 0x04
|
||||
//byte btOp pos 0x09
|
||||
GETCONDDATA(011);
|
||||
/*
|
||||
if(data->btWho == 0)
|
||||
{
|
||||
CNpc* thisNpc = reinterpret_cast<CNpc*>(entity);
|
||||
thisNpc = thisNpc->SelectedNpc;
|
||||
if(thisNpc == NULL) return QUEST_FAILURE;
|
||||
|
||||
short VarValue = thisNpc->ObjVar.GetVar(data->nVarNo);
|
||||
if(OperateValues(data->btOp, &VarValue, (short)data->iValue)) return QUEST_SUCCESS;
|
||||
}*/
|
||||
if(data->btWho == 0)
|
||||
{
|
||||
|
||||
if(data->nVarNo > 19) return AI_FAILURE;
|
||||
int refVal = GServer->ObjVar[client->NPCvar][data->nVarNo];
|
||||
int tempval = 0;
|
||||
switch( data->btOp )
|
||||
{
|
||||
case 0:
|
||||
if(refVal == data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
if(refVal > data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 2:
|
||||
if(refVal >= data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 3:
|
||||
if(refVal < data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 4:
|
||||
if(refVal <= data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
case 10:
|
||||
if(refVal != data->iValue)return QUEST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
Log(MSG_WARNING,"Unknown btOp in QuestCond 011");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//select event object
|
||||
QUESTCOND(012)
|
||||
{
|
||||
GETCONDDATA(012);
|
||||
//word iZone; pos 0x00
|
||||
//dword ulZone; pos 0x00
|
||||
//int iX; pos 0x04
|
||||
//int iY; pos 0x06
|
||||
//int iEventID; pos 0x08
|
||||
//dword m_HashEventOBJ; pos 0x08
|
||||
//this should be easy enough - PY
|
||||
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Select NPC
|
||||
QUESTCOND(013)
|
||||
{
|
||||
//int iNpcNo pos 0x00
|
||||
GETCONDDATA(013);
|
||||
// dammit!!!! This darn function is set up to use the CCharacter class so I can't use entity (CCharacter)
|
||||
// This is going to be a serious pain in the ass
|
||||
// OK so we now have a temporary player structure so we shuold be able to do this.
|
||||
|
||||
//Log(MSG_DEBUG,"Setting NPC ref number AICOND(017). NPC Ref = %i",data->iNpcNo);
|
||||
//CMonster* monster = reinterpret_cast<CMonster*>(entity);
|
||||
//if(monster == NULL) return AI_FAILURE;
|
||||
//monster->thisnpc->refNPC = data->iNpcNo; // sets the reference variable for the correct ObjVar
|
||||
//Log(MSG_DEBUG,"Set NPC ref number %i successfully", monster->thisnpc->refNPC);
|
||||
//not sure this is going to work properly for an NPC.
|
||||
//NPC only exists as a temporary entity so refNPC may be lost after it returns from here.
|
||||
|
||||
|
||||
/*if(entity->_EntityType != ENTITY_NPC) return QUEST_FAILURE;
|
||||
|
||||
CNpc* thisNpc = reinterpret_cast<CNpc*>(entity);
|
||||
std::map<dword, CNpc*>::iterator triggerITR = server->NpcList.find(data->iNpcNo);
|
||||
if(triggerITR == server->NpcList.end()){
|
||||
thisNpc->SelectedNpc = NULL;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
thisNpc->SelectedNpc = triggerITR->second;
|
||||
*/
|
||||
client->NPCvar = data->iNpcNo;
|
||||
//Actually that was kind of easy.. lol - PY
|
||||
|
||||
//return QUEST_SUCCESS;
|
||||
// More NPC specific stuff
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Quest Flag
|
||||
QUESTCOND(014)
|
||||
{
|
||||
GETCONDDATA(014);
|
||||
//word nSN; pos 0x00
|
||||
//byte btOp; pos 0x02
|
||||
bool dataOp = (data->btOp)?true:false;
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Check QFlag[%i] == %i", data->nSN, data->btOp);
|
||||
if(client->quest.GetFlag(data->nSN) == dataOp)
|
||||
{
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Quest cond 014 (check quest flag) returned Success");
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "Quest cond 014 (check quest flag) returned Failure");
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
//Party member count between X and Y - PY
|
||||
QUESTCOND(015)
|
||||
{
|
||||
|
||||
//word nNumber1 pos 0x00
|
||||
//word nNumber2 pos 0x02
|
||||
GETCONDDATA(015);
|
||||
|
||||
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Zone Time
|
||||
QUESTCOND(016)
|
||||
{
|
||||
|
||||
//byte btWho pos 0x00
|
||||
//dword ulWho pos 0x00
|
||||
//dword ulTime pos 0x04
|
||||
//dword ulEndTime pos 0x08
|
||||
GETCONDDATA(016);
|
||||
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//NPC & Obj Variables?
|
||||
QUESTCOND(017)
|
||||
{
|
||||
//dword iNpcNo pos 0x00
|
||||
//word nVarNo pos 0x04
|
||||
//word unused pos 0x06
|
||||
//dword iNpcNo pos 0x08
|
||||
//word nVarNo pos 0x0c
|
||||
//word unused pos 0x0e
|
||||
//byte btOp pos 0x0f
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Time on Date
|
||||
QUESTCOND(018)
|
||||
{
|
||||
//Returns SUCCESS if the system time of the server is between the defined start and end times. Else returns FAILURE.
|
||||
//Allows for time dependent quests
|
||||
//byte btDate; pos 0x00
|
||||
//byte btHour1; pos 0x01
|
||||
//byte btMin1; pos 0x02
|
||||
//byte btHour2; pos 0x03
|
||||
//byte btMin2; pos 0x04
|
||||
GETCONDDATA(018);
|
||||
SYSTEMTIME sTIME;
|
||||
GetLocalTime(&sTIME);
|
||||
|
||||
if(data->btDate != 0)
|
||||
{
|
||||
if(sTIME.wDay != data->btDate)
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
word wMin = ((sTIME.wHour * 60) + sTIME.wMinute);
|
||||
word wFrom = (data->btHour1 * 60) + data->btMin1;
|
||||
word wTo = (data->btHour2 * 60) + data->btMin2;
|
||||
if(wMin >= wFrom && wMin <= wTo)
|
||||
return QUEST_SUCCESS;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Time on Day
|
||||
QUESTCOND(019)
|
||||
{
|
||||
//byte btWeekDay; pos 0x00
|
||||
//byte btHour1; pos 0x01
|
||||
//byte btMin1; pos 0x02
|
||||
//byte btHour2; pos 0x03
|
||||
//byte btMin2; pos 0x04
|
||||
GETCONDDATA(019);
|
||||
SYSTEMTIME sTIME;
|
||||
GetLocalTime(&sTIME);
|
||||
if(data->btWeekDay != 0)
|
||||
{
|
||||
if(sTIME.wDayOfWeek != data->btWeekDay)
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
word wMin = ((sTIME.wHour * 60) + sTIME.wMinute);
|
||||
word wFrom = (data->btHour1 * 60) + data->btMin1;
|
||||
word wTo = (data->btHour2 * 60) + data->btMin2;
|
||||
if(wMin >= wFrom && wMin <= wTo)
|
||||
return QUEST_SUCCESS;
|
||||
return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Team number between iNo1 and iNo2
|
||||
QUESTCOND(020)
|
||||
{
|
||||
//int iNo1 pos 0x00
|
||||
//int iNo2 pos 0x02
|
||||
GETCONDDATA(020);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Distance check
|
||||
QUESTCOND(021)
|
||||
{
|
||||
// byte btSelObjType pos 0x00
|
||||
// byte iRadius pos 0x04
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Check Server/Channel
|
||||
QUESTCOND(022)
|
||||
{
|
||||
//word nX pos 0x00
|
||||
//word nY pos 0x02
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//In Clan?
|
||||
QUESTCOND(023)
|
||||
{
|
||||
//byte btReg pos 0x00
|
||||
GETCONDDATA(023);
|
||||
int Clanid = client->Clan->clanid;
|
||||
if(data->btReg == 0)
|
||||
{
|
||||
if(Clanid == 0)return QUEST_SUCCESS;
|
||||
else return QUEST_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Clanid != 0)return QUEST_SUCCESS;
|
||||
else return QUEST_FAILURE;
|
||||
}
|
||||
//btReg should only ever be 1 or 0 but just in case......
|
||||
//return QUEST_FAILURE;
|
||||
}
|
||||
|
||||
//Clan Position
|
||||
QUESTCOND(024)
|
||||
{
|
||||
//check my current rank in the clan against data->nPOS using btOP
|
||||
GETCONDDATA(024);
|
||||
//word nPOS; pos 0x00
|
||||
//byte btOP; pos 0x02
|
||||
int myRank = client->Clan->clanrank;
|
||||
switch(data->btOP)
|
||||
{
|
||||
case 0:
|
||||
if(myRank == data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
if(myRank > data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 2:
|
||||
if(myRank >= data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 3:
|
||||
if(myRank < data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 4:
|
||||
if(myRank <= data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 10:
|
||||
if(myRank != data->nPOS)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Clan Contribution
|
||||
QUESTCOND(025)
|
||||
{
|
||||
//word nCONT pos 0x00
|
||||
//byte btOP pos 0x02
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Grade
|
||||
QUESTCOND(026)
|
||||
{
|
||||
//possibly compare client's current clan grade with data->nGRD using data->btOp?
|
||||
GETCONDDATA(026);
|
||||
//word nGRD;
|
||||
//byte btOP;
|
||||
int myGrade = client->Clan->grade;
|
||||
switch(data->btOP)
|
||||
{
|
||||
case 0:
|
||||
if(myGrade == data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
if(myGrade > data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 2:
|
||||
if(myGrade >= data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 3:
|
||||
if(myGrade < data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 4:
|
||||
if(myGrade <= data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
case 10:
|
||||
if(myGrade != data->nGRD)
|
||||
return QUEST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
return QUEST_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Clan Points
|
||||
QUESTCOND(027)
|
||||
{
|
||||
//word nPOINT pos 0x00
|
||||
//byte btOP pos 0x02
|
||||
GETCONDDATA(027);
|
||||
if( client->questdebug )
|
||||
server->SendPM(client, "QUEST - Clan Points");
|
||||
switch(data->btOP)
|
||||
{
|
||||
case 0x01:
|
||||
BEGINPACKET( pak, 0x7e0 );
|
||||
ADDBYTE ( pak, 0x5C ); //action to update clan points (charserver)
|
||||
ADDWORD ( pak, client->Clan->clanid);
|
||||
ADDWORD ( pak, client->clientid );
|
||||
ADDDWORD ( pak, client->Clan->CP );
|
||||
ADDWORD ( pak, 0x00);
|
||||
GServer->SendISCPacket( &pak );
|
||||
break;
|
||||
//default:
|
||||
//break;
|
||||
}
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Funds
|
||||
QUESTCOND(028)
|
||||
{
|
||||
//word iMONEY; pos 0x00
|
||||
//byte btOP; pos 0x02
|
||||
GETCONDDATA(027);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Members
|
||||
QUESTCOND(029)
|
||||
{
|
||||
//word nMemberCNT; pos 0x00
|
||||
//byte btOP; pos 0x02
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
|
||||
//Clan Skills
|
||||
QUESTCOND(030)
|
||||
{
|
||||
//word nSkill1; pos 0x00
|
||||
//word nSkill2; pos 0x02
|
||||
//byte btOP; pos 0x05
|
||||
GETCONDDATA(030);
|
||||
//not sure what to do here. Looks like we compare something with two skill ids
|
||||
if( client->questdebug )server->SendPM(client, "Clan skills. Skill1: %i Skill2 %i btOP: %i",data->nSkill1,data->nSkill2,data->btOP);
|
||||
return QUEST_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
// Props to ExJam for this code :D Ported to OSpRose by Drakia
|
||||
#define QUESTCOND(cond) int QUEST_COND_ ## cond (class CWorldServer* server, class CPlayer* client, byte* raw)
|
||||
typedef int (*fpQuestCond)(class CWorldServer*, class CPlayer*, byte*);
|
||||
#define GETCONDDATA(cond) STR_COND_ ## cond * data = (STR_COND_ ## cond *)raw
|
||||
|
||||
QUESTCOND(000);QUESTCOND(001);QUESTCOND(002);
|
||||
QUESTCOND(003);QUESTCOND(004);QUESTCOND(005);
|
||||
QUESTCOND(006);QUESTCOND(007);QUESTCOND(008);
|
||||
QUESTCOND(009);QUESTCOND(010);QUESTCOND(011);
|
||||
QUESTCOND(012);QUESTCOND(013);QUESTCOND(014);
|
||||
QUESTCOND(015);QUESTCOND(016);QUESTCOND(017);
|
||||
QUESTCOND(018);QUESTCOND(019);QUESTCOND(020);
|
||||
QUESTCOND(021);QUESTCOND(022);QUESTCOND(023);
|
||||
QUESTCOND(024);QUESTCOND(025);QUESTCOND(026);
|
||||
QUESTCOND(027);QUESTCOND(028);QUESTCOND(029);
|
||||
QUESTCOND(030);
|
||||
|
||||
struct STR_COND_000
|
||||
{
|
||||
int iQuestSN;
|
||||
};
|
||||
|
||||
struct STR_COND_001
|
||||
{
|
||||
dword iDataCnt;
|
||||
//int iDataCnt;
|
||||
STR_QUEST_DATA* CheckData;
|
||||
};
|
||||
|
||||
struct STR_COND_002
|
||||
{
|
||||
dword iDataCnt;
|
||||
//int iDataCnt;
|
||||
STR_QUEST_DATA* CheckData;
|
||||
};
|
||||
|
||||
struct STR_COND_003
|
||||
{
|
||||
dword iDataCnt; //pos 0x00
|
||||
STR_ABIL_DATA* CheckData; // pos = variable. it repeats iDataCnt times
|
||||
};
|
||||
|
||||
struct STR_COND_004
|
||||
{
|
||||
dword iDataCnt; //pos 0x00
|
||||
STR_ITEM_DATA* CheckData; // pos = variable. it repeats iDataCnt times
|
||||
};
|
||||
|
||||
struct STR_COND_005
|
||||
{
|
||||
byte btIsLeader;
|
||||
int iLevel;
|
||||
byte btReversed;
|
||||
};
|
||||
|
||||
struct STR_COND_006
|
||||
{
|
||||
int iZoneSN; //pos 0x00
|
||||
int iX; //pos 0x04
|
||||
int iY; //pos 0x08
|
||||
int iZ; //pos 0x0c
|
||||
int iRadius; //pos 0x10
|
||||
};
|
||||
|
||||
struct STR_COND_007
|
||||
{
|
||||
dword ulTime;
|
||||
dword ulEndTime;
|
||||
};
|
||||
|
||||
struct STR_COND_008
|
||||
{
|
||||
dword ulTime;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_COND_009
|
||||
{
|
||||
int iSkillSN1;
|
||||
int iSkillSN2;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_COND_010
|
||||
{
|
||||
byte btLowPcnt;
|
||||
byte btHighPcnt;
|
||||
};
|
||||
|
||||
struct STR_COND_011
|
||||
{
|
||||
union
|
||||
{
|
||||
byte btWho; //pos 0x00
|
||||
word usWho;
|
||||
};
|
||||
word nVarNo; //pos 0x02
|
||||
int iValue; //pos 0x04
|
||||
byte btOp; //pos 0x09
|
||||
};
|
||||
|
||||
struct STR_COND_012
|
||||
{
|
||||
union
|
||||
{
|
||||
word iZone;
|
||||
dword ulZone;
|
||||
};
|
||||
int iX;
|
||||
int iY;
|
||||
union
|
||||
{
|
||||
int iEventID;
|
||||
dword m_HashEventOBJ;
|
||||
};
|
||||
};
|
||||
|
||||
struct STR_COND_013
|
||||
{
|
||||
int iNpcNo;
|
||||
};
|
||||
|
||||
struct STR_COND_014
|
||||
{
|
||||
word nSN;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_COND_015
|
||||
{
|
||||
word nNumber1;
|
||||
word nNumber2;
|
||||
};
|
||||
|
||||
struct STR_COND_016
|
||||
{
|
||||
union
|
||||
{
|
||||
byte btWho;
|
||||
dword ulWho;
|
||||
};
|
||||
dword ulTime;
|
||||
dword ulEndTime;
|
||||
};
|
||||
|
||||
struct STR_COND_017
|
||||
{
|
||||
STR_NPCVAR NpcVar1;
|
||||
STR_NPCVAR NpcVar2;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_COND_018
|
||||
{
|
||||
byte btDate;
|
||||
byte btHour1;
|
||||
byte btMin1;
|
||||
byte btHour2;
|
||||
byte btMin2;
|
||||
};
|
||||
|
||||
struct STR_COND_019
|
||||
{
|
||||
byte btWeekDay;
|
||||
byte btHour1;
|
||||
byte btMin1;
|
||||
byte btHour2;
|
||||
byte btMin2;
|
||||
};
|
||||
|
||||
struct STR_COND_020
|
||||
{
|
||||
int iNo1;
|
||||
int iNo2;
|
||||
};
|
||||
|
||||
struct STR_COND_021
|
||||
{
|
||||
union
|
||||
{
|
||||
byte btSelObjType;
|
||||
dword ulSelObjType;
|
||||
};
|
||||
int iRadius;
|
||||
};
|
||||
|
||||
struct STR_COND_022
|
||||
{
|
||||
word nX;
|
||||
word nY;
|
||||
};
|
||||
|
||||
struct STR_COND_023
|
||||
{
|
||||
byte btReg;
|
||||
};
|
||||
|
||||
struct STR_COND_024
|
||||
{
|
||||
word nPOS;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_COND_025
|
||||
{
|
||||
word nCONT;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_COND_026
|
||||
{
|
||||
word nGRD;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_COND_027
|
||||
{
|
||||
word nPOINT;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_COND_028
|
||||
{
|
||||
word iMONEY;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_COND_029
|
||||
{
|
||||
word nMemberCNT;
|
||||
byte btOP;
|
||||
};
|
||||
|
||||
struct STR_COND_030
|
||||
{
|
||||
word nSkill1;
|
||||
word nSkill2;
|
||||
byte btOP;
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
// Props to ExJam for this code :D Ported to OSpRose by Drakia
|
||||
class CQuestTrigger {
|
||||
public:
|
||||
struct SQuestDatum {
|
||||
int size;
|
||||
int opcode;
|
||||
byte* data;
|
||||
};
|
||||
|
||||
strings TriggerName;
|
||||
dword TriggerHash;
|
||||
|
||||
byte CheckNext;
|
||||
dword id;
|
||||
|
||||
dword ConditionCount;
|
||||
SQuestDatum** Conditions;
|
||||
|
||||
dword ActionCount;
|
||||
SQuestDatum** Actions;
|
||||
private:
|
||||
};
|
||||
|
||||
struct STR_NPCVAR {
|
||||
dword iNpcNo;
|
||||
word nVarNo;
|
||||
word unused;
|
||||
};
|
||||
|
||||
struct STR_ITEM_DATA {
|
||||
dword uiItemSN;
|
||||
dword iWhere;
|
||||
dword iRequestCnt;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_QUEST_DATA
|
||||
{
|
||||
union
|
||||
{
|
||||
dword iType;
|
||||
struct
|
||||
{
|
||||
short m_wVarNO;
|
||||
word m_wVarTYPE;
|
||||
};
|
||||
};
|
||||
word nValue;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
struct STR_ABIL_DATA
|
||||
{
|
||||
dword iType;
|
||||
int iValue;
|
||||
byte btOp;
|
||||
};
|
||||
|
||||
#define QUEST_FAILURE 6
|
||||
#define QUEST_SUCCESS 5
|
||||
template <class T> int OperateValues(byte btOp, T* value1PTR, T value2)
|
||||
{
|
||||
T value1 = *value1PTR;
|
||||
switch(btOp)
|
||||
{
|
||||
case 0:
|
||||
return (value1 == value2);
|
||||
case 1:
|
||||
return (value1 > value2);
|
||||
case 2:
|
||||
return (value1 >= value2);
|
||||
case 3:
|
||||
return (value1 < value2);
|
||||
case 4:
|
||||
return (value1 <= value2);
|
||||
case 5:
|
||||
(*value1PTR) = value2;
|
||||
return 1;
|
||||
case 6:
|
||||
(*value1PTR) = value1 + value2;
|
||||
return 1;
|
||||
case 7:
|
||||
(*value1PTR) = value1 - value2;
|
||||
return 1;
|
||||
case 9:
|
||||
(*value1PTR) += 1;
|
||||
return 1;
|
||||
case 10:
|
||||
return (value1 != value2);
|
||||
default:
|
||||
Log(MSG_WARNING, "OperateValues unknown btOp='%u'", btOp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dword GetRewardValue(dword function, dword amount, CPlayer* client, word nDupCNT);
|
||||
|
||||
#include "QuestConditions.h"
|
||||
#include "QuestActions.h"
|
||||
@@ -0,0 +1,157 @@
|
||||
// Props to ExJam for this code :D
|
||||
#include "../WorldServer.h"
|
||||
#include "QuestActions.h"
|
||||
|
||||
void CWorldServer::ReadQSD(strings path, dword index){
|
||||
CRoseFile* fh = new CRoseFile(path, FM_READ | FM_BINARY);
|
||||
|
||||
if(fh->IsOpen())
|
||||
{ // goto done;
|
||||
|
||||
//Log(MSG_LOAD, "Loading %s ", path);
|
||||
|
||||
fh->Seek(4, SEEK_CUR);
|
||||
dword BlockCount = fh->Get<dword>();
|
||||
fh->Seek(fh->Get<word>(), SEEK_CUR);
|
||||
for(dword i = 0; i < BlockCount; i++)
|
||||
{
|
||||
dword RecordCount = fh->Get<dword>();
|
||||
fh->Seek(fh->Get<word>(), SEEK_CUR);
|
||||
for(dword j = 0; j < RecordCount; j++)
|
||||
{
|
||||
CQuestTrigger* trigger = new CQuestTrigger();
|
||||
trigger->id=((index*0x10000)+(i*0x100)+j);
|
||||
trigger->CheckNext = fh->Get<byte>();
|
||||
trigger->ConditionCount = fh->Get<dword>();
|
||||
trigger->ActionCount = fh->Get<dword>();
|
||||
dword len = fh->Get<word>();
|
||||
trigger->TriggerName = new char[len+1];
|
||||
fh->Read(trigger->TriggerName, len, 1);
|
||||
trigger->TriggerName[len] = 0;
|
||||
|
||||
if(trigger->ConditionCount > 0)
|
||||
{
|
||||
trigger->Conditions = new CQuestTrigger::SQuestDatum*[trigger->ConditionCount];
|
||||
for(dword k = 0; k < trigger->ConditionCount; k++)
|
||||
{
|
||||
CQuestTrigger::SQuestDatum* data = new CQuestTrigger::SQuestDatum();
|
||||
data->size = fh->Get<int>();
|
||||
data->opcode = fh->Get<int>();
|
||||
data->data = new byte[data->size - 8];
|
||||
fh->Read(data->data, data->size - 8, 1);
|
||||
trigger->Conditions[k] = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger->Conditions = NULL;
|
||||
}
|
||||
|
||||
if(trigger->ActionCount > 0)
|
||||
{
|
||||
trigger->Actions = new CQuestTrigger::SQuestDatum*[trigger->ActionCount];
|
||||
for(dword k = 0; k < trigger->ActionCount; k++)
|
||||
{
|
||||
CQuestTrigger::SQuestDatum* data = new CQuestTrigger::SQuestDatum();
|
||||
data->size = fh->Get<int>();
|
||||
data->opcode = fh->Get<int>() - 0x01000000;
|
||||
data->data = new byte[data->size - 8];
|
||||
fh->Read(data->data, data->size - 8, 1);
|
||||
trigger->Actions[k] = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger->Actions = NULL;
|
||||
}
|
||||
|
||||
trigger->TriggerHash = MakeStrHash(trigger->TriggerName);
|
||||
TriggerList.push_back( trigger );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Log( MSG_ERROR, "QSD File: '%s' did not load properly", path );
|
||||
|
||||
fh->Close();
|
||||
delete fh;
|
||||
}
|
||||
|
||||
void CWorldServer::LoadQuestData(){
|
||||
CStrStb* stbQuest = new CStrStb("3DDATA\\STB\\LIST_QUESTDATA.STB");
|
||||
Log(MSG_INFO, "Loading QSD files");
|
||||
for(dword i = 1; i < stbQuest->Rows(); i++){
|
||||
if(stbQuest->Data(i, 0)){
|
||||
GServer->ReadQSD(stbQuest->Data(i, 0),i);
|
||||
}
|
||||
}
|
||||
|
||||
Log(MSG_INFO, "Finished loading quest data ");
|
||||
|
||||
qstCondFunc[0] = &QUEST_COND_000;
|
||||
qstCondFunc[1] = &QUEST_COND_001;
|
||||
qstCondFunc[2] = &QUEST_COND_002;
|
||||
qstCondFunc[3] = &QUEST_COND_003;
|
||||
qstCondFunc[4] = &QUEST_COND_004;
|
||||
qstCondFunc[5] = &QUEST_COND_005;
|
||||
qstCondFunc[6] = &QUEST_COND_006;
|
||||
qstCondFunc[7] = &QUEST_COND_007;
|
||||
qstCondFunc[8] = &QUEST_COND_008;
|
||||
qstCondFunc[9] = &QUEST_COND_009;
|
||||
qstCondFunc[10] = &QUEST_COND_010;
|
||||
qstCondFunc[11] = &QUEST_COND_011;
|
||||
qstCondFunc[12] = &QUEST_COND_012;
|
||||
qstCondFunc[13] = &QUEST_COND_013;
|
||||
qstCondFunc[14] = &QUEST_COND_014;
|
||||
qstCondFunc[15] = &QUEST_COND_015;
|
||||
qstCondFunc[16] = &QUEST_COND_016;
|
||||
qstCondFunc[17] = &QUEST_COND_017;
|
||||
qstCondFunc[18] = &QUEST_COND_018;
|
||||
qstCondFunc[19] = &QUEST_COND_019;
|
||||
qstCondFunc[20] = &QUEST_COND_020;
|
||||
qstCondFunc[21] = &QUEST_COND_021;
|
||||
qstCondFunc[22] = &QUEST_COND_022;
|
||||
qstCondFunc[23] = &QUEST_COND_023;
|
||||
qstCondFunc[24] = &QUEST_COND_024;
|
||||
qstCondFunc[25] = &QUEST_COND_025;
|
||||
qstCondFunc[26] = &QUEST_COND_026;
|
||||
qstCondFunc[27] = &QUEST_COND_027;
|
||||
qstCondFunc[28] = &QUEST_COND_028;
|
||||
qstCondFunc[29] = &QUEST_COND_029;
|
||||
qstCondFunc[30] = &QUEST_COND_030;
|
||||
|
||||
qstRewdFunc[0] = &QUEST_REWD_000;
|
||||
qstRewdFunc[1] = &QUEST_REWD_001;
|
||||
qstRewdFunc[2] = &QUEST_REWD_002;
|
||||
qstRewdFunc[3] = &QUEST_REWD_003;
|
||||
qstRewdFunc[4] = &QUEST_REWD_004;
|
||||
qstRewdFunc[5] = &QUEST_REWD_005;
|
||||
qstRewdFunc[6] = &QUEST_REWD_006;
|
||||
qstRewdFunc[7] = &QUEST_REWD_007;
|
||||
qstRewdFunc[8] = &QUEST_REWD_008;
|
||||
qstRewdFunc[9] = &QUEST_REWD_009;
|
||||
qstRewdFunc[10] = &QUEST_REWD_010;
|
||||
qstRewdFunc[11] = &QUEST_REWD_011;
|
||||
qstRewdFunc[12] = &QUEST_REWD_012;
|
||||
qstRewdFunc[13] = &QUEST_REWD_013;
|
||||
qstRewdFunc[14] = &QUEST_REWD_014;
|
||||
qstRewdFunc[15] = &QUEST_REWD_015;
|
||||
qstRewdFunc[16] = &QUEST_REWD_016;
|
||||
qstRewdFunc[17] = &QUEST_REWD_017;
|
||||
qstRewdFunc[18] = &QUEST_REWD_018;
|
||||
qstRewdFunc[19] = &QUEST_REWD_019;
|
||||
qstRewdFunc[20] = &QUEST_REWD_020;
|
||||
qstRewdFunc[21] = &QUEST_REWD_021;
|
||||
qstRewdFunc[22] = &QUEST_REWD_022;
|
||||
qstRewdFunc[23] = &QUEST_REWD_023;
|
||||
qstRewdFunc[24] = &QUEST_REWD_024;
|
||||
qstRewdFunc[25] = &QUEST_REWD_025;
|
||||
qstRewdFunc[26] = &QUEST_REWD_026;
|
||||
qstRewdFunc[27] = &QUEST_REWD_027;
|
||||
qstRewdFunc[28] = &QUEST_REWD_028;
|
||||
qstRewdFunc[29] = &QUEST_REWD_029;
|
||||
qstRewdFunc[30] = &QUEST_REWD_030;
|
||||
//qstRewdFunc[50] = &QUEST_REWD_050;
|
||||
|
||||
delete stbQuest;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "../WorldServer.h"
|
||||
|
||||
unsigned long MakeStrHash(const char *str)
|
||||
{
|
||||
register unsigned long result = 0xDEADC0DE;
|
||||
register unsigned long tkey = 0x7FED7FED;
|
||||
register char c = 0;
|
||||
while (*(str)){
|
||||
c = (*str<'a'||*str>'z')?*str:*str-32;
|
||||
result += tkey;
|
||||
tkey *= 0x21;
|
||||
result ^= keys[c];
|
||||
tkey += result + c + 3;
|
||||
str++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
const unsigned long keys[256] = {
|
||||
0x697A5, 0x6045C, 0xAB4E2, 0x409E4, 0x71209, 0x32392, 0xA7292, 0xB09FC, 0x4B658, 0xAAAD5, 0x9B9CF, 0xA326A, 0x8DD12, 0x38150, 0x8E14D, 0x2EB7F,
|
||||
0xE0A56, 0x7E6FA, 0xDFC27, 0xB1301, 0x8B4F7, 0xA7F70, 0xAA713, 0x6CC0F, 0x6FEDF, 0x2EC87, 0xC0F1C, 0x45CA4, 0x30DF8, 0x60E99, 0xBC13E, 0x4E0B5,
|
||||
0x6318B, 0x82679, 0x26EF2, 0x79C95, 0x86DDC, 0x99BC0, 0xB7167, 0x72532, 0x68765, 0xC7446, 0xDA70D, 0x9D132, 0xE5038, 0x2F755, 0x9171F, 0xCB49E,
|
||||
0x6F925, 0x601D3, 0x5BD8A, 0x2A4F4, 0x9B022, 0x706C3, 0x28C10, 0x2B24B, 0x7CD55, 0xCA355, 0xD95F4, 0x727BC, 0xB1138, 0x9AD21, 0xC0ACA, 0xCD928,
|
||||
0x953E5, 0x97A20, 0x345F3, 0xBDC03, 0x7E157, 0x96C99, 0x968EF, 0x92AA9, 0xC2276, 0xA695D, 0x6743B, 0x2723B, 0x58980, 0x66E08, 0x51D1B, 0xB97D2,
|
||||
0x6CAEE, 0xCC80F, 0x3BA6C, 0xB0BF5, 0x9E27B, 0xD122C, 0x48611, 0x8C326, 0xD2AF8, 0xBB3B7, 0xDED7F, 0x4B236, 0xD298F, 0xBE912, 0xDC926, 0xC873F,
|
||||
0xD0716, 0x9E1D3, 0x48D94, 0x9BD91, 0x5825D, 0x55637, 0xB2057, 0xBCC6C, 0x460DE, 0xAE7FB, 0x81B03, 0x34D8F, 0xC0528, 0xC9B59, 0x3D260, 0x6051D,
|
||||
0x93757, 0x8027F, 0xB7C34, 0x4A14E, 0xB12B8, 0xE4945, 0x28203, 0xA1C0F, 0xAA382, 0x46ABB, 0x330B9, 0x5A114, 0xA754B, 0xC68D0, 0x9040E, 0x6C955,
|
||||
0xBB1EF, 0x51E6B, 0x9FF21, 0x51BCA, 0x4C879, 0xDFF70, 0x5B5EE, 0x29936, 0xB9247, 0x42611, 0x2E353, 0x26F3A, 0x683A3, 0xA1082, 0x67333, 0x74EB7,
|
||||
0x754BA, 0x369D5, 0x8E0BC, 0xABAFD, 0x6630B, 0xA3A7E, 0xCDBB1, 0x8C2DE, 0x92D32, 0x2F8ED, 0x7EC54, 0x572F5, 0x77461, 0xCB3F5, 0x82C64, 0x35FE0,
|
||||
0x9203B, 0xADA2D, 0xBAEBD, 0xCB6AF, 0xC8C9A, 0x5D897, 0xCB727, 0xA13B3, 0xB4D6D, 0xC4929, 0xB8732, 0xCCE5A, 0xD3E69, 0xD4B60, 0x89941, 0x79D85,
|
||||
0x39E0F, 0x6945B, 0xC37F8, 0x77733, 0x45D7D, 0x25565, 0xA3A4E, 0xB9F9E, 0x316E4, 0x36734, 0x6F5C3, 0xA8BA6, 0xC0871, 0x42D05, 0x40A74, 0x2E7ED,
|
||||
0x67C1F, 0x28BE0, 0xE162B, 0xA1C0F, 0x2F7E5, 0xD505A, 0x9FCC8, 0x78381, 0x29394, 0x53D6B, 0x7091D, 0xA2FB1, 0xBB942, 0x29906, 0xC412D, 0x3FCD5,
|
||||
0x9F2EB, 0x8F0CC, 0xE25C3, 0x7E519, 0x4E7D9, 0x5F043, 0xBBA1B, 0x6710A, 0x819FB, 0x9A223, 0x38E47, 0xE28AD, 0xB690B, 0x42328, 0x7CF7E, 0xAE108,
|
||||
0xE54BA, 0xBA5A1, 0xA09A6, 0x9CAB7, 0xDB2B3, 0xA98CC, 0x5CEBA, 0x9245D, 0x5D083, 0x8EA21, 0xAE349, 0x54940, 0x8E557, 0x83EFD, 0xDC504, 0xA6059,
|
||||
0xB85C9, 0x9D162, 0x7AEB6, 0xBED34, 0xB4963, 0xE367B, 0x4C891, 0x9E42C, 0xD4304, 0x96EAA, 0xD5D69, 0x866B8, 0x83508, 0x7BAEC, 0xD03FD, 0xDA122
|
||||
};
|
||||
|
||||
unsigned long MakeStrHash(const char *str);
|
||||
Reference in new issue
Block a user