aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/wintermute/BDiskFile.cpp24
-rw-r--r--engines/wintermute/BFileManager.cpp207
-rw-r--r--engines/wintermute/BFileManager.h11
-rw-r--r--engines/wintermute/BPackage.cpp17
-rw-r--r--engines/wintermute/BPackage.h12
-rw-r--r--engines/wintermute/BPkgFile.h6
-rw-r--r--engines/wintermute/Matrix4.cpp83
-rw-r--r--engines/wintermute/Matrix4.h56
-rw-r--r--engines/wintermute/PartEmitter.cpp1194
-rw-r--r--engines/wintermute/PartForce.cpp56
-rw-r--r--engines/wintermute/PartParticle.cpp252
-rw-r--r--engines/wintermute/dcpackage.h23
-rw-r--r--engines/wintermute/module.mk5
-rw-r--r--engines/wintermute/wintermute.cpp6
14 files changed, 1903 insertions, 49 deletions
diff --git a/engines/wintermute/BDiskFile.cpp b/engines/wintermute/BDiskFile.cpp
index df2db0003d..ed735c846d 100644
--- a/engines/wintermute/BDiskFile.cpp
+++ b/engines/wintermute/BDiskFile.cpp
@@ -32,6 +32,7 @@
#include "BPkgFile.h"
#include "BDiskFile.h"
#include "common/stream.h"
+#include "common/file.h"
#include "BFileManager.h"
namespace WinterMute {
@@ -61,20 +62,37 @@ HRESULT CBDiskFile::Open(Common::String Filename) {
sprintf(FullPath, "%s%s", Game->m_FileManager->m_SinglePaths[i], Filename.c_str());
CorrectSlashes(FullPath);
- error("Tried to open %s, TODO: add SearchMan-support", Filename.c_str());
//m_File = Common::createFileStream(FullPath);
- if (m_File != NULL)
+ Common::File *tempFile = new Common::File();
+ if(tempFile->open(FullPath)) {
+ m_File = tempFile;
+ } else {
+ delete tempFile;
+ }
+/* if (m_File != NULL) {
+ error("Tried to open %s, but failed", Filename.c_str());
break;
+ }*/
}
// if we didn't find it in search paths, try to open directly
if (!m_File) {
strcpy(FullPath, Filename.c_str());
CorrectSlashes(FullPath);
- error("Tried to open %s, TODO: add SearchMan-support", Filename.c_str());
+ //error("Tried to open %s, TODO: add SearchMan-support", Filename.c_str());
//m_File = Common::createFileStream(FullPath);
+ Common::File *tempFile = new Common::File();
+ if (tempFile->open(FullPath)) {
+ m_File = tempFile;
+ } else {
+ delete tempFile;
+ }
}
+ if (!m_File) {
+ warning("Couldn't load %s", Filename.c_str());
+ }
+
if (m_File) {
uint32 magic1, magic2;
magic1 = m_File->readUint32LE();
diff --git a/engines/wintermute/BFileManager.cpp b/engines/wintermute/BFileManager.cpp
index 8763506e99..2e0e296eb0 100644
--- a/engines/wintermute/BFileManager.cpp
+++ b/engines/wintermute/BFileManager.cpp
@@ -26,6 +26,8 @@
* Copyright (c) 2011 Jan Nedoma
*/
+
+
#include "dcgf.h"
#include "BFileManager.h"
#include "StringUtil.h"
@@ -44,6 +46,10 @@
#include "common/str.h"
#include "common/textconsole.h"
#include "common/util.h"
+#include "common/config-manager.h"
+#include "common/system.h"
+#include "common/fs.h"
+#include "common/file.h"
//#include <boost/filesystem.hpp>
#ifdef __WIN32__
@@ -178,6 +184,9 @@ byte *CBFileManager::ReadWholeFile(const char *Filename, uint32 *Size, bool Must
//////////////////////////////////////////////////////////////////////////
HRESULT CBFileManager::SaveFile(char *Filename, byte *Buffer, uint32 BufferSize, bool Compressed, byte *PrefixBuffer, uint32 PrefixSize) {
+ // TODO
+ warning("Implement SaveFile");
+#if 0
RestoreCurrentDir();
CBUtils::CreatePath(Filename, false);
@@ -224,7 +233,7 @@ HRESULT CBFileManager::SaveFile(char *Filename, byte *Buffer, uint32 BufferSize,
if (!Compressed) fwrite(Buffer, BufferSize, 1, f);
fclose(f);
-
+#endif
return S_OK;
}
@@ -357,6 +366,10 @@ HRESULT CBFileManager::RegisterPackages() {
Game->LOG(0, "Scanning packages...");
warning("Scanning packages");
+
+// TODO: Actually scan the folder, for now we just hardcode the files for Dirty Split.
+ RegisterPackage("data.dcp");
+ RegisterPackage("english.dcp");
#if 0
AnsiString extension = AnsiString(".") + AnsiString(PACKAGE_EXTENSION);
@@ -385,15 +398,144 @@ HRESULT CBFileManager::RegisterPackages() {
}
}
-
+ warning(" Registered %d files in %d package(s)", m_Files.size(), m_Packages.GetSize());
Game->LOG(0, " Registered %d files in %d package(s)", m_Files.size(), m_Packages.GetSize());
#endif
+ warning(" Registered %d files in %d package(s)", m_Files.size(), m_Packages.GetSize());
return S_OK;
}
-
+//////////////////////////////////////////////////////////////////////////
+HRESULT CBFileManager::RegisterPackage(Common::String Filename , bool SearchSignature) {
+// FILE *f = fopen(Filename, "rb");
+ Common::File *package = new Common::File();
+ package->open(Filename);
+ if (!package->isOpen()) {
+ Game->LOG(0, " Error opening package file '%s'. Ignoring.", Filename.c_str());
+ return S_OK;
+ }
+
+ uint32 AbsoluteOffset = 0;
+ bool BoundToExe = false;
+
+ if (SearchSignature) {
+ uint32 Offset;
+ if (!FindPackageSignature(package, &Offset)) {
+ delete package;
+ return S_OK;
+ } else {
+ package->seek(Offset, SEEK_SET);
+ AbsoluteOffset = Offset;
+ BoundToExe = true;
+ }
+ }
+
+ TPackageHeader hdr;
+ hdr.readFromStream(package);
+// package->read(&hdr, sizeof(TPackageHeader), 1, f);
+ if (hdr.Magic1 != PACKAGE_MAGIC_1 || hdr.Magic2 != PACKAGE_MAGIC_2 || hdr.PackageVersion > PACKAGE_VERSION) {
+ Game->LOG(0, " Invalid header in package file '%s'. Ignoring.", Filename);
+ delete package;
+ return S_OK;
+ }
+
+ if (hdr.PackageVersion != PACKAGE_VERSION) {
+ Game->LOG(0, " Warning: package file '%s' is outdated.", Filename);
+ }
+
+ // new in v2
+ if (hdr.PackageVersion == PACKAGE_VERSION) {
+ uint32 DirOffset;
+ DirOffset = package->readUint32LE();
+ DirOffset += AbsoluteOffset;
+ package->seek(DirOffset, SEEK_SET);
+ }
+
+ for (int i = 0; i < hdr.NumDirs; i++) {
+ CBPackage *pkg = new CBPackage(Game);
+ if (!pkg) return E_FAIL;
+
+ pkg->m_BoundToExe = BoundToExe;
+
+ // read package info
+ byte NameLength = package->readByte();
+ pkg->m_Name = new char[NameLength];
+ package->read(pkg->m_Name, NameLength);
+ pkg->m_CD = package->readByte();
+ pkg->m_Priority = hdr.Priority;
+
+ if (!hdr.MasterIndex) pkg->m_CD = 0; // override CD to fixed disk
+ m_Packages.Add(pkg);
+
+
+ // read file entries
+ uint32 NumFiles = package->readUint32LE();
+
+ for (int j = 0; j < NumFiles; j++) {
+ char *Name;
+ uint32 Offset, Length, CompLength, Flags, TimeDate1, TimeDate2;
+
+ NameLength = package->readByte();
+ Name = new char[NameLength];
+ package->read(Name, NameLength);
+
+ // v2 - xor name
+ if (hdr.PackageVersion == PACKAGE_VERSION) {
+ for (int k = 0; k < NameLength; k++) {
+ ((byte *)Name)[k] ^= 'D';
+ }
+ }
+
+ // some old version of ProjectMan writes invalid directory entries
+ // so at least prevent strupr from corrupting memory
+ Name[NameLength - 1] = '\0';
+
+
+ CBPlatform::strupr(Name);
+
+ Offset = package->readUint32LE();
+ Offset += AbsoluteOffset;
+ Length = package->readUint32LE();
+ CompLength = package->readUint32LE();
+ Flags = package->readUint32LE();
+
+ if (hdr.PackageVersion == PACKAGE_VERSION) {
+ TimeDate1 = package->readUint32LE();
+ TimeDate2 = package->readUint32LE();
+ }
+ m_FilesIter = m_Files.find(Name);
+ if (m_FilesIter == m_Files.end()) {
+ CBFileEntry *file = new CBFileEntry(Game);
+ file->m_Package = pkg;
+ file->m_Offset = Offset;
+ file->m_Length = Length;
+ file->m_CompressedLength = CompLength;
+ file->m_Flags = Flags;
+
+ m_Files[Name] = file;
+ } else {
+ // current package has lower CD number or higher priority, than the registered
+ if (pkg->m_CD < m_FilesIter->_value->m_Package->m_CD || pkg->m_Priority > m_FilesIter->_value->m_Package->m_Priority) {
+ m_FilesIter->_value->m_Package = pkg;
+ m_FilesIter->_value->m_Offset = Offset;
+ m_FilesIter->_value->m_Length = Length;
+ m_FilesIter->_value->m_CompressedLength = CompLength;
+ m_FilesIter->_value->m_Flags = Flags;
+ }
+ }
+ delete [] Name;
+ }
+ }
+
+
+ delete package;
+ return S_OK;
+}
//////////////////////////////////////////////////////////////////////////
HRESULT CBFileManager::RegisterPackage(const char *Path, const char *Name, bool SearchSignature) {
+// TODO
+ error("Implement RegisterPackage, this is the old one");
+#if 0
char Filename[MAX_PATH];
sprintf(Filename, "%s%s", Path, Name);
@@ -403,7 +545,7 @@ HRESULT CBFileManager::RegisterPackage(const char *Path, const char *Name, bool
return S_OK;
}
- uint32 AbosulteOffset = 0;
+ uint32 AbsoluteOffset = 0;
bool BoundToExe = false;
if (SearchSignature) {
@@ -413,7 +555,7 @@ HRESULT CBFileManager::RegisterPackage(const char *Path, const char *Name, bool
return S_OK;
} else {
fseek(f, Offset, SEEK_SET);
- AbosulteOffset = Offset;
+ AbsoluteOffset = Offset;
BoundToExe = true;
}
}
@@ -434,7 +576,7 @@ HRESULT CBFileManager::RegisterPackage(const char *Path, const char *Name, bool
if (hdr.PackageVersion == PACKAGE_VERSION) {
uint32 DirOffset;
fread(&DirOffset, sizeof(uint32), 1, f);
- DirOffset += AbosulteOffset;
+ DirOffset += AbsoluteOffset;
fseek(f, DirOffset, SEEK_SET);
}
@@ -483,7 +625,7 @@ HRESULT CBFileManager::RegisterPackage(const char *Path, const char *Name, bool
CBPlatform::strupr(Name);
fread(&Offset, sizeof(uint32), 1, f);
- Offset += AbosulteOffset;
+ Offset += AbsoluteOffset;
fread(&Length, sizeof(uint32), 1, f);
fread(&CompLength, sizeof(uint32), 1, f);
fread(&Flags, sizeof(uint32), 1, f);
@@ -518,7 +660,7 @@ HRESULT CBFileManager::RegisterPackage(const char *Path, const char *Name, bool
fclose(f);
-
+#endif
return S_OK;
}
@@ -534,36 +676,50 @@ bool CBFileManager::IsValidPackage(const AnsiString &fileName) const {
}
//////////////////////////////////////////////////////////////////////////
-FILE *CBFileManager::OpenPackage(char *Name) {
- RestoreCurrentDir();
+Common::File *CBFileManager::OpenPackage(char *Name) {
+ //TODO
+ warning("Implement OpenPackage %s", Name);
+
+ //RestoreCurrentDir();
- FILE *ret = NULL;
+ Common::File *ret = new Common::File();
char Filename[MAX_PATH];
for (int i = 0; i < m_PackagePaths.GetSize(); i++) {
sprintf(Filename, "%s%s.%s", m_PackagePaths[i], Name, PACKAGE_EXTENSION);
- ret = fopen(Filename, "rb");
- if (ret != NULL) return ret;
+ //ret = fopen(Filename, "rb");
+ ret->open(Filename);
+ if (ret->isOpen()) {
+ return ret;
+ }
}
+ delete ret;
return NULL;
}
//////////////////////////////////////////////////////////////////////////
-FILE *CBFileManager::OpenSingleFile(char *Name) {
+Common::File *CBFileManager::OpenSingleFile(char *Name) {
RestoreCurrentDir();
-
- FILE *ret = NULL;
+
+ Common::File *ret = NULL;
char Filename[MAX_PATH];
-
+
for (int i = 0; i < m_SinglePaths.GetSize(); i++) {
sprintf(Filename, "%s%s", m_SinglePaths[i], Name);
- ret = fopen(Filename, "rb");
- if (ret != NULL) return ret;
+ ret->open(Filename);
+ if (ret->isOpen())
+ return ret;
}
-
+
// didn't find in search paths, try to open directly
- return fopen(Name, "rb");
+ ret->open(Name);
+ if (ret->isOpen()) {
+ return ret;
+ } else {
+ delete ret;
+ return NULL;
+ }
}
@@ -706,15 +862,14 @@ HRESULT CBFileManager::SetBasePath(char *Path) {
//////////////////////////////////////////////////////////////////////////
-bool CBFileManager::FindPackageSignature(FILE *f, uint32 *Offset) {
+bool CBFileManager::FindPackageSignature(Common::File *f, uint32 *Offset) {
byte buf[32768];
byte Signature[8];
((uint32 *)Signature)[0] = PACKAGE_MAGIC_1;
((uint32 *)Signature)[1] = PACKAGE_MAGIC_2;
- fseek(f, 0, SEEK_END);
- uint32 FileSize = ftell(f);
+ uint32 FileSize = f->size();
int StartPos = 1024 * 1024;
@@ -722,8 +877,8 @@ bool CBFileManager::FindPackageSignature(FILE *f, uint32 *Offset) {
while (BytesRead < FileSize - 16) {
int ToRead = MIN((unsigned int)32768, FileSize - BytesRead);
- fseek(f, StartPos, SEEK_SET);
- int ActuallyRead = fread(buf, 1, ToRead, f);
+ f->seek(StartPos, SEEK_SET);
+ int ActuallyRead = f->read(buf, ToRead);
if (ActuallyRead != ToRead) return false;
for (int i = 0; i < ToRead - 8; i++)
diff --git a/engines/wintermute/BFileManager.h b/engines/wintermute/BFileManager.h
index 849a30bf8e..bee43e696d 100644
--- a/engines/wintermute/BFileManager.h
+++ b/engines/wintermute/BFileManager.h
@@ -35,11 +35,15 @@
#include "BFileEntry.h"
#include "common/archive.h"
+namespace Common {
+ class File;
+}
+
namespace WinterMute {
class CBFile;
class CBFileManager: CBBase {
public:
- bool FindPackageSignature(FILE *f, uint32 *Offset);
+ bool FindPackageSignature(Common::File *f, uint32 *Offset);
HRESULT Cleanup();
HRESULT SetBasePath(char *Path);
HRESULT RestoreCurrentDir();
@@ -49,8 +53,8 @@ public:
HRESULT CloseFile(CBFile *File);
CBFile *OpenFile(const char *Filename, bool AbsPathWarning = true);
CBFileEntry *GetPackageEntry(const char *Filename);
- FILE *OpenSingleFile(char *Name);
- FILE *OpenPackage(char *Name);
+ Common::File *OpenSingleFile(char *Name);
+ Common::File *OpenPackage(char *Name);
HRESULT RegisterPackages();
HRESULT InitPaths();
HRESULT ReloadPaths();
@@ -71,6 +75,7 @@ public:
Common::HashMap<Common::String, CBFileEntry *> m_Files;
private:
HRESULT RegisterPackage(const char *Path, const char *Name, bool SearchSignature = false);
+ HRESULT RegisterPackage(Common::String Filename, bool SearchSignature = false);
Common::HashMap<Common::String, CBFileEntry *>::iterator m_FilesIter;
bool IsValidPackage(const AnsiString &fileName) const;
diff --git a/engines/wintermute/BPackage.cpp b/engines/wintermute/BPackage.cpp
index d5ae12fa84..2193999e2c 100644
--- a/engines/wintermute/BPackage.cpp
+++ b/engines/wintermute/BPackage.cpp
@@ -30,6 +30,7 @@
#include "BPackage.h"
#include "BGame.h"
#include "BFileManager.h"
+#include "common/file.h"
namespace WinterMute {
//////////////////////////////////////////////////////////////////////
@@ -66,26 +67,26 @@ HRESULT CBPackage::Open() {
//////////////////////////////////////////////////////////////////////////
HRESULT CBPackage::Close() {
- if (m_File) fclose(m_File);
+ delete m_File;
m_File = NULL;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////
-HRESULT CBPackage::Read(FILE *file, uint32 offset, byte *buffer, uint32 size) {
+HRESULT CBPackage::Read(Common::File *file, uint32 offset, byte *buffer, uint32 size) {
HRESULT ret;
if (FAILED(ret = Open())) return ret;
else {
- if (fseek(file, offset, SEEK_SET)) return E_FAIL;
- if (fread(buffer, size, 1, file) != 1) return E_FAIL;
+ if (file->seek(offset, SEEK_SET)) return E_FAIL;
+ if (file->read(buffer, size) != 1) return E_FAIL;
else return S_OK;
}
}
//////////////////////////////////////////////////////////////////////////
-FILE *CBPackage::GetFilePointer() {
- FILE *file = Game->m_FileManager->OpenPackage(m_Name);
+Common::File *CBPackage::GetFilePointer() {
+ Common::File *file = Game->m_FileManager->OpenPackage(m_Name);
if (!file) {
Game->m_FileManager->RequestCD(m_CD, m_Name, "");
file = Game->m_FileManager->OpenPackage(m_Name);
@@ -94,8 +95,8 @@ FILE *CBPackage::GetFilePointer() {
}
//////////////////////////////////////////////////////////////////////////
-void CBPackage::CloseFilePointer(FILE*& file) {
- if (file) fclose(file);
+void CBPackage::CloseFilePointer(Common::File*& file) {
+ delete file;
file = NULL;
}
diff --git a/engines/wintermute/BPackage.h b/engines/wintermute/BPackage.h
index 54f2e04a6c..6f1c8e1561 100644
--- a/engines/wintermute/BPackage.h
+++ b/engines/wintermute/BPackage.h
@@ -32,21 +32,25 @@
#include "BBase.h"
+namespace Common {
+ class File;
+}
+
namespace WinterMute {
class CBPackage : public CBBase {
public:
- FILE *GetFilePointer();
- void CloseFilePointer(FILE*& file);
+ Common::File *GetFilePointer();
+ void CloseFilePointer(Common::File*& file);
bool m_BoundToExe;
byte m_Priority;
- HRESULT Read(FILE *file, uint32 offset, byte *buffer, uint32 size);
+ HRESULT Read(Common::File *file, uint32 offset, byte *buffer, uint32 size);
HRESULT Close();
HRESULT Open();
char *m_Name;
int m_CD;
- FILE *m_File;
+ Common::File *m_File;
CBPackage(CBGame *inGame);
virtual ~CBPackage();
diff --git a/engines/wintermute/BPkgFile.h b/engines/wintermute/BPkgFile.h
index a00c954860..d6aac57d1d 100644
--- a/engines/wintermute/BPkgFile.h
+++ b/engines/wintermute/BPkgFile.h
@@ -36,6 +36,10 @@
#define COMPRESSED_BUFFER_SIZE 4096
+namespace Common {
+ class File;
+}
+
namespace WinterMute {
class CBPkgFile : public CBFile {
@@ -53,7 +57,7 @@ private:
CBFileEntry *m_FileEntry;
z_stream m_Stream;
byte m_CompBuffer[COMPRESSED_BUFFER_SIZE];
- FILE *m_File;
+ Common::File *m_File;
};
} // end of namespace WinterMute
diff --git a/engines/wintermute/Matrix4.cpp b/engines/wintermute/Matrix4.cpp
new file mode 100644
index 0000000000..90a3f69f2c
--- /dev/null
+++ b/engines/wintermute/Matrix4.cpp
@@ -0,0 +1,83 @@
+/*
+This file is part of WME Lite.
+http://dead-code.org/redir.php?target=wmelite
+
+Copyright (c) 2011 Jan Nedoma
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "engines/wintermute/Matrix4.h"
+#include "engines/wintermute/Vector2.h"
+#include <math.h>
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////////
+Matrix4::Matrix4() {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ m[i][j] = 0.0f;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+Matrix4::~Matrix4() {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void Matrix4::Identity() {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ m[i][j] = 0.0f;
+ }
+ }
+ m[0][0] = 1.0f;
+ m[1][1] = 1.0f;
+ m[2][2] = 1.0f;
+ m[3][3] = 1.0f;
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+void Matrix4::RotationZ(float angle) {
+ Identity();
+
+ m[0][0] = cos(angle);
+ m[1][1] = cos(angle);
+ m[0][1] = sin(angle);
+ m[1][0] = -sin(angle);
+}
+
+//////////////////////////////////////////////////////////////////////////
+void Matrix4::TransformVector2(Vector2 &vec) {
+ float norm;
+
+ norm = m[0][3] * vec.x + m[1][3] * vec.y + m[3][3];
+
+ float x = (m[0][0] * vec.x + m[1][0] * vec.y + m[3][0]) / norm;
+ float y = (m[0][1] * vec.x + m[1][1] * vec.y + m[3][1]) / norm;
+
+ vec.x = x;
+ vec.y = y;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/Matrix4.h b/engines/wintermute/Matrix4.h
new file mode 100644
index 0000000000..866d5cdf34
--- /dev/null
+++ b/engines/wintermute/Matrix4.h
@@ -0,0 +1,56 @@
+/*
+This file is part of WME Lite.
+http://dead-code.org/redir.php?target=wmelite
+
+Copyright (c) 2011 Jan Nedoma
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef __WmeMatrix4_H__
+#define __WmeMatrix4_H__
+
+namespace WinterMute {
+
+class Vector2;
+
+class Matrix4 {
+public:
+ Matrix4();
+ ~Matrix4();
+
+ void Identity();
+ void RotationZ(float angle);
+ void TransformVector2(Vector2 &vec);
+
+/* union {
+ struct {
+ float _11, _12, _13, _14;
+ float _21, _22, _23, _24;
+ float _31, _32, _33, _34;
+ float _41, _42, _43, _44;
+ };*/
+ float m[4][4];
+ //};
+
+};
+
+} // end of namespace WinterMute
+
+#endif // __WmeMatrix4_H__ \ No newline at end of file
diff --git a/engines/wintermute/PartEmitter.cpp b/engines/wintermute/PartEmitter.cpp
new file mode 100644
index 0000000000..0e8f7ee1b7
--- /dev/null
+++ b/engines/wintermute/PartEmitter.cpp
@@ -0,0 +1,1194 @@
+/*
+This file is part of WME Lite.
+http://dead-code.org/redir.php?target=wmelite
+
+Copyright (c) 2011 Jan Nedoma
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/PartEmitter.h"
+#include "engines/wintermute/Vector2.h"
+#include "engines/wintermute/Matrix4.h"
+#include "engines/wintermute/scriptables/ScValue.h"
+#include "engines/wintermute/scriptables/ScStack.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/BRegion.h"
+#include "engines/wintermute/BFileManager.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CPartEmitter, false)
+
+//////////////////////////////////////////////////////////////////////////
+CPartEmitter::CPartEmitter(CBGame *inGame, CBScriptHolder *Owner) : CBObject(inGame) {
+ m_Width = m_Height = 0;
+
+ CBPlatform::SetRectEmpty(&m_Border);
+ m_BorderThicknessLeft = m_BorderThicknessRight = m_BorderThicknessTop = m_BorderThicknessBottom = 0;
+
+ m_Angle1 = m_Angle2 = 0;
+
+ m_Velocity1 = m_Velocity2 = 0.0f;
+ m_VelocityZBased = false;
+
+ m_Scale1 = m_Scale2 = 100.0f;
+ m_ScaleZBased = false;
+
+ m_MaxParticles = 100;
+
+ m_LifeTime1 = m_LifeTime2 = 1000;
+ m_LifeTimeZBased = false;
+
+ m_LastGenTime = 0;
+ m_GenInterval = 0;
+ m_GenAmount = 1;
+
+ m_OverheadTime = 0;
+ m_Running = false;
+
+ m_MaxBatches = 0;
+ m_BatchesGenerated = 0;
+
+ m_FadeInTime = m_FadeOutTime = 0;
+
+ m_Alpha1 = m_Alpha2 = 255;
+ m_AlphaTimeBased = false;
+
+ m_Rotation1 = m_Rotation2 = 0.0f;
+ m_AngVelocity1 = m_AngVelocity2 = 0.0f;
+
+ m_GrowthRate1 = m_GrowthRate2 = 0.0f;
+ m_ExponentialGrowth = false;
+
+ m_UseRegion = false;
+
+ m_EmitEvent = NULL;
+ m_Owner = Owner;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CPartEmitter::~CPartEmitter(void) {
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ delete m_Particles[i];
+ }
+ m_Particles.RemoveAll();
+
+ for (int i = 0; i < m_Forces.GetSize(); i++) {
+ delete m_Forces[i];
+ }
+ m_Forces.RemoveAll();
+
+
+ for (int i = 0; i < m_Sprites.GetSize(); i++) {
+ delete [] m_Sprites[i];
+ }
+ m_Sprites.RemoveAll();
+
+ delete[] m_EmitEvent;
+ m_EmitEvent = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::AddSprite(char *Filename) {
+ if (!Filename) return E_FAIL;
+
+ // do we already have the file?
+ for (int i = 0; i < m_Sprites.GetSize(); i++) {
+ if (scumm_stricmp(Filename, m_Sprites[i]) == 0) return S_OK;
+ }
+
+ // check if file exists
+ CBFile *File = Game->m_FileManager->OpenFile(Filename);
+ if (!File) {
+ Game->LOG(0, "Sprite '%s' not found", Filename);
+ return E_FAIL;
+ } else Game->m_FileManager->CloseFile(File);
+
+ char *Str = new char[strlen(Filename) + 1];
+ strcpy(Str, Filename);
+ m_Sprites.Add(Str);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::RemoveSprite(char *Filename) {
+ for (int i = 0; i < m_Sprites.GetSize(); i++) {
+ if (scumm_stricmp(Filename, m_Sprites[i]) == 0) {
+ delete [] m_Sprites[i];
+ m_Sprites.RemoveAt(i);
+ return S_OK;
+ }
+ }
+ return E_FAIL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::InitParticle(CPartParticle *Particle, uint32 CurrentTime, uint32 TimerDelta) {
+ if (!Particle) return E_FAIL;
+ if (m_Sprites.GetSize() == 0) return E_FAIL;
+
+ int PosX = CBUtils::RandomInt(m_PosX, m_PosX + m_Width);
+ int PosY = CBUtils::RandomInt(m_PosY, m_PosY + m_Height);
+ float PosZ = CBUtils::RandomFloat(0.0f, 100.0f);
+
+ float Velocity;
+ if (m_VelocityZBased) Velocity = m_Velocity1 + PosZ * (m_Velocity2 - m_Velocity1) / 100;
+ else Velocity = CBUtils::RandomFloat(m_Velocity1, m_Velocity2);
+
+ float Scale;
+ if (m_ScaleZBased) Scale = m_Scale1 + PosZ * (m_Scale2 - m_Scale1) / 100;
+ else Scale = CBUtils::RandomFloat(m_Scale1, m_Scale2);
+
+ int LifeTime;
+ if (m_LifeTimeZBased) LifeTime = m_LifeTime2 - PosZ * (m_LifeTime2 - m_LifeTime1) / 100;
+ else LifeTime = CBUtils::RandomInt(m_LifeTime1, m_LifeTime2);
+
+ float Angle = CBUtils::RandomAngle(m_Angle1, m_Angle2);
+ int SpriteIndex = CBUtils::RandomInt(0, m_Sprites.GetSize() - 1);
+
+ float Rotation = CBUtils::RandomAngle(m_Rotation1, m_Rotation2);
+ float AngVelocity = CBUtils::RandomFloat(m_AngVelocity1, m_AngVelocity2);
+ float GrowthRate = CBUtils::RandomFloat(m_GrowthRate1, m_GrowthRate2);
+
+ if (!CBPlatform::IsRectEmpty(&m_Border)) {
+ int ThicknessLeft = m_BorderThicknessLeft - (float)m_BorderThicknessLeft * PosZ / 100.0f;
+ int ThicknessRight = m_BorderThicknessRight - (float)m_BorderThicknessRight * PosZ / 100.0f;
+ int ThicknessTop = m_BorderThicknessTop - (float)m_BorderThicknessTop * PosZ / 100.0f;
+ int ThicknessBottom = m_BorderThicknessBottom - (float)m_BorderThicknessBottom * PosZ / 100.0f;
+
+ Particle->m_Border = m_Border;
+ Particle->m_Border.left += ThicknessLeft;
+ Particle->m_Border.right -= ThicknessRight;
+ Particle->m_Border.top += ThicknessTop;
+ Particle->m_Border.bottom -= ThicknessBottom;
+ }
+
+ Vector2 VecPos((float)PosX, (float)PosY);
+ Vector2 VecVel(0, Velocity);
+
+ Matrix4 MatRot;
+ MatRot.RotationZ(DegToRad(CBUtils::NormalizeAngle(Angle - 180)));
+ MatRot.TransformVector2(VecVel);
+
+ if (m_AlphaTimeBased) {
+ Particle->m_Alpha1 = m_Alpha1;
+ Particle->m_Alpha2 = m_Alpha2;
+ } else {
+ int Alpha = CBUtils::RandomInt(m_Alpha1, m_Alpha2);
+ Particle->m_Alpha1 = Alpha;
+ Particle->m_Alpha2 = Alpha;
+ }
+
+ Particle->m_CreationTime = CurrentTime;
+ Particle->m_Pos = VecPos;
+ Particle->m_PosZ = PosZ;
+ Particle->m_Velocity = VecVel;
+ Particle->m_Scale = Scale;
+ Particle->m_LifeTime = LifeTime;
+ Particle->m_Rotation = Rotation;
+ Particle->m_AngVelocity = AngVelocity;
+ Particle->m_GrowthRate = GrowthRate;
+ Particle->m_ExponentialGrowth = m_ExponentialGrowth;
+ Particle->m_IsDead = FAILED(Particle->SetSprite(m_Sprites[SpriteIndex]));
+ Particle->FadeIn(CurrentTime, m_FadeInTime);
+
+
+ if (Particle->m_IsDead) return E_FAIL;
+ else return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::Update() {
+ if (!m_Running) return S_OK;
+ else return UpdateInternal(Game->m_Timer, Game->m_TimerDelta);
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::UpdateInternal(uint32 CurrentTime, uint32 TimerDelta) {
+ int NumLive = 0;
+
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ m_Particles[i]->Update(this, CurrentTime, TimerDelta);
+
+ if (!m_Particles[i]->m_IsDead) NumLive++;
+ }
+
+
+ // we're understaffed
+ if (NumLive < m_MaxParticles) {
+ bool NeedsSort = false;
+ if (CurrentTime - m_LastGenTime > m_GenInterval) {
+ m_LastGenTime = CurrentTime;
+ m_BatchesGenerated++;
+
+ if (m_MaxBatches > 0 && m_BatchesGenerated > m_MaxBatches) {
+ return S_OK;
+ }
+
+ int ToGen = std::min(m_GenAmount, m_MaxParticles - NumLive);
+ while (ToGen > 0) {
+ int FirstDeadIndex = -1;
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ if (m_Particles[i]->m_IsDead) {
+ FirstDeadIndex = i;
+ break;
+ }
+ }
+
+ CPartParticle *Particle;
+ if (FirstDeadIndex >= 0) Particle = m_Particles[FirstDeadIndex];
+ else {
+ Particle = new CPartParticle(Game);
+ m_Particles.Add(Particle);
+ }
+ InitParticle(Particle, CurrentTime, TimerDelta);
+ NeedsSort = true;
+
+ ToGen--;
+ }
+ }
+ if (NeedsSort && (m_ScaleZBased || m_VelocityZBased || m_LifeTimeZBased))
+ SortParticlesByZ();
+
+ // we actually generated some particles and we're not in fast-forward mode
+ if (NeedsSort && m_OverheadTime == 0) {
+ if (m_Owner && m_EmitEvent) m_Owner->ApplyEvent(m_EmitEvent);
+ }
+ }
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::Display(CBRegion *Region) {
+ if (m_Sprites.GetSize() <= 1) Game->m_Renderer->StartSpriteBatch();
+
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ if (Region != NULL && m_UseRegion) {
+ if (!Region->PointInRegion(m_Particles[i]->m_Pos.x, m_Particles[i]->m_Pos.y)) continue;
+ }
+
+ m_Particles[i]->Display(this);
+ }
+
+ if (m_Sprites.GetSize() <= 1) Game->m_Renderer->EndSpriteBatch();
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::Start() {
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ m_Particles[i]->m_IsDead = true;
+ }
+ m_Running = true;
+ m_BatchesGenerated = 0;
+
+
+ if (m_OverheadTime > 0) {
+ uint32 Delta = 500;
+ int Steps = m_OverheadTime / Delta;
+ uint32 CurrentTime = Game->m_Timer - m_OverheadTime;
+
+ for (int i = 0; i < Steps; i++) {
+ UpdateInternal(CurrentTime, Delta);
+ CurrentTime += Delta;
+ }
+ m_OverheadTime = 0;
+ }
+
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::SortParticlesByZ() {
+ // sort particles by m_PosY
+ qsort(m_Particles.GetData(), m_Particles.GetSize(), sizeof(CPartParticle *), CPartEmitter::CompareZ);
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CPartEmitter::CompareZ(const void *Obj1, const void *Obj2) {
+ CPartParticle *P1 = *(CPartParticle **)Obj1;
+ CPartParticle *P2 = *(CPartParticle **)Obj2;
+
+ if (P1->m_PosZ < P2->m_PosZ) return -1;
+ else if (P1->m_PosZ > P2->m_PosZ) return 1;
+ else return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::SetBorder(int X, int Y, int Width, int Height) {
+ CBPlatform::SetRect(&m_Border, X, Y, X + Width, Y + Height);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::SetBorderThickness(int ThicknessLeft, int ThicknessRight, int ThicknessTop, int ThicknessBottom) {
+ m_BorderThicknessLeft = ThicknessLeft;
+ m_BorderThicknessRight = ThicknessRight;
+ m_BorderThicknessTop = ThicknessTop;
+ m_BorderThicknessBottom = ThicknessBottom;
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+CPartForce *CPartEmitter::AddForceByName(char *Name) {
+ CPartForce *Force = NULL;
+
+ for (int i = 0; i < m_Forces.GetSize(); i++) {
+ if (scumm_stricmp(Name, m_Forces[i]->m_Name) == 0) {
+ Force = m_Forces[i];
+ break;
+ }
+ }
+ if (!Force) {
+ Force = new CPartForce(Game);
+ if (Force) {
+ Force->SetName(Name);
+ m_Forces.Add(Force);
+ }
+ }
+ return Force;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::AddForce(char *Name, CPartForce::TForceType Type, int PosX, int PosY, float Angle, float Strength) {
+ CPartForce *Force = AddForceByName(Name);
+ if (!Force) return E_FAIL;
+
+ Force->m_Type = Type;
+ Force->m_Pos = Vector2(PosX, PosY);
+
+ Force->m_Direction = Vector2(0, Strength);
+ Matrix4 MatRot;
+ MatRot.RotationZ(DegToRad(CBUtils::NormalizeAngle(Angle - 180)));
+ MatRot.TransformVector2(Force->m_Direction);
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::RemoveForce(char *Name) {
+ for (int i = 0; i < m_Forces.GetSize(); i++) {
+ if (scumm_stricmp(Name, m_Forces[i]->m_Name) == 0) {
+ delete m_Forces[i];
+ m_Forces.RemoveAt(i);
+ return S_OK;
+ }
+ }
+ return E_FAIL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetBorder
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "SetBorder") == 0) {
+ Stack->CorrectParams(4);
+ int BorderX = Stack->Pop()->GetInt();
+ int BorderY = Stack->Pop()->GetInt();
+ int BorderWidth = Stack->Pop()->GetInt();
+ int BorderHeight = Stack->Pop()->GetInt();
+
+ Stack->PushBool(SUCCEEDED(SetBorder(BorderX, BorderY, BorderWidth, BorderHeight)));
+
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // SetBorderThickness
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "SetBorderThickness") == 0) {
+ Stack->CorrectParams(4);
+ int Left = Stack->Pop()->GetInt();
+ int Right = Stack->Pop()->GetInt();
+ int Top = Stack->Pop()->GetInt();
+ int Bottom = Stack->Pop()->GetInt();
+
+ Stack->PushBool(SUCCEEDED(SetBorderThickness(Left, Right, Top, Bottom)));
+
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // AddSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddSprite") == 0) {
+ Stack->CorrectParams(1);
+ char *SpriteFile = Stack->Pop()->GetString();
+ Stack->PushBool(SUCCEEDED(AddSprite(SpriteFile)));
+
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveSprite
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveSprite") == 0) {
+ Stack->CorrectParams(1);
+ char *SpriteFile = Stack->Pop()->GetString();
+ Stack->PushBool(SUCCEEDED(RemoveSprite(SpriteFile)));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Start
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Start") == 0) {
+ Stack->CorrectParams(1);
+ m_OverheadTime = Stack->Pop()->GetInt();
+ Stack->PushBool(SUCCEEDED(Start()));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Stop
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Stop") == 0) {
+ Stack->CorrectParams(0);
+
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ delete m_Particles[i];
+ }
+ m_Particles.RemoveAll();
+
+ m_Running = false;
+ Stack->PushBool(true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Pause
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Pause") == 0) {
+ Stack->CorrectParams(0);
+ m_Running = false;
+ Stack->PushBool(true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Resume
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Resume") == 0) {
+ Stack->CorrectParams(0);
+ m_Running = true;
+ Stack->PushBool(true);
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddGlobalForce
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddGlobalForce") == 0) {
+ Stack->CorrectParams(3);
+ char *Name = Stack->Pop()->GetString();
+ float Angle = Stack->Pop()->GetFloat();
+ float Strength = Stack->Pop()->GetFloat();
+
+ Stack->PushBool(SUCCEEDED(AddForce(Name, CPartForce::FORCE_GLOBAL, 0, 0, Angle, Strength)));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddPointForce
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AddPointForce") == 0) {
+ Stack->CorrectParams(5);
+ char *Name = Stack->Pop()->GetString();
+ int PosX = Stack->Pop()->GetInt();
+ int PosY = Stack->Pop()->GetInt();
+ float Angle = Stack->Pop()->GetFloat();
+ float Strength = Stack->Pop()->GetFloat();
+
+ Stack->PushBool(SUCCEEDED(AddForce(Name, CPartForce::FORCE_GLOBAL, PosX, PosY, Angle, Strength)));
+
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemoveForce
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "RemoveForce") == 0) {
+ Stack->CorrectParams(1);
+ char *Name = Stack->Pop()->GetString();
+
+ Stack->PushBool(SUCCEEDED(RemoveForce(Name)));
+
+ return S_OK;
+ }
+
+ else return CBObject::ScCallMethod(Script, Stack, ThisStack, Name);
+}
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CPartEmitter::ScGetProperty(char *Name) {
+ m_ScValue->SetNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "Type") == 0) {
+ m_ScValue->SetString("particle-emitter");
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // X
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "X") == 0) {
+ m_ScValue->SetInt(m_PosX);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Y
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Y") == 0) {
+ m_ScValue->SetInt(m_PosY);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ m_ScValue->SetInt(m_Width);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ m_ScValue->SetInt(m_Height);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Scale1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale1") == 0) {
+ m_ScValue->SetFloat(m_Scale1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Scale2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale2") == 0) {
+ m_ScValue->SetFloat(m_Scale2);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // ScaleZBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScaleZBased") == 0) {
+ m_ScValue->SetBool(m_ScaleZBased);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Velocity1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Velocity1") == 0) {
+ m_ScValue->SetFloat(m_Velocity1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Velocity2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Velocity2") == 0) {
+ m_ScValue->SetFloat(m_Velocity2);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // VelocityZBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "VelocityZBased") == 0) {
+ m_ScValue->SetBool(m_VelocityZBased);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LifeTime1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LifeTime1") == 0) {
+ m_ScValue->SetInt(m_LifeTime1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // LifeTime2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LifeTime2") == 0) {
+ m_ScValue->SetInt(m_LifeTime2);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // LifeTimeZBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LifeTimeZBased") == 0) {
+ m_ScValue->SetBool(m_LifeTimeZBased);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Angle1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Angle1") == 0) {
+ m_ScValue->SetInt(m_Angle1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Angle2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Angle2") == 0) {
+ m_ScValue->SetInt(m_Angle2);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AngVelocity1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AngVelocity1") == 0) {
+ m_ScValue->SetFloat(m_AngVelocity1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // AngVelocity2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AngVelocity2") == 0) {
+ m_ScValue->SetFloat(m_AngVelocity2);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Rotation1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Rotation1") == 0) {
+ m_ScValue->SetFloat(m_Rotation1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Rotation2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Rotation2") == 0) {
+ m_ScValue->SetFloat(m_Rotation2);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Alpha1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Alpha1") == 0) {
+ m_ScValue->SetInt(m_Alpha1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Alpha2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Alpha2") == 0) {
+ m_ScValue->SetInt(m_Alpha2);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // AlphaTimeBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AlphaTimeBased") == 0) {
+ m_ScValue->SetBool(m_AlphaTimeBased);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MaxParticles
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MaxParticles") == 0) {
+ m_ScValue->SetInt(m_MaxParticles);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // NumLiveParticles (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "NumLiveParticles") == 0) {
+ int NumAlive = 0;
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ if (m_Particles[i] && !m_Particles[i]->m_IsDead) NumAlive++;
+ }
+ m_ScValue->SetInt(NumAlive);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GenerationInterval
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GenerationInterval") == 0) {
+ m_ScValue->SetInt(m_GenInterval);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // GenerationAmount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GenerationAmount") == 0) {
+ m_ScValue->SetInt(m_GenAmount);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // MaxBatches
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MaxBatches") == 0) {
+ m_ScValue->SetInt(m_MaxBatches);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FadeInTime
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "FadeInTime") == 0) {
+ m_ScValue->SetInt(m_FadeInTime);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // FadeOutTime
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "FadeOutTime") == 0) {
+ m_ScValue->SetInt(m_FadeOutTime);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GrowthRate1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GrowthRate1") == 0) {
+ m_ScValue->SetFloat(m_GrowthRate1);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // GrowthRate2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GrowthRate2") == 0) {
+ m_ScValue->SetFloat(m_GrowthRate2);
+ return m_ScValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // ExponentialGrowth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ExponentialGrowth") == 0) {
+ m_ScValue->SetBool(m_ExponentialGrowth);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // UseRegion
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "UseRegion") == 0) {
+ m_ScValue->SetBool(m_UseRegion);
+ return m_ScValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // EmitEvent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "EmitEvent") == 0) {
+ if (!m_EmitEvent) m_ScValue->SetNULL();
+ else m_ScValue->SetString(m_EmitEvent);
+ return m_ScValue;
+ }
+
+ else return CBObject::ScGetProperty(Name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::ScSetProperty(char *Name, CScValue *Value) {
+ //////////////////////////////////////////////////////////////////////////
+ // X
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(Name, "X") == 0) {
+ m_PosX = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Y
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Y") == 0) {
+ m_PosY = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Width") == 0) {
+ m_Width = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Height") == 0) {
+ m_Height = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Scale1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale1") == 0) {
+ m_Scale1 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Scale2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Scale2") == 0) {
+ m_Scale2 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // ScaleZBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ScaleZBased") == 0) {
+ m_ScaleZBased = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Velocity1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Velocity1") == 0) {
+ m_Velocity1 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Velocity2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Velocity2") == 0) {
+ m_Velocity2 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // VelocityZBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "VelocityZBased") == 0) {
+ m_VelocityZBased = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LifeTime1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LifeTime1") == 0) {
+ m_LifeTime1 = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // LifeTime2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LifeTime2") == 0) {
+ m_LifeTime2 = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // LifeTimeZBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "LifeTimeZBased") == 0) {
+ m_LifeTimeZBased = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Angle1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Angle1") == 0) {
+ m_Angle1 = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Angle2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Angle2") == 0) {
+ m_Angle2 = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // AngVelocity1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AngVelocity1") == 0) {
+ m_AngVelocity1 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // AngVelocity2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AngVelocity2") == 0) {
+ m_AngVelocity2 = Value->GetFloat();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Rotation1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Rotation1") == 0) {
+ m_Rotation1 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Rotation2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Rotation2") == 0) {
+ m_Rotation2 = Value->GetFloat();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Alpha1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Alpha1") == 0) {
+ m_Alpha1 = Value->GetInt();
+ if (m_Alpha1 < 0) m_Alpha1 = 0;
+ if (m_Alpha1 > 255) m_Alpha1 = 255;
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Alpha2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "Alpha2") == 0) {
+ m_Alpha2 = Value->GetInt();
+ if (m_Alpha2 < 0) m_Alpha2 = 0;
+ if (m_Alpha2 > 255) m_Alpha2 = 255;
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // AlphaTimeBased
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "AlphaTimeBased") == 0) {
+ m_AlphaTimeBased = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MaxParticles
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MaxParticles") == 0) {
+ m_MaxParticles = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GenerationInterval
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GenerationInterval") == 0) {
+ m_GenInterval = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // GenerationAmount
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GenerationAmount") == 0) {
+ m_GenAmount = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // MaxBatches
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "MaxBatches") == 0) {
+ m_MaxBatches = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FadeInTime
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "FadeInTime") == 0) {
+ m_FadeInTime = Value->GetInt();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // FadeOutTime
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "FadeOutTime") == 0) {
+ m_FadeOutTime = Value->GetInt();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GrowthRate1
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GrowthRate1") == 0) {
+ m_GrowthRate1 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // GrowthRate2
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "GrowthRate2") == 0) {
+ m_GrowthRate2 = Value->GetFloat();
+ return S_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // ExponentialGrowth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "ExponentialGrowth") == 0) {
+ m_ExponentialGrowth = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // UseRegion
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "UseRegion") == 0) {
+ m_UseRegion = Value->GetBool();
+ return S_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // EmitEvent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(Name, "EmitEvent") == 0) {
+ SAFE_DELETE_ARRAY(m_EmitEvent);
+ if (!Value->IsNULL()) CBUtils::SetString(&m_EmitEvent, Value->GetString());
+ return S_OK;
+ }
+
+ else return CBObject::ScSetProperty(Name, Value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CPartEmitter::ScToString() {
+ return "[particle emitter]";
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartEmitter::Persist(CBPersistMgr *PersistMgr) {
+ CBObject::Persist(PersistMgr);
+
+ PersistMgr->Transfer(TMEMBER(m_Width));
+ PersistMgr->Transfer(TMEMBER(m_Height));
+
+ PersistMgr->Transfer(TMEMBER(m_Angle1));
+ PersistMgr->Transfer(TMEMBER(m_Angle2));
+
+ PersistMgr->Transfer(TMEMBER(m_Velocity1));
+ PersistMgr->Transfer(TMEMBER(m_Velocity2));
+ PersistMgr->Transfer(TMEMBER(m_VelocityZBased));
+
+ PersistMgr->Transfer(TMEMBER(m_Scale1));
+ PersistMgr->Transfer(TMEMBER(m_Scale2));
+ PersistMgr->Transfer(TMEMBER(m_ScaleZBased));
+
+ PersistMgr->Transfer(TMEMBER(m_MaxParticles));
+
+ PersistMgr->Transfer(TMEMBER(m_LifeTime1));
+ PersistMgr->Transfer(TMEMBER(m_LifeTime2));
+ PersistMgr->Transfer(TMEMBER(m_LifeTimeZBased));
+
+ PersistMgr->Transfer(TMEMBER(m_GenInterval));
+ PersistMgr->Transfer(TMEMBER(m_GenAmount));
+
+ PersistMgr->Transfer(TMEMBER(m_Running));
+ PersistMgr->Transfer(TMEMBER(m_OverheadTime));
+
+ PersistMgr->Transfer(TMEMBER(m_Border));
+ PersistMgr->Transfer(TMEMBER(m_BorderThicknessLeft));
+ PersistMgr->Transfer(TMEMBER(m_BorderThicknessRight));
+ PersistMgr->Transfer(TMEMBER(m_BorderThicknessTop));
+ PersistMgr->Transfer(TMEMBER(m_BorderThicknessBottom));
+
+ PersistMgr->Transfer(TMEMBER(m_FadeInTime));
+ PersistMgr->Transfer(TMEMBER(m_FadeOutTime));
+
+ PersistMgr->Transfer(TMEMBER(m_Alpha1));
+ PersistMgr->Transfer(TMEMBER(m_Alpha2));
+ PersistMgr->Transfer(TMEMBER(m_AlphaTimeBased));
+
+ PersistMgr->Transfer(TMEMBER(m_AngVelocity1));
+ PersistMgr->Transfer(TMEMBER(m_AngVelocity2));
+
+ PersistMgr->Transfer(TMEMBER(m_Rotation1));
+ PersistMgr->Transfer(TMEMBER(m_Rotation2));
+
+ PersistMgr->Transfer(TMEMBER(m_GrowthRate1));
+ PersistMgr->Transfer(TMEMBER(m_GrowthRate2));
+ PersistMgr->Transfer(TMEMBER(m_ExponentialGrowth));
+
+ PersistMgr->Transfer(TMEMBER(m_UseRegion));
+
+ PersistMgr->Transfer(TMEMBER_INT(m_MaxBatches));
+ PersistMgr->Transfer(TMEMBER_INT(m_BatchesGenerated));
+
+ PersistMgr->Transfer(TMEMBER(m_EmitEvent));
+ PersistMgr->Transfer(TMEMBER(m_Owner));
+
+
+ m_Sprites.Persist(PersistMgr);
+
+ int NumForces;
+ if (PersistMgr->m_Saving) {
+ NumForces = m_Forces.GetSize();
+ PersistMgr->Transfer(TMEMBER(NumForces));
+ for (int i = 0; i < m_Forces.GetSize(); i++) {
+ m_Forces[i]->Persist(PersistMgr);
+ }
+ } else {
+ PersistMgr->Transfer(TMEMBER(NumForces));
+ for (int i = 0; i < NumForces; i++) {
+ CPartForce *Force = new CPartForce(Game);
+ Force->Persist(PersistMgr);
+ m_Forces.Add(Force);
+ }
+ }
+
+ int NumParticles;
+ if (PersistMgr->m_Saving) {
+ NumParticles = m_Particles.GetSize();
+ PersistMgr->Transfer(TMEMBER(NumParticles));
+ for (int i = 0; i < m_Particles.GetSize(); i++) {
+ m_Particles[i]->Persist(PersistMgr);
+ }
+ } else {
+ PersistMgr->Transfer(TMEMBER(NumParticles));
+ for (int i = 0; i < NumParticles; i++) {
+ CPartParticle *Particle = new CPartParticle(Game);
+ Particle->Persist(PersistMgr);
+ m_Particles.Add(Particle);
+ }
+ }
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/PartForce.cpp b/engines/wintermute/PartForce.cpp
new file mode 100644
index 0000000000..06f5902ab6
--- /dev/null
+++ b/engines/wintermute/PartForce.cpp
@@ -0,0 +1,56 @@
+/*
+This file is part of WME Lite.
+http://dead-code.org/redir.php?target=wmelite
+
+Copyright (c) 2011 Jan Nedoma
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/PartForce.h"
+#include "engines/wintermute/BPersistMgr.h"
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////////
+CPartForce::CPartForce(CBGame *inGame) : CBNamedObject(inGame) {
+ m_Pos = Vector2(0.0f, 0.0f);
+ m_Direction = Vector2(0.0f, 0.0f);
+ m_Type = FORCE_POINT;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CPartForce::~CPartForce(void) {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartForce::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(m_Name));
+ PersistMgr->Transfer(TMEMBER(m_Pos));
+ PersistMgr->Transfer(TMEMBER(m_Direction));
+ PersistMgr->Transfer(TMEMBER_INT(m_Type));
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/PartParticle.cpp b/engines/wintermute/PartParticle.cpp
new file mode 100644
index 0000000000..d1a892645b
--- /dev/null
+++ b/engines/wintermute/PartParticle.cpp
@@ -0,0 +1,252 @@
+/*
+This file is part of WME Lite.
+http://dead-code.org/redir.php?target=wmelite
+
+Copyright (c) 2011 Jan Nedoma
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/PartParticle.h"
+#include "engines/wintermute/PartEmitter.h"
+#include "engines/wintermute/BSprite.h"
+#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "common/str.h"
+#include <math.h>
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////////
+CPartParticle::CPartParticle(CBGame *inGame) : CBBase(inGame) {
+ m_Pos = Vector2(0.0f, 0.0f);
+ m_PosZ = 0.0f;
+ m_Velocity = Vector2(0.0f, 0.0f);
+ m_Scale = 100.0f;
+ m_Sprite = NULL;
+ m_CreationTime = 0;
+ m_LifeTime = 0;
+ m_IsDead = true;
+ CBPlatform::SetRectEmpty(&m_Border);
+
+ m_State = PARTICLE_NORMAL;
+ m_FadeStart = 0;
+ m_FadeTime = 0;
+ m_CurrentAlpha = 255;
+
+ m_Alpha1 = m_Alpha2 = 255;
+
+ m_Rotation = 0.0f;
+ m_AngVelocity = 0.0f;
+
+ m_GrowthRate = 0.0f;
+ m_ExponentialGrowth = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CPartParticle::~CPartParticle(void) {
+ delete m_Sprite;
+ m_Sprite = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartParticle::SetSprite(char *Filename) {
+ if (m_Sprite && m_Sprite->m_Filename && scumm_stricmp(Filename, m_Sprite->m_Filename) == 0) {
+ m_Sprite->Reset();
+ return S_OK;
+ }
+
+ delete m_Sprite;
+ m_Sprite = NULL;
+
+ CSysClassRegistry::GetInstance()->m_Disabled = true;
+ m_Sprite = new CBSprite(Game, Game);
+ if (m_Sprite && SUCCEEDED(m_Sprite->LoadFile(Filename))) {
+ CSysClassRegistry::GetInstance()->m_Disabled = false;
+ return S_OK;
+ } else {
+ delete m_Sprite;
+ m_Sprite = NULL;
+ CSysClassRegistry::GetInstance()->m_Disabled = false;
+ return E_FAIL;
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartParticle::Update(CPartEmitter *Emitter, uint32 CurrentTime, uint32 TimerDelta) {
+ if (m_State == PARTICLE_FADEIN) {
+ if (CurrentTime - m_FadeStart >= m_FadeTime) {
+ m_State = PARTICLE_NORMAL;
+ m_CurrentAlpha = m_Alpha1;
+ } else m_CurrentAlpha = ((float)CurrentTime - (float)m_FadeStart) / (float)m_FadeTime * m_Alpha1;
+
+ return S_OK;
+ } else if (m_State == PARTICLE_FADEOUT) {
+ if (CurrentTime - m_FadeStart >= m_FadeTime) {
+ m_IsDead = true;
+ return S_OK;
+ } else m_CurrentAlpha = m_FadeStartAlpha - ((float)CurrentTime - (float)m_FadeStart) / (float)m_FadeTime * m_FadeStartAlpha;
+
+ return S_OK;
+ } else {
+ // time is up
+ if (m_LifeTime > 0) {
+ if (CurrentTime - m_CreationTime >= m_LifeTime) {
+ if (Emitter->m_FadeOutTime > 0)
+ FadeOut(CurrentTime, Emitter->m_FadeOutTime);
+ else
+ m_IsDead = true;
+ }
+ }
+
+ // particle hit the border
+ if (!m_IsDead && !CBPlatform::IsRectEmpty(&m_Border)) {
+ POINT p;
+ p.x = m_Pos.x;
+ p.y = m_Pos.y;
+ if (!CBPlatform::PtInRect(&m_Border, p)) FadeOut(CurrentTime, Emitter->m_FadeOutTime);
+ }
+ if (m_State != PARTICLE_NORMAL) return S_OK;
+
+ // update alpha
+ if (m_LifeTime > 0) {
+ int Age = CurrentTime - m_CreationTime;
+ int AlphaDelta = m_Alpha2 - m_Alpha1;
+
+ m_CurrentAlpha = m_Alpha1 + ((float)AlphaDelta / (float)m_LifeTime * (float)Age);
+ }
+
+ // update position
+ float ElapsedTime = (float)TimerDelta / 1000.f;
+
+ for (int i = 0; i < Emitter->m_Forces.GetSize(); i++) {
+ CPartForce *Force = Emitter->m_Forces[i];
+ switch (Force->m_Type) {
+ case CPartForce::FORCE_GLOBAL:
+ m_Velocity += Force->m_Direction * ElapsedTime;
+ break;
+
+ case CPartForce::FORCE_POINT: {
+ Vector2 VecDist = Force->m_Pos - m_Pos;
+ float Dist = fabs(VecDist.Length());
+
+ Dist = 100.0f / Dist;
+
+ m_Velocity += Force->m_Direction * Dist * ElapsedTime;
+ }
+ break;
+ }
+ }
+ m_Pos += m_Velocity * ElapsedTime;
+
+ // update rotation
+ m_Rotation += m_AngVelocity * ElapsedTime;
+ m_Rotation = CBUtils::NormalizeAngle(m_Rotation);
+
+ // update scale
+ if (m_ExponentialGrowth)
+ m_Scale += m_Scale / 100.0f * m_GrowthRate * ElapsedTime;
+ else
+ m_Scale += m_GrowthRate * ElapsedTime;
+
+ if (m_Scale <= 0.0f) m_IsDead = true;
+
+
+ return S_OK;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartParticle::Display(CPartEmitter *Emitter) {
+ if (!m_Sprite) return E_FAIL;
+ if (m_IsDead) return S_OK;
+
+ m_Sprite->GetCurrentFrame();
+ return m_Sprite->Display(m_Pos.x, m_Pos.y,
+ NULL,
+ m_Scale, m_Scale,
+ DRGBA(255, 255, 255, m_CurrentAlpha),
+ m_Rotation,
+ Emitter->m_BlendMode);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartParticle::FadeIn(uint32 CurrentTime, int FadeTime) {
+ m_CurrentAlpha = 0;
+ m_FadeStart = CurrentTime;
+ m_FadeTime = FadeTime;
+ m_State = PARTICLE_FADEIN;
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartParticle::FadeOut(uint32 CurrentTime, int FadeTime) {
+ //m_CurrentAlpha = 255;
+ m_FadeStartAlpha = m_CurrentAlpha;
+ m_FadeStart = CurrentTime;
+ m_FadeTime = FadeTime;
+ m_State = PARTICLE_FADEOUT;
+
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CPartParticle::Persist(CBPersistMgr *PersistMgr) {
+ PersistMgr->Transfer(TMEMBER(m_Alpha1));
+ PersistMgr->Transfer(TMEMBER(m_Alpha2));
+ PersistMgr->Transfer(TMEMBER(m_Border));
+ PersistMgr->Transfer(TMEMBER(m_Pos));
+ PersistMgr->Transfer(TMEMBER(m_PosZ));
+ PersistMgr->Transfer(TMEMBER(m_Velocity));
+ PersistMgr->Transfer(TMEMBER(m_Scale));
+ PersistMgr->Transfer(TMEMBER(m_CreationTime));
+ PersistMgr->Transfer(TMEMBER(m_LifeTime));
+ PersistMgr->Transfer(TMEMBER(m_IsDead));
+ PersistMgr->Transfer(TMEMBER_INT(m_State));
+ PersistMgr->Transfer(TMEMBER(m_FadeStart));
+ PersistMgr->Transfer(TMEMBER(m_FadeTime));
+ PersistMgr->Transfer(TMEMBER(m_CurrentAlpha));
+ PersistMgr->Transfer(TMEMBER(m_AngVelocity));
+ PersistMgr->Transfer(TMEMBER(m_Rotation));
+ PersistMgr->Transfer(TMEMBER(m_GrowthRate));
+ PersistMgr->Transfer(TMEMBER(m_ExponentialGrowth));
+ PersistMgr->Transfer(TMEMBER(m_FadeStartAlpha));
+
+ if (PersistMgr->m_Saving) {
+ PersistMgr->Transfer(TMEMBER(m_Sprite->m_Filename));
+ } else {
+ char *Filename;
+ PersistMgr->Transfer(TMEMBER(Filename));
+ CSysClassRegistry::GetInstance()->m_Disabled = true;
+ SetSprite(Filename);
+ CSysClassRegistry::GetInstance()->m_Disabled = false;
+ delete[] Filename;
+ Filename = NULL;
+ }
+
+ return S_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/dcpackage.h b/engines/wintermute/dcpackage.h
index 3987f56798..f3ecb0d645 100644
--- a/engines/wintermute/dcpackage.h
+++ b/engines/wintermute/dcpackage.h
@@ -33,10 +33,11 @@ THE SOFTWARE.
#define PACKAGE_EXTENSION "dcp"
#include <time.h>
+#include "common/stream.h"
namespace WinterMute {
-typedef struct {
+struct TPackageHeader {
uint32 Magic1;
uint32 Magic2;
uint32 PackageVersion;
@@ -51,7 +52,25 @@ typedef struct {
#endif
char Desc[100];
uint32 NumDirs;
-} TPackageHeader;
+ // TODO: Move this out of the header.
+ void readFromStream(Common::ReadStream *stream) {
+ Magic1 = stream->readUint32LE();
+ Magic2 = stream->readUint32LE();
+ PackageVersion = stream->readUint32LE();
+
+ GameVersion = stream->readUint32LE();
+
+ Priority = stream->readByte();
+ CD = stream->readByte();
+ MasterIndex = stream->readByte();
+ stream->readByte(); // To align the next byte...
+
+ CreationTime = stream->readUint32LE();
+
+ stream->read(Desc, 100);
+ NumDirs = stream->readUint32LE();
+ }
+};
/*
v2: uint32 DirOffset
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index fa7106c801..3dc00b5a33 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -28,6 +28,7 @@ MODULE_OBJS := \
AdRegion.o \
AdResponse.o \
AdResponseBox.o \
+ AdResponseContext.o \
AdRotLevel.o \
AdScaleLevel.o \
AdScene.o \
@@ -90,7 +91,11 @@ MODULE_OBJS := \
detection.o \
FontGlyphCache.o \
MathUtil.o \
+ Matrix4.o \
PathUtil.o \
+ PartParticle.o \
+ PartEmitter.o \
+ PartForce.o \
PlatformSDL.o \
StringUtil.o \
SysClass.o \
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index 39152acc5d..aa32ad8578 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -31,8 +31,9 @@
#include "common/fs.h"
#include "engines/util.h"
-#include "engines/wintermute/BGame.h"
+#include "engines/wintermute/ADGame.h"
#include "engines/wintermute/wintermute.h"
+#include "engines/wintermute/PlatformSDL.h"
namespace WinterMute {
@@ -102,7 +103,8 @@ namespace WinterMute {
// This test will show up if --debugflags=example or --debugflags=example2 or both of them and -d3 are specified on the commandline
debugC(3, kWinterMuteDebugExample | kWinterMuteDebugExample2, "Example debug call two");
- CBGame game;
+ CAdGame *game = new CAdGame;
+ CBPlatform::Initialize(game, NULL, 0);
return Common::kNoError;
}