diff --git a/src/GenericChunks.cpp b/src/GenericChunks.cpp index 19a37fa..665568d 100644 --- a/src/GenericChunks.cpp +++ b/src/GenericChunks.cpp @@ -1937,7 +1937,10 @@ GENMNAM::GENMNAM(): NWCellX(0), NWCellY(0), SECellX(0), - SECellY(0) + SECellY(0), + minHeight(50000.0f), + maxHeight(80000.0f), + initialPitch(50.0f) { // } diff --git a/src/GenericChunks.h b/src/GenericChunks.h index 04e8b64..81c38dd 100644 --- a/src/GenericChunks.h +++ b/src/GenericChunks.h @@ -753,6 +753,10 @@ struct GENMNAM int32_t dimX, dimY; int16_t NWCellX, NWCellY, SECellX, SECellY; + float minHeight; + float maxHeight; + float initialPitch; + GENMNAM(); ~GENMNAM(); diff --git a/src/Skyrim/GRUPRecord.h b/src/Skyrim/GRUPRecord.h index 8e5ccb8..5131785 100644 --- a/src/Skyrim/GRUPRecord.h +++ b/src/Skyrim/GRUPRecord.h @@ -37,6 +37,7 @@ #include "Records/CELLRecord.h" #include "Records/LANDRecord.h" #include "Records/WRLDRecord.h" +#include "Records/DIALRecord.h" template class TES5GRUPRecords @@ -2176,3 +2177,263 @@ class TES5GRUPRecords return formCount; } }; + + +template +class TES5GRUPRecords +{ +public: + RecordPoolAllocator dial_pool; + RecordPoolAllocator info_pool; + uint32_t stamp, unknown; + + TES5GRUPRecords() : + stamp(134671), + unknown(0) + { + // + } + + ~TES5GRUPRecords() + { + // + } + + bool Read(unsigned char *&buffer_start, unsigned char *&buffer_position, unsigned char *&group_buffer_end, RecordOp &indexer, RecordOp &parser, std::vector &DeletedRecords, RecordProcessor &processor, char * &FileName) + { + stamp = *(uint32_t *)buffer_position; + buffer_position += 4; + if (group_buffer_end <= buffer_position) + { + printer("TES5GRUPRecords::Read: Error - Unable to load group in file \"%s\". The group has a size of 0.\n", FileName); +#ifdef CBASH_DEBUG_CHUNK + peek_around(buffer_position, PEEK_SIZE); +#endif + return false; + } + + Record * curRecord = NULL; + uint32_t recordSize = 0; + RecordHeader header; + + Sk::DIALRecord *last_record = NULL, *orphaned_records = NULL; + uint32_t numDIAL = 0, numINFO = 0; + + std::vector records; + records.reserve((uint32_t)(group_buffer_end - buffer_position) / sizeof(Sk::DIALRecord)); //gross overestimation, but good enough + while (buffer_position < group_buffer_end){ + if ((processor.IsSkipAllRecords && processor.IsTrackNewTypes) && + processor.NewTypes.count(REV32(DIAL)) > 0 && + processor.NewTypes.count(REV32(INFO)) > 0) + { + buffer_position = group_buffer_end; + break; + } + + //Assumes that all records in a generic group are of the same type + header.type = *(uint32_t *)buffer_position; + buffer_position += 4; + recordSize = *(uint32_t *)buffer_position; + buffer_position += 4; + + if (header.type == REV32(GRUP)) //All GRUPs will be recreated from scratch on write (saves memory) + { + if (recordSize == 20) + processor.EmptyGRUPs++; + buffer_position += 16; + continue; + } + + header.flags = *(uint32_t *)buffer_position; + buffer_position += 4; + header.formID = *(FORMID *)buffer_position; + buffer_position += 4; + header.flagsUnk = *(uint32_t *)buffer_position; //VersionControl1 + buffer_position += 4; + header.formVersion = *(uint16_t *)buffer_position; + buffer_position += 2; + header.versionControl2[0] = *(uint8_t *)buffer_position; + buffer_position++; + header.versionControl2[1] = *(uint8_t *)buffer_position; + buffer_position++; + + if (processor.Accept(header)) + { + header.data = buffer_position; + records.push_back(header); + + switch (header.type) + { + case REV32(DIAL): + numDIAL++; + break; + case REV32(INFO): + numINFO++; + break; + default: + printer("TES5GRUPRecords::Read: Warning - Parsing error. Unexpected record type (%c%c%c%c) in file \"%s\".\n", ((char *)&header.type)[0], ((char *)&header.type)[1], ((char *)&header.type)[2], ((char *)&header.type)[3], FileName); +#ifdef CBASH_DEBUG_CHUNK + peek_around(buffer_position, PEEK_SIZE); +#endif + records.pop_back(); + break; + } + } + + buffer_position += recordSize; + }; + + if (records.size()) + { + //Allocates many records at once in a contiguous space + //Allocate memory + unsigned char *dial_buffer = NULL; + if (numDIAL) + { + dial_buffer = (unsigned char *)malloc(sizeof(Sk::DIALRecord) * numDIAL); + if (dial_buffer == 0) + throw std::bad_alloc(); + dial_pool.add_buffer(dial_buffer); + } + + unsigned char *info_buffer = NULL; + if (numINFO) + { + info_buffer = (unsigned char *)malloc(sizeof(Sk::INFORecord) * numINFO); + if (info_buffer == 0) + throw std::bad_alloc(); + info_pool.add_buffer(info_buffer); + } + + last_record = orphaned_records = new Sk::DIALRecord(); + + //Construct the records + for (uint32_t x = 0; x < records.size(); ++x) + { + header = records[x]; + + switch (header.type) + { + case REV32(DIAL): + curRecord = last_record = new(dial_buffer)Sk::DIALRecord(header.data); + dial_buffer += sizeof(Sk::DIALRecord); + curRecord->SetParent(processor.curModFile, true); + break; + case REV32(INFO): + curRecord = new(info_buffer)Sk::INFORecord(header.data); + info_buffer += sizeof(Sk::INFORecord); + curRecord->SetParent(last_record, false); + last_record->INFO.push_back(curRecord); + break; + default: + printer("TES5GRUPRecords::Read: Warning - Parsing error. Unexpected record type (%c%c%c%c) in file \"%s\".\n", ((char *)&header.type)[0], ((char *)&header.type)[1], ((char *)&header.type)[2], ((char *)&header.type)[3], FileName); +#ifdef CBASH_DEBUG_CHUNK + peek_around(header.data, PEEK_SIZE); +#endif + continue; + break; + } + + curRecord->flags = header.flags; + curRecord->formID = header.formID; + curRecord->flagsUnk = header.flagsUnk; + //Testing Messages + //if((flags & 0x4000) != 0) + // printer("0x4000 used: %08X!!!!\n", curRecord->formID); + + //Read (if FullLoad), no-op otherwise + parser.Accept(curRecord); + //Save any deleted records for post-processing + if (curRecord->IsDeleted()) + DeletedRecords.push_back(curRecord); + //Index it for fast, random lookup + indexer.Accept(curRecord); + } + + records.clear(); + + for (uint32_t x = 0; x < orphaned_records->INFO.size(); ++x) + { + curRecord = orphaned_records->INFO[x]; + processor.OrphanedRecords.push_back(curRecord->formID); + //printer("TES5GRUPRecords::Read: Warning - Parsing error. Skipped orphan INFO (%08X) at %08X in file \"%s\"\n", curRecord->formID, curRecord->recData - buffer_start, FileName); +#ifdef CBASH_DEBUG_CHUNK + peek_around(curRecord->recData, PEEK_SIZE); +#endif + info_pool.destroy(curRecord); + } + delete orphaned_records; + } + + return true; + } + + uint32_t Write(FileWriter &writer, std::vector &Expanders, FormIDResolver &expander, FormIDResolver &collapser, const bool &bMastersChanged, bool CloseMod) + { + std::vector Records; + dial_pool.MakeRecordsVector(Records); + uint32_t numDIALRecords = (uint32_t)Records.size(); //Parent Records + if (numDIALRecords == 0) + return 0; + + uint32_t type = REV32(GRUP); + uint32_t gType = eTop; + uint32_t TopSize = 0; + uint32_t ChildrenSize = 0; + uint32_t formCount = 0; + uint32_t TopLabel = REV32(DIAL); + uint32_t numINFORecords = 0; + uint32_t parentFormID = 0; + Sk::DIALRecord *curRecord = NULL; + + //Top GRUP Header + writer.file_write(&type, 4); + uint32_t TopSizePos = writer.file_tell(); + writer.file_write(&TopSize, 4); //Placeholder: will be overwritten with correct value later. + writer.file_write(&TopLabel, 4); + writer.file_write(&gType, 4); + writer.file_write(&stamp, 4); + writer.file_write(&unknown, 4); + ++formCount; + TopSize = 24; + + + gType = eTopicChildren; + formCount += numDIALRecords; + for (uint32_t p = 0; p < numDIALRecords; ++p) + { + curRecord = (Sk::DIALRecord *)Records[p]; + parentFormID = curRecord->formID; + collapser.Accept(parentFormID); + TopSize += curRecord->Write(writer, bMastersChanged, expander, collapser, Expanders); + + numINFORecords = (uint32_t)curRecord->INFO.size(); + if (numINFORecords) + { + writer.file_write(&type, 4); + uint32_t ChildrenSizePos = writer.file_tell(); + writer.file_write(&ChildrenSize, 4); //Placeholder: will be overwritten with correct value later. + writer.file_write(&parentFormID, 4); + writer.file_write(&gType, 4); + writer.file_write(&stamp, 4); + writer.file_write(&unknown, 4); + ++formCount; + ChildrenSize = 24; + + formCount += numINFORecords; + for (uint32_t y = 0; y < numINFORecords; ++y) + ChildrenSize += curRecord->INFO[y]->Write(writer, bMastersChanged, expander, collapser, Expanders); + writer.file_write(ChildrenSizePos, &ChildrenSize, 4); + TopSize += ChildrenSize; + } + } + writer.file_write(TopSizePos, &TopSize, 4); + if (CloseMod) + { + info_pool.purge_with_destructors(); + dial_pool.purge_with_destructors(); + } + return formCount; + } + +}; diff --git a/src/Skyrim/Records/CELLRecord.cpp b/src/Skyrim/Records/CELLRecord.cpp index 5719b01..1b66fcc 100644 --- a/src/Skyrim/Records/CELLRecord.cpp +++ b/src/Skyrim/Records/CELLRecord.cpp @@ -81,7 +81,7 @@ CELLRecord::CELLRecord(CELLRecord *srcRecord): FULL = srcRecord->FULL; DATA = srcRecord->DATA; XCLC = srcRecord->XCLC; -/* XCLL = srcRecord->XCLL;*/ + XCLL = srcRecord->XCLL; IMPS = srcRecord->IMPS; IMPF = srcRecord->IMPF; LTMP = srcRecord->LTMP; @@ -95,6 +95,7 @@ CELLRecord::CELLRecord(CELLRecord *srcRecord): XCCM = srcRecord->XCCM; XCWT = srcRecord->XCWT; /* Ownership = srcRecord->Ownership;*/ + XOWN = srcRecord->XOWN; XCAS = srcRecord->XCAS; XCMT = srcRecord->XCMT; XCMO = srcRecord->XCMO; @@ -162,6 +163,8 @@ bool CELLRecord::VisitFormIDs(FormIDOp &op) op.Accept(XCWT.value); /* if(Ownership.IsLoaded()) op.Accept(Ownership->XOWN.value);*/ + if(XOWN.IsLoaded()) + op.Accept(XOWN.value); if(XCAS.IsLoaded()) op.Accept(XCAS.value); if(XCMO.IsLoaded()) @@ -468,9 +471,9 @@ int32_t CELLRecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer case REV32(XCLC): XCLC.Read(buffer, subSize); break; -/* case REV32(XCLL): + case REV32(XCLL): XCLL.Read(buffer, subSize); - break;*/ + break; case REV32(IMPS): IMPS.Read(buffer, subSize); break; @@ -507,10 +510,10 @@ int32_t CELLRecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer case REV32(XCWT): XCWT.Read(buffer, subSize); break; -/* case REV32(XOWN): - Ownership.Load(); - Ownership->XOWN.Read(buffer, subSize); + case REV32(XOWN): + XOWN.Read(buffer, subSize); break; + /* case REV32(XRNK): Ownership.Load(); Ownership->XRNK.Read(buffer, subSize); @@ -561,7 +564,7 @@ int32_t CELLRecord::Unload() FULL.Unload(); DATA.Unload(); XCLC.Unload(); -/* XCLL.Unload();*/ + XCLL.Unload(); IMPS.Unload(); IMPF.Unload(); LTMP.Unload(); @@ -574,6 +577,7 @@ int32_t CELLRecord::Unload() XEZN.Unload(); XCCM.Unload(); XCWT.Unload(); + XOWN.Unload(); /* Ownership.Unload();*/ XCAS.Unload(); XCMT.Unload(); @@ -592,7 +596,7 @@ int32_t CELLRecord::WriteRecord(FileWriter &writer) WRITE(FULL); //DATA.Unload(); //need to keep IsInterior around WRITE(XCLC); -/* WRITE(XCLL);*/ + WRITE(XCLL); WRITE(IMPS); WRITE(IMPF); if(LNAM.value != 0 || LTMP.value != 0) @@ -612,6 +616,7 @@ int32_t CELLRecord::WriteRecord(FileWriter &writer) WRITE(XCCM); WRITE(XCWT); /* Ownership.Write(writer);*/ + WRITE(XOWN); WRITE(XCAS); WRITE(XCMT); WRITE(XCMO); @@ -627,7 +632,7 @@ bool CELLRecord::operator ==(const CELLRecord &other) const { return (DATA == other.DATA && XCLC == other.XCLC && -/* XCLL == other.XCLL &&*/ + XCLL == other.XCLL && IMPF == other.IMPF && LTMP == other.LTMP && LNAM == other.LNAM && @@ -641,6 +646,7 @@ bool CELLRecord::operator ==(const CELLRecord &other) const IMPS == other.IMPS && XCLR == other.XCLR && /* Ownership == other.Ownership &&*/ + XOWN == other.XOWN && EDID.equalsi(other.EDID) && FULL.equals(other.FULL) && XNAM.equalsi(other.XNAM) && @@ -753,4 +759,59 @@ bool CELLRecord::deep_equals(Record *master, RecordOp &read_self, RecordOp &read return true; } + +CELLRecord::TES5LIGHT::TES5LIGHT() : +fogNear(0.0f), +fogFar(0.0f), +directionalXY(0), +directionalZ(0), +directionalFade(0.0f), +fogClip(0.0f), +fogPower(0.0f), +fresnelPow(0.0f), +fogMax(0.0f), +lightFadeDistancesStart(0.0f), +lightFadeDistancesEnd(0.0f) +{ + // +} + +CELLRecord::TES5LIGHT::~TES5LIGHT() +{ + // +} + +bool CELLRecord::TES5LIGHT::operator ==(const TES5LIGHT &other) const +{ + return (ambient == other.ambient && + directional == other.directional && + fog == other.fog && + AlmostEqual(fogNear, other.fogNear, 2) && + AlmostEqual(fogFar, other.fogFar, 2) && + directionalXY == other.directionalXY && + directionalZ == other.directionalZ && + AlmostEqual(directionalFade, other.directionalFade, 2) && + AlmostEqual(fogClip, other.fogClip, 2) && + AlmostEqual(fogPower, other.fogPower, 2) && + ambientXp == other.ambientXp && + ambientXm == other.ambientXm && + ambientYp == other.ambientYp && + ambientYm == other.ambientYm && + ambientZp == other.ambientZp && + ambientZm == other.ambientZm && + specular == other.specular && + AlmostEqual(fresnelPow, other.fresnelPow, 2) && + fogFarTwo == other.fogFarTwo && + AlmostEqual(fogMax, other.fogMax, 2) && + AlmostEqual(lightFadeDistancesStart, other.lightFadeDistancesStart, 2) && + AlmostEqual(lightFadeDistancesEnd, other.lightFadeDistancesEnd, 2) && + inheritFlags == other.inheritFlags + ); +} + +bool CELLRecord::TES5LIGHT::operator !=(const TES5LIGHT &other) const +{ + return !(*this == other); +} + } \ No newline at end of file diff --git a/src/Skyrim/Records/CELLRecord.h b/src/Skyrim/Records/CELLRecord.h index 0a2d00b..11da396 100644 --- a/src/Skyrim/Records/CELLRecord.h +++ b/src/Skyrim/Records/CELLRecord.h @@ -54,6 +54,33 @@ class CELLRecord : public TES5Record //Cell bool operator !=(const CELLXCLC &other) const; }; + + struct TES5LIGHT + { + GENCLR ambient; //Ambient Color + GENCLR directional; //Directional Color + GENCLR fog; //Fog Color + float fogNear, fogFar; //Fog Near, Fog Far + int32_t directionalXY, directionalZ; //Directional Rotation XY, Directional Rotation Z + float directionalFade, fogClip, fogPower; //Directional Fade, Fog Clip Dist, Fog Power + + GENCLR ambientXp, ambientXm, ambientYp, ambientYm, ambientZp, ambientZm; + GENCLR specular; + float fresnelPow; + GENCLR fogFarTwo; + float fogMax; + float lightFadeDistancesStart; + float lightFadeDistancesEnd; + + uint32_t inheritFlags; + + TES5LIGHT(); + ~TES5LIGHT(); + + bool operator ==(const TES5LIGHT &other) const; + bool operator !=(const TES5LIGHT &other) const; + }; + enum flagsFlags { fIsInterior = 0x00000001, @@ -92,7 +119,7 @@ class CELLRecord : public TES5Record //Cell StringRecord FULL; //Name ReqSimpleSubRecord DATA; //Flags OptSubRecord XCLC; //Grid -// OptSubRecord XCLL; //Lighting + OptSubRecord XCLL; //Lighting UnorderedSparseArray IMPS; //Swapped Impact OptSubRecord IMPF; //Footstep Materials ReqSimpleSubRecord LTMP; //Light Template @@ -106,6 +133,7 @@ class CELLRecord : public TES5Record //Cell OptSimpleSubRecord XCCM; //Climate OptSimpleSubRecord XCWT; //Water -> WATR // OptSubRecord Ownership; //Owner + OptSimpleSubRecord XOWN; //Owner simple. OptSimpleSubRecord XCAS; //Acoustic Space RawRecord XCMT; //Unused OptSimpleSubRecord XCMO; //Music Type diff --git a/src/Skyrim/Records/DIALRecord.cpp b/src/Skyrim/Records/DIALRecord.cpp new file mode 100644 index 0000000..dc59cf4 --- /dev/null +++ b/src/Skyrim/Records/DIALRecord.cpp @@ -0,0 +1,219 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is CBash code. + * + * The Initial Developer of the Original Code is + * Waruddar. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "..\..\Common.h" +#include "DIALRecord.h" + +namespace Sk +{ +DIALRecord::DIALRecord(unsigned char *_recData): + TES5Record(_recData) + { + // + } + +DIALRecord::DIALRecord(DIALRecord *srcRecord): + TES5Record() + { + if(srcRecord == NULL) + return; + + flags = srcRecord->flags; + formID = srcRecord->formID; + flagsUnk = srcRecord->flagsUnk; + formVersion = srcRecord->formVersion; + versionControl2[0] = srcRecord->versionControl2[0]; + versionControl2[1] = srcRecord->versionControl2[1]; + + recData = srcRecord->recData; + if(!srcRecord->IsChanged()) + return; + + EDID = srcRecord->EDID; + FULL = srcRecord->FULL; + PNAM = srcRecord->PNAM; + BNAM = srcRecord->BNAM; + QNAM = srcRecord->QNAM; + DATA = srcRecord->DATA; + SNAM = srcRecord->SNAM; + TIFC = srcRecord->TIFC; + INFO = srcRecord->INFO; + + return; + } + +DIALRecord::~DIALRecord() + { + // + } + +uint32_t DIALRecord::GetType() + { + return REV32(DIAL); + } + +char * DIALRecord::GetStrType() + { + return "DIAL"; + } + +bool DIALRecord::VisitFormIDs(FormIDOp &op) +{ + if (!IsLoaded()) + return false; + + op.Accept(BNAM.value); + //REVERT ASAP + op.Accept(QNAM.value); + + return op.Stop(); +} + + +int32_t DIALRecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk) + { + uint32_t subType = 0; + uint32_t subSize = 0; + while(buffer < end_buffer){ + subType = *(uint32_t *)buffer; + buffer += 4; + switch(subType) + { + case REV32(XXXX): + buffer += 2; + subSize = *(uint32_t *)buffer; + buffer += 4; + subType = *(uint32_t *)buffer; + buffer += 6; + break; + default: + subSize = *(uint16_t *)buffer; + buffer += 2; + break; + } + switch(subType) + { + case REV32(EDID): + EDID.Read(buffer, subSize, CompressedOnDisk); + break; + case REV32(FULL): + FULL.Read(buffer, subSize, CompressedOnDisk); + break; + case REV32(PNAM): + PNAM.Read(buffer, subSize); + break; + case REV32(BNAM): + BNAM.Read(buffer, subSize); + break; + case REV32(QNAM): + QNAM.Read(buffer, subSize); + break; + case REV32(DATA): + DATA.Read(buffer, subSize); + break; + case REV32(SNAM): + SNAM.Read(buffer, subSize); + break; + case REV32(TIFC): + TIFC.Read(buffer, subSize); + break; + default: + //printer("FileName = %s\n", FileName); + printer(" DIAL: %08X - Unknown subType = %04x\n", formID, subType); + CBASH_CHUNK_DEBUG + printer(" Size = %i\n", subSize); + printer(" CurPos = %04x\n\n", buffer - 6); + buffer = end_buffer; + break; + } + }; + return 0; + } + +int32_t DIALRecord::Unload() + { + IsChanged(false); + IsLoaded(false); + + + EDID.Unload(); + FULL.Unload(); + PNAM.Unload(); + BNAM.Unload(); + QNAM.Unload(); + DATA.Unload(); + SNAM.Unload(); + TIFC.Unload(); + + + return 1; + } + +int32_t DIALRecord::WriteRecord(FileWriter &writer) + { + WRITE(EDID); + WRITE(FULL); + WRITE(PNAM); + WRITE(BNAM); + WRITE(QNAM); + WRITE(DATA); + WRITE(SNAM); + WRITE(TIFC); + return -1; + } + +bool DIALRecord::operator ==(const DIALRecord &other) const + { + return (EDID.equalsi(other.EDID) && + FULL.equalsi(other.FULL) && + PNAM == other.PNAM && + BNAM == other.BNAM && + QNAM == other.QNAM && + DATA == other.DATA && + SNAM == other.SNAM && + TIFC == other.TIFC + ); + } + +bool DIALRecord::operator !=(const DIALRecord &other) const + { + return !(*this == other); + } + +bool DIALRecord::equals(Record *other) + { + return *this == *(DIALRecord *)other; + } +} \ No newline at end of file diff --git a/src/Skyrim/Records/DIALrecord.h b/src/Skyrim/Records/DIALrecord.h new file mode 100644 index 0000000..d1a03c0 --- /dev/null +++ b/src/Skyrim/Records/DIALrecord.h @@ -0,0 +1,102 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is CBash code. + * + * The Initial Developer of the Original Code is + * Waruddar. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#pragma once +#include "..\..\Common.h" +#include "..\..\GenericRecord.h" +#include "INFORecord.h" +namespace Sk +{ + +struct DIALPACKDATA { + + DIALPACKDATA() { unknown = false; dialogueTab = 0; subtypeId = 0; unused = 0; } + ~DIALPACKDATA() {} + + + bool unknown; + uint8_t dialogueTab; + uint8_t subtypeId; + uint8_t unused; + + bool operator ==(const DIALPACKDATA &other) const { + return ( + this->dialogueTab == other.dialogueTab && + this->subtypeId == other.subtypeId && + this->subtypeId == other.subtypeId && + this->unused == other.unused + ); + } + + bool operator !=(const DIALPACKDATA &other) const + { + return !(*this == other); + } + +}; + +class DIALRecord : public TES5Record //Texture Set + { + + public: + StringRecord EDID; //Editor ID + StringRecord FULL; //Player dialogue. + ReqSimpleFloatSubRecord PNAM; + ReqSimpleSubRecord BNAM; //Branch formid + ReqSimpleSubRecord QNAM; //Quest formid + ReqSubRecord DATA; + ReqSimpleSubRecord SNAM; //Subtype + ReqSimpleSubRecord TIFC; //Topic info count + + std::vector INFO; + + DIALRecord(unsigned char *_recData=NULL); + DIALRecord(DIALRecord *srcRecord); + ~DIALRecord(); + + uint32_t GetType(); + char * GetStrType(); + + bool VisitFormIDs(FormIDOp &op); + + int32_t ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk); + int32_t Unload(); + int32_t WriteRecord(FileWriter &writer); + + bool operator ==(const DIALRecord &other) const; + bool operator !=(const DIALRecord &other) const; + bool equals(Record *other); + }; +} \ No newline at end of file diff --git a/src/Skyrim/Records/DLBRrecord.cpp b/src/Skyrim/Records/DLBRrecord.cpp new file mode 100644 index 0000000..f76a021 --- /dev/null +++ b/src/Skyrim/Records/DLBRrecord.cpp @@ -0,0 +1,200 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ +#include "..\..\Common.h" +#include "DLBRRecord.h" + +namespace Sk +{ + DLBRRecord::DLBRRecord(unsigned char *_recData) : + TES5Record(_recData) + { + // + } + + DLBRRecord::DLBRRecord(DLBRRecord *srcRecord) : + TES5Record() + { + if (srcRecord == NULL) + return; + + flags = srcRecord->flags; + formID = srcRecord->formID; + flagsUnk = srcRecord->flagsUnk; + formVersion = srcRecord->formVersion; + versionControl2[0] = srcRecord->versionControl2[0]; + versionControl2[1] = srcRecord->versionControl2[1]; + + EDID = srcRecord->EDID; + QNAM = srcRecord->QNAM; + TNAM = srcRecord->TNAM; + DNAM = srcRecord->DNAM; + SNAM = srcRecord->SNAM; + + recData = srcRecord->recData; + if (!srcRecord->IsChanged()) + return; + + return; + } + + DLBRRecord::~DLBRRecord() + { + // + } + + uint32_t DLBRRecord::GetType() + { + return REV32(DLBR); + } + + char * DLBRRecord::GetStrType() + { + return "DLBR"; + } + + + bool DLBRRecord::VisitFormIDs(FormIDOp &op) + { + if (!IsLoaded()) + return false; + //REVERT ASAP + op.Accept(QNAM.value); + op.Accept(SNAM.value); + + + return op.Stop(); + } + + + int32_t DLBRRecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk) + { + uint32_t subType = 0; + uint32_t subSize = 0; + while (buffer < end_buffer){ + subType = *(uint32_t *)buffer; + buffer += 4; + switch (subType) + { + case REV32(XXXX): + buffer += 2; + subSize = *(uint32_t *)buffer; + buffer += 4; + subType = *(uint32_t *)buffer; + buffer += 6; + break; + default: + subSize = *(uint16_t *)buffer; + buffer += 2; + break; + } + switch (subType) + { + case REV32(EDID): + EDID.Read(buffer, subSize, CompressedOnDisk); + break; + + case REV32(QNAM): + QNAM.Read(buffer, subSize); + break; + + case REV32(TNAM): + TNAM.Read(buffer, subSize); + break; + + case REV32(DNAM): + DNAM.Read(buffer, subSize); + break; + + case REV32(SNAM): + SNAM.Read(buffer, subSize); + break; + + default: + //printer("FileName = %s\n", FileName); + printer(" TXST: %08X - Unknown subType = %04x\n", formID, subType); + CBASH_CHUNK_DEBUG + printer(" Size = %i\n", subSize); + printer(" CurPos = %04x\n\n", buffer - 6); + buffer = end_buffer; + break; + } + }; + return 0; + } + + int32_t DLBRRecord::Unload() + { + IsChanged(false); + IsLoaded(false); + + EDID.Unload(); + QNAM.Unload(); + TNAM.Unload(); + DNAM.Unload(); + SNAM.Unload(); + return 1; + } + + int32_t DLBRRecord::WriteRecord(FileWriter &writer) + { + WRITE(EDID); + WRITE(QNAM); + WRITE(TNAM); + WRITE(DNAM); + WRITE(SNAM); + return -1; + } + + bool DLBRRecord::operator ==(const DLBRRecord &other) const + { + return (EDID.equalsi(other.EDID) && + QNAM == other.QNAM && + TNAM == other.TNAM && + DNAM == other.DNAM && + SNAM == other.SNAM + ); + } + + bool DLBRRecord::operator !=(const DLBRRecord &other) const + { + return !(*this == other); + } + + bool DLBRRecord::equals(Record *other) + { + return *this == *(DLBRRecord *)other; + } +} \ No newline at end of file diff --git a/src/Skyrim/Records/DLBRrecord.h b/src/Skyrim/Records/DLBRrecord.h new file mode 100644 index 0000000..7af6003 --- /dev/null +++ b/src/Skyrim/Records/DLBRrecord.h @@ -0,0 +1,71 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is CBash code. + * + * The Initial Developer of the Original Code is + * Waruddar. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#pragma once +#include "..\..\Common.h" +#include "..\..\GenericRecord.h" + +namespace Sk +{ +class DLBRRecord : public TES5Record //Texture Set + { + + public: + StringRecord EDID; //Editor ID + ReqSimpleSubRecord QNAM; //Quest formid + ReqSimpleSubRecord TNAM; + ReqSimpleSubRecord DNAM; + ReqSimpleSubRecord SNAM; //Dial reference + + + DLBRRecord(unsigned char *_recData = NULL); + DLBRRecord(DLBRRecord *srcRecord); + ~DLBRRecord(); + + uint32_t GetType(); + char * GetStrType(); + + bool VisitFormIDs(FormIDOp &op); + + int32_t ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk); + int32_t Unload(); + int32_t WriteRecord(FileWriter &writer); + + + bool operator ==(const DLBRRecord &other) const; + bool operator !=(const DLBRRecord &other) const; + bool equals(Record *other); + }; +} \ No newline at end of file diff --git a/src/Skyrim/Records/INFORecord.cpp b/src/Skyrim/Records/INFORecord.cpp new file mode 100644 index 0000000..33c9fe7 --- /dev/null +++ b/src/Skyrim/Records/INFORecord.cpp @@ -0,0 +1,361 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ +#pragma once +// BaseRecord.h +#include "../../Common.h" +#include "../../GenericChunks.h" +#include "INFORecord.h" +#include + +namespace Sk { + + + INFORecord::INFORecord(unsigned char *_recData) : + TES5Record(_recData) + { + // + } + + INFORecord::INFORecord(INFORecord *srcRecord) : + TES5Record() + { + if (srcRecord == NULL) + return; + + flags = srcRecord->flags; + formID = srcRecord->formID; + flagsUnk = srcRecord->flagsUnk; + formVersion = srcRecord->formVersion; + versionControl2[0] = srcRecord->versionControl2[0]; + versionControl2[1] = srcRecord->versionControl2[1]; + + EDID = srcRecord->EDID; + DATA = srcRecord->DATA; + ENAM = srcRecord->ENAM; + PNAM = srcRecord->PNAM; + CNAM = srcRecord->CNAM; + TCLT = srcRecord->TCLT; + DNAM = srcRecord->DNAM; + responses = srcRecord->responses; + CTDA = srcRecord->CTDA; + RNAM = srcRecord->RNAM; + ANAM = srcRecord->ANAM; + TWAT = srcRecord->TWAT; + ONAM = srcRecord->ONAM; + + recData = srcRecord->recData; + if (!srcRecord->IsChanged()) + return; + + return; + } + + INFORecord::~INFORecord() + { + // + } + + uint32_t INFORecord::GetType() + { + return REV32(INFO); + } + + char * INFORecord::GetStrType() + { + return "INFO"; + } + + + bool INFORecord::VisitFormIDs(FormIDOp &op) + { + if (!IsLoaded()) + return false; + + if (PNAM.IsLoaded()) { + op.Accept(PNAM.value); + } + + for (uint32_t ListIndex = 0; ListIndex < TCLT.value.size(); ListIndex++) + op.Accept(TCLT.value[ListIndex]); + + op.Accept(DNAM.value); + + if (RNAM.IsLoaded()) { + op.Accept(RNAM.value); + } + + //REVERT ASAP! + if (ANAM.IsLoaded()) { + op.Accept(ANAM.value); + } + + if (TWAT.IsLoaded()) { + op.Accept(TWAT.value); + } + + if (ONAM.IsLoaded()) { + op.Accept(ONAM.value); + } + + return op.Stop(); + } + + int32_t INFORecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk) + { + uint32_t subType = 0; + uint32_t subSize = 0; + INFORecordResponse* response = new INFORecordResponse(); + bool isFirst = true; + + while (buffer < end_buffer){ + subType = *(uint32_t *)buffer; + buffer += 4; + switch (subType) + { + case REV32(XXXX): + buffer += 2; + subSize = *(uint32_t *)buffer; + buffer += 4; + subType = *(uint32_t *)buffer; + buffer += 6; + break; + default: + subSize = *(uint16_t *)buffer; + buffer += 2; + break; + } + switch (subType) + { + case REV32(EDID): + EDID.Read(buffer, subSize, CompressedOnDisk); + break; + + case REV32(DATA): + DATA.Read(buffer, subSize); + break; + + case REV32(ENAM): + ENAM.Read(buffer, subSize); + break; + + case REV32(PNAM): + PNAM.Read(buffer, subSize); + break; + + case REV32(CNAM): + CNAM.Read(buffer, subSize); + break; + + case REV32(TCLT): + TCLT.Read(buffer, subSize); + break; + + case REV32(DNAM): + DNAM.Read(buffer, subSize); + break; + + case REV32(TRDT): + if (!isFirst) { + this->responses.push_back(response); + INFORecordResponse* response = new INFORecordResponse(); + } + else { + isFirst = false; + } + response->TRDT.Read(buffer, subSize); + break; + + case REV32(NAM1): + if (response == NULL) { + throw std::exception("Wrong responses format in INFO"); + } + response->NAM1.Read(buffer, subSize, CompressedOnDisk); + break; + + case REV32(NAM2): + if (response == NULL) { + throw std::exception("Wrong responses format in INFO"); + } + response->NAM2.Read(buffer, subSize, CompressedOnDisk); + break; + + case REV32(NAM3): + if (response == NULL) { + throw std::exception("Wrong responses format in INFO"); + } + response->NAM3.Read(buffer, subSize, CompressedOnDisk); + break; + + case REV32(SNAM): + if (response == NULL) { + throw std::exception("Wrong responses format in INFO"); + } + response->SNAM.Read(buffer, subSize); + break; + + case REV32(LNAM): + if (response == NULL) { + throw std::exception("Wrong responses format in INFO"); + } + response->LNAM.Read(buffer, subSize); + break; + + case REV32(CTDA): + CTDA.Read(buffer, subSize); + break; + + case REV32(RNAM): + RNAM.Read(buffer, subSize); + break; + + case REV32(ANAM): + ANAM.Read(buffer, subSize); + break; + + case REV32(TWAT): + TWAT.Read(buffer, subSize); + break; + + case REV32(ONAM): + ONAM.Read(buffer, subSize); + break; + + default: + //printer("FileName = %s\n", FileName); + printer(" INFO: %08X - Unknown subType = %04x\n", formID, subType); + CBASH_CHUNK_DEBUG + printer(" Size = %i\n", subSize); + printer(" CurPos = %04x\n\n", buffer - 6); + buffer = end_buffer; + break; + } + }; + return 0; + } + + int32_t INFORecord::Unload() + { + IsChanged(false); + IsLoaded(false); + + + EDID.Unload(); + DATA.Unload(); + ENAM.Unload(); + PNAM.Unload(); + CNAM.Unload(); + TCLT.Unload(); + DNAM.Unload(); + + for (uint32_t i = 0; i < responses.size(); ++i) { + + /* + responses[i]->TRDT.Unload(); + */ + responses[i]->NAM1.Unload(); + responses[i]->NAM2.Unload(); + responses[i]->NAM3.Unload(); + responses[i]->SNAM.Unload(); + responses[i]->LNAM.Unload(); + delete responses[i]; + } + + + CTDA.Unload(); + RNAM.Unload(); + ANAM.Unload(); + TWAT.Unload(); + ONAM.Unload(); + return 1; + } + + int32_t INFORecord::WriteRecord(FileWriter &writer) + { + WRITE(EDID); + WRITE(DATA); + WRITE(ENAM); + WRITE(PNAM); + WRITE(CNAM); + WRITE(TCLT); + WRITE(DNAM); + + for (uint32_t i = 0; i < responses.size(); ++i) { + + responses[i]->TRDT.Write(REV32(TRDT),writer); + responses[i]->NAM1.Write(REV32(NAM1), writer); + responses[i]->NAM2.Write(REV32(NAM2), writer); + responses[i]->NAM3.Write(REV32(NAM3), writer); + responses[i]->SNAM.Write(REV32(SNAM), writer); + responses[i]->LNAM.Write(REV32(LNAM), writer); + } + + WRITE(CTDA); + WRITE(RNAM); + WRITE(ANAM); + WRITE(TWAT); + WRITE(ONAM); + return -1; + } + + bool INFORecord::operator ==(const INFORecord &other) const + { + return (EDID.equalsi(other.EDID) && + DATA == other.DATA && + ENAM == other.ENAM && + PNAM == other.PNAM && + CNAM == other.CNAM && + TCLT == other.TCLT && + DNAM == other.DNAM && + responses == other.responses && + CTDA == other.CTDA && + RNAM == other.RNAM && + ANAM == other.ANAM && + TWAT == other.TWAT && + ONAM == other.ONAM + ); + } + + bool INFORecord::operator !=(const INFORecord &other) const + { + return !(*this == other); + } + + bool INFORecord::equals(Record *other) + { + return *this == *(INFORecord *)other; + } + +} \ No newline at end of file diff --git a/src/Skyrim/Records/INFORecord.h b/src/Skyrim/Records/INFORecord.h new file mode 100644 index 0000000..ff4ae91 --- /dev/null +++ b/src/Skyrim/Records/INFORecord.h @@ -0,0 +1,144 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is CBash code. +* +* The Initial Developer of the Original Code is +* Waruddar. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ +#pragma once +// BaseRecord.h +#include "../../Common.h" +#include "../../GenericRecord.h" +#include "../SkyrimChunks.h" +#include + +namespace Sk { + + struct INFOPACKDATA { + + uint16_t dialogueTab; + uint16_t flags; + float resetTime; + bool operator ==(const INFOPACKDATA &other) const { + return ( + this->dialogueTab == other.dialogueTab && + this->flags == other.flags && + this->resetTime == other.resetTime + ); + } + + bool operator !=(const INFOPACKDATA &other) const + { + return !(*this == other); + } + + ~INFOPACKDATA() {} + + }; + + struct PACKTRDT { + uint32_t emotionType; + uint32_t emotionValue; + uint32_t unk1AlwaysZero; + uint8_t responseNumber; + uint8_t junk[3]; + FORMID soundFile; + uint8_t useEmotionAnimation; + uint8_t junkTwo[3]; + + PACKTRDT() { + this->emotionType = 0; + this->emotionValue = 0; + this->unk1AlwaysZero = 0; + this->responseNumber = 0; + for (uint8_t i = 0; i <= 2; ++i) { junk[i] = 0; } + this->soundFile = 0; + this->useEmotionAnimation = false; + for (uint8_t i = 0; i <= 2; ++i) { junkTwo[i] = 0; } + + }; + ~PACKTRDT() {}; + + }; + + struct INFORecordResponse { + ReqSubRecord TRDT; + StringRecord NAM1; + StringRecord NAM2; + StringRecord NAM3; + OptSimpleSubRecord SNAM; + OptSimpleSubRecord LNAM; + }; + + class INFORecord : public TES5Record { + + public: + StringRecord EDID; //Editor ID + //VMAD + OptSubRecord DATA; + OptSimpleSubRecord ENAM; //Quest formid + OptSimpleSubRecord PNAM; + OptSimpleSubRecord CNAM; + OrderedSparseArray TCLT; //Array of formids to the following topics. + ReqSimpleSubRecord DNAM; //Dial reference + + std::vector responses; //Array of formids to the following topics. + OrderedSparseArray CTDA; //Conditions + + //SCHR + + OptSimpleSubRecord RNAM; + OptSimpleSubRecord ANAM; + OptSimpleSubRecord TWAT; + OptSimpleSubRecord ONAM; + + INFORecord(unsigned char *_recData = NULL); + INFORecord(INFORecord *srcRecord); + ~INFORecord(); + + uint32_t GetType(); + char * GetStrType(); + + bool VisitFormIDs(FormIDOp &op); + + int32_t ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk); + int32_t Unload(); + int32_t WriteRecord(FileWriter &writer); + + + bool operator ==(const INFORecord &other) const; + bool operator !=(const INFORecord &other) const; + bool equals(Record *other); + + }; + + +} \ No newline at end of file diff --git a/src/Skyrim/Records/PACKRecord.cpp b/src/Skyrim/Records/PACKRecord.cpp new file mode 100644 index 0000000..4274020 --- /dev/null +++ b/src/Skyrim/Records/PACKRecord.cpp @@ -0,0 +1,378 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is CBash code. + * + * The Initial Developer of the Original Code is + * Waruddar. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "..\..\Common.h" +#include "PACKRecord.h" +#include "../../Oblivion/Records/PACKRecord.h" + +namespace Sk +{ + +PACKRecord::PACKPKDT::PACKPKDT(): + flags(0), + packageType(0x12), + interruptOverride(0), + preferredSpeed(0), + unused1(0), + interruptFlags(0) + { + } + +PACKRecord::PACKPKDT::~PACKPKDT() + { + // + } + +PACKRecord::PACKPKCU::PACKPKCU(): +dataInputCount(0), +packageTemplate(0), +versionCounter(0) +{ + // +} + +PACKRecord::PACKPKCU::~PACKPKCU() +{ + // +} + + +bool PACKRecord::PACKPKDT::operator ==(const PACKPKDT &other) const + { + return (flags == other.flags && + packageType == other.packageType && + interruptOverride == other.interruptOverride && + interruptOverride == other.interruptOverride && + preferredSpeed == other.preferredSpeed && + interruptFlags == other.interruptFlags); + } + +bool PACKRecord::PACKPKDT::operator !=(const PACKPKDT &other) const + { + return !(*this == other); + } + +PACKRecord::PACKPLDT::PACKPLDT(): + locType(0), + locId(0), + locRadius(0) + { + // + } + +PACKRecord::PACKPLDT::~PACKPLDT() + { + // + } + +bool PACKRecord::PACKPLDT::operator ==(const PACKPLDT &other) const + { + return (locType == other.locType && + locId == other.locId && + locRadius == other.locRadius); + } + +bool PACKRecord::PACKPLDT::operator !=(const PACKPLDT &other) const + { + return !(*this == other); + } + +PACKRecord::PACKPSDT::PACKPSDT(): + month(0), + day(0), + date(0), + hour(0), + minute(0), + duration(0) + { + memset(&unused1[0], 0x00, sizeof(unused1)); + } + +PACKRecord::PACKPSDT::~PACKPSDT() + { + // + } + +bool PACKRecord::PACKPSDT::operator ==(const PACKPSDT &other) const + { + return (month == other.month && + day == other.day && + date == other.date && + hour == other.hour && + minute == other.minute && + duration == other.duration); + } + +bool PACKRecord::PACKPSDT::operator !=(const PACKPSDT &other) const + { + return !(*this == other); + } + +PACKRecord::PACKPTDA::PACKPTDA(): + targetType(0), + targetId(0), + targetCount(0) + { + // + } + +PACKRecord::PACKPTDA::~PACKPTDA() + { + // + } + +bool PACKRecord::PACKPTDA::operator ==(const PACKPTDA &other) const + { + return (targetType == other.targetType && + targetId == other.targetId && + targetCount == other.targetCount); + } + +bool PACKRecord::PACKPTDA::operator !=(const PACKPTDA &other) const + { + return !(*this == other); + } + +PACKRecord::PACKRecord(unsigned char *_recData): + TES5Record(_recData) + { + // + } + +PACKRecord::PACKRecord(PACKRecord *srcRecord): +TES5Record() + { + if(srcRecord == NULL) + return; + + flags = srcRecord->flags; + formID = srcRecord->formID; + flagsUnk = srcRecord->flagsUnk; + formVersion = srcRecord->formVersion; + versionControl2[0] = srcRecord->versionControl2[0]; + + + recData = srcRecord->recData; + if(!srcRecord->IsChanged()) + return; + + EDID = srcRecord->EDID; + CTDA = srcRecord->CTDA; + PKCU = srcRecord->PKCU; + PKDT = srcRecord->PKDT; + PSDT = srcRecord->PSDT; + TDAT = srcRecord->TDAT; + return; + } + +PACKRecord::~PACKRecord() + { + // + } + +bool PACKRecord::VisitFormIDs(FormIDOp &op) + { + + if(!IsLoaded()) + return false; + + op.Accept(PKCU.value.packageTemplate); + + for(uint32_t ListIndex = 0; ListIndex < CTDA.value.size(); ListIndex++) { + CTDA.value[ListIndex]->VisitFormIDs(op); + } + for(uint32_t ListIndex = 0; ListIndex < TDAT.ANAM.size(); ListIndex++) { + + if (TDAT.ANAM[ListIndex] == "Location") { + + if ((TDAT.cnamData[ListIndex].writtenPLDT.locId == 0x07) || (TDAT.cnamData[ListIndex].writtenPLDT.locId == 0x01000007) || (TDAT.cnamData[ListIndex].writtenPLDT.locId == 0x01000014)) { + TDAT.cnamData[ListIndex].writtenPLDT.locId = 0x14; + } + + op.Accept((TDAT.cnamData[ListIndex].writtenPLDT.locId)); + } + + if (TDAT.ANAM[ListIndex] == "SingleRef" || TDAT.ANAM[ListIndex] == "TargetSelector") { + + if ((TDAT.cnamData[ListIndex].writtenPTDA.targetId == 0x07) || (TDAT.cnamData[ListIndex].writtenPTDA.targetId == 0x01000007) || (TDAT.cnamData[ListIndex].writtenPTDA.targetId == 0x01000014)) { + TDAT.cnamData[ListIndex].writtenPTDA.targetId = 0x14; + } + + op.Accept((TDAT.cnamData[ListIndex].writtenPTDA.targetId)); + } + + } + + return op.Stop(); + } + +bool PACKRecord::isMustComplete() { return (PKDT.value.flags & fMustComplete) != 0; } +bool PACKRecord::isMaintainSpeedAtGoal() { return (PKDT.value.flags & fMaintainSpeedAtGoal) != 0; } +bool PACKRecord::isAtPackageStartUnlockDoors() { return (PKDT.value.flags & fAtPackageStartUnlockDoors) != 0; } +bool PACKRecord::isAtPackageChangeUnlockDoors() { return (PKDT.value.flags & fAtPackageChangeUnlockDoors) != 0; } +bool PACKRecord::isOncePerDay() { return (PKDT.value.flags & fOncePerDay) != 0; } +bool PACKRecord::isPreferredSpeed() { return (PKDT.value.flags & fPreferredSpeed) != 0; } +bool PACKRecord::isAlwaysSneak() { return (PKDT.value.flags & fAlwaysSneak) != 0; } +bool PACKRecord::isAllowSwimming() { return (PKDT.value.flags & fAllowSwimming) != 0; } +bool PACKRecord::isIgnoreCombat() { return (PKDT.value.flags & fIgnoreCombat) != 0; } +bool PACKRecord::isWeaponsUnequipped() { return (PKDT.value.flags & fWeaponsUnequipped) != 0; } +bool PACKRecord::isWeaponDrawn() { return (PKDT.value.flags & fWeaponDrawn) != 0; } +bool PACKRecord::isNoCombatAlert() { return (PKDT.value.flags & fNoCombatAlert) != 0; } +bool PACKRecord::isWearSleepOutfit() { return (PKDT.value.flags & fWearSleepOutfit) != 0; } +/* +bool PACKRecord::isHellosToPlayer() { return (PKDT.value.interruptFlags & PACKRecord::interrupt) != 0; } +bool PACKRecord::isRandomConversations() { return (PKDT.value.interruptFlags & fRandomConversations) != 0; } +bool PACKRecord::isObserveCombatBehavior() { return (PKDT.value.interruptFlags & fObserveCombatBehavior) != 0; } +bool PACKRecord::isGreetCorpseBehavior() { return (PKDT.value.interruptFlags & fGreetCorpseBehavior) != 0; } +bool PACKRecord::isReactionToPlayerActions() { return (PKDT.value.interruptFlags & fReactionToPlayerActions) != 0; } +bool PACKRecord::isFriendlyFireComments() { return (PKDT.value.interruptFlags & fFriendlyFireComments) != 0; } +bool PACKRecord::isAggroRadiusBehavior() { return (PKDT.value.interruptFlags & fAggroRadiusBehavior) != 0; } +bool PACKRecord::isAllowIdleChatter() { return (PKDT.value.interruptFlags & fAllowIdleChatter) != 0; } +bool PACKRecord::isWorldInteractions() { return (PKDT.value.interruptFlags & fWorldInteractions) != 0; } +*/ + +uint32_t PACKRecord::GetType() + { + return REV32(PACK); + } + +char* PACKRecord::GetStrType() + { + return "PACK"; + } + +int32_t PACKRecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk) + { + uint32_t subType = 0; + uint32_t subSize = 0; + while(buffer < end_buffer){ + subType = *(uint32_t *)buffer; + buffer += 4; + switch(subType) + { + case REV32(XXXX): + buffer += 2; + subSize = *(uint32_t *)buffer; + buffer += 4; + subType = *(uint32_t *)buffer; + buffer += 6; + break; + default: + subSize = *(uint16_t *)buffer; + buffer += 2; + break; + } + switch(subType) + { + case REV32(EDID): + EDID.Read(buffer, subSize, CompressedOnDisk); + break; + case REV32(PKDT): + PKDT.Read(buffer, subSize); + break; + case REV32(PSDT): + PSDT.Read(buffer, subSize); + break; + case REV32(CTDT): + case REV32(CTDA): + CTDA.Read(buffer, subSize); + break; + case REV32(ANAM): + TDAT.ReadANAM(buffer, subSize); + break; + case REV32(CNAM): + case REV32(PLDT): + case REV32(PTDA): + TDAT.ReadSelector(buffer, subSize); + case REV32(UNAM): + TDAT.ReadUNAM(buffer, subSize); + default: + //printer("FileName = %s\n", FileName); + printer(" PACK: %08X - Unknown subType = %04x\n", formID, subType); + CBASH_CHUNK_DEBUG + printer(" Size = %i\n", subSize); + printer(" CurPos = %04x\n\n", buffer - 6); + buffer = end_buffer; + break; + } + }; + return 0; + } + +int32_t PACKRecord::Unload() + { + IsChanged(false); + IsLoaded(false); + + EDID.Unload(); + PKDT.Unload(); + PSDT.Unload(); + CTDA.Unload(); + return 1; + } + +int32_t PACKRecord::WriteRecord(FileWriter &writer) + { + WRITE(EDID); + WRITE(PKDT); + WRITE(PSDT); + CTDA.Write(writer, true); + WRITE(PKCU); + TDAT.Write(writer); + + + return -1; + } + +bool PACKRecord::operator ==(const PACKRecord &other) const + { + return (EDID.equalsi(other.EDID) && + PKDT == other.PKDT && + PSDT == other.PSDT && + CTDA == other.CTDA); + } + +bool PACKRecord::operator !=(const PACKRecord &other) const + { + return !(*this == other); + } + +bool PACKRecord::equals(Record *other) + { + return *this == *(PACKRecord *)other; + } + + +} \ No newline at end of file diff --git a/src/Skyrim/Records/PACKRecord.h b/src/Skyrim/Records/PACKRecord.h new file mode 100644 index 0000000..b5e4f0a --- /dev/null +++ b/src/Skyrim/Records/PACKRecord.h @@ -0,0 +1,398 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is CBash code. + * + * The Initial Developer of the Original Code is + * Waruddar. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#pragma once +#include "..\..\Common.h" +#include "..\..\GenericRecord.h" +#include "..\..\Oblivion\Records\PACKRecord.h" +#include "..\SkyrimChunks.h" + +namespace Sk +{ + class PACKRecord : public TES5Record //Package + { + + + + public: + struct PACKPKCU //Template info + { + uint32_t dataInputCount; + uint32_t packageTemplate; + uint32_t versionCounter; + + PACKPKCU(); + ~PACKPKCU(); + + bool operator ==(const PACKPKCU &other) const; + bool operator !=(const PACKPKCU &other) const; + }; + + + struct PACKPTDA //Target + { + int32_t targetType; + FORMID_OR_UINT32 targetId; + int32_t targetCount; + + PACKPTDA(); + ~PACKPTDA(); + + bool operator ==(const PACKPTDA &other) const; + bool operator !=(const PACKPTDA &other) const; + }; + + struct PACKPLDT //Location + { + int32_t locType; + FORMID_OR_UINT32 locId; + int32_t locRadius; + + PACKPLDT(); + ~PACKPLDT(); + + bool operator ==(const PACKPLDT &other) const; + bool operator !=(const PACKPLDT &other) const; + }; + + + + struct PACKACTIVITY { + + bool writtenBool; + int writtenInt; + float writtenFloat; + PACKPLDT writtenPLDT; + PACKPTDA writtenPTDA; + + }; + + struct PACKTDAT //Template data.. + { + std::vector ANAM; + std::vector cnamData; + std::vector unamData; + + bool ReadANAM(unsigned char *&buffer, const uint32_t &subSize) { + char * name = new char[subSize + 1]; + name[subSize] = 0x00; + memcpy(name, buffer, subSize); + ANAM.push_back(name); + buffer += subSize; + return true; + } + + bool ReadUNAM(unsigned char *&buffer, const uint32_t &subSize) { + uint8_t data; + memcpy(&data, buffer, subSize); + unamData.push_back(data); + return true; + } + + bool ReadSelector(unsigned char *&buffer, const uint32_t &subSize) { + char * lastANAM = ANAM[ANAM.size() - 1]; + PACKACTIVITY p = PACKACTIVITY(); + + if (lastANAM == "Bool") { + assert(subSize == 1); + memcpy(&p.writtenBool, buffer, subSize); + } + + if (lastANAM == "Float") { + assert(subSize == 4); + memcpy(&p.writtenFloat, buffer, subSize); + } + + if (lastANAM == "Int") { + assert(subSize == 1); + memcpy(&p.writtenInt, buffer, subSize); + } + + if (lastANAM == "Location") { + memcpy(&p.writtenPLDT, buffer, subSize); + } + + if (lastANAM == "SingleRef") { + memcpy(&p.writtenPTDA, buffer, subSize); + } + + if (lastANAM == "ObjectList") { + memcpy(&p.writtenFloat, buffer, subSize); + } + + if (lastANAM == "TargetSelector") { + memcpy(&p.writtenPTDA, buffer, subSize); + } + + return true; + } + + + void Write(FileWriter &writer) { + +// assert(ANAM.size() == cnamData.size() == unamData.size()); + + for (uint32_t i = 0; i < ANAM.size(); ++i) { + int sizeString = 0; + char * stringData = ANAM[i]; + char * p = stringData; + while (*p != 0x00) { + ++sizeString; + ++p; + } + ++sizeString; + + writer.record_write_subheader(REV32(ANAM),sizeString); + writer.record_write(stringData, sizeString); + + if (stringData == "Bool") { + writer.record_write_subheader(REV32(CNAM), 1); + writer.record_write(&cnamData[i].writtenBool, 1); + } + + if (stringData == "Float") { + writer.record_write_subheader(REV32(CNAM), 4); + writer.record_write(&cnamData[i].writtenFloat, 4); + } + + if (stringData == "Int") { + writer.record_write_subheader(REV32(CNAM), 4); + writer.record_write(&cnamData[i].writtenInt, 4); + } + + if (stringData == "Location") { + int sizeData = sizeof(cnamData[i].writtenPLDT); + writer.record_write_subheader(REV32(PLDT), sizeData); + writer.record_write(&cnamData[i].writtenPLDT, sizeData); + } + + if (stringData == "SingleRef") { + int sizeData = sizeof(cnamData[i].writtenPTDA); + writer.record_write_subheader(REV32(PTDA), sizeData); + writer.record_write(&cnamData[i].writtenPTDA, sizeData); + } + + if (stringData == "ObjectList") { + writer.record_write_subheader(REV32(CNAM), 4); + writer.record_write(&cnamData[i].writtenFloat, 4); + } + + if (stringData == "TargetSelector") { + int sizeData = sizeof(cnamData[i].writtenPTDA); + writer.record_write_subheader(REV32(PTDA), sizeData); + writer.record_write(&cnamData[i].writtenPTDA, sizeData); + } + + } + + for (uint32_t i = 0; i < unamData.size(); ++i) { + + writer.record_write_subheader(REV32(UNAM), 1); + writer.record_write(&unamData[i], 1); + + } + + int xnamNumber = 10; + int emptyNumber = 0; + writer.record_write_subheader(REV32(XNAM), 1); + writer.record_write(&xnamNumber, 1); + + + writer.record_write_subheader(REV32(POBA), 0); + writer.record_write_subheader(REV32(INAM), 4); + writer.record_write(&emptyNumber, 4); + writer.record_write_subheader(REV32(PDTO), 8); + writer.record_write(&emptyNumber, 4); + writer.record_write(&emptyNumber, 4); + writer.record_write_subheader(REV32(POEA), 0); + writer.record_write_subheader(REV32(INAM), 4); + writer.record_write(&emptyNumber, 4); + writer.record_write_subheader(REV32(PDTO), 8); + writer.record_write(&emptyNumber, 4); + writer.record_write(&emptyNumber, 4); + writer.record_write_subheader(REV32(POCA), 0); + writer.record_write_subheader(REV32(INAM), 4); + writer.record_write(&emptyNumber, 4); + writer.record_write_subheader(REV32(PDTO), 8); + writer.record_write(&emptyNumber, 4); + writer.record_write(&emptyNumber, 4); + } + + }; + + struct PACKPKDT //General + { + uint32_t flags; + uint8_t packageType; + uint8_t interruptOverride; + uint8_t preferredSpeed; + uint8_t unused1; + uint32_t interruptFlags; + + PACKPKDT(); + ~PACKPKDT(); + + bool operator ==(const PACKPKDT &other) const; + bool operator !=(const PACKPKDT &other) const; + }; + + struct PACKPSDT //Schedule + { + int8_t month, day; + uint8_t date; + uint8_t hour, minute; + uint8_t unused1[3]; + int32_t duration; + + PACKPSDT(); + ~PACKPSDT(); + + bool operator ==(const PACKPSDT &other) const; + bool operator !=(const PACKPSDT &other) const; + }; + + enum interruptFlagsFlags + { + fHellosToPlayer = 0x01, + fRandomConversations = 0x02, + fObserveCombatBehavior = 0x04, + fGreetCorpseBehavior = 0x08, + fReactionToPlayerActions = 0x10, + fFriendlyFireComments = 0x20, + fAggroRadiusBehavior = 0x40, + fAllowIdleChatter = 0x80, + fWorldInteractions = 0x200 + }; + + enum flagsFlags + { + fMustComplete = 0x04, + fMaintainSpeedAtGoal = 0x08, + fAtPackageStartUnlockDoors = 0x40, + fAtPackageChangeUnlockDoors = 0x80, + fOncePerDay = 0x400, + fPreferredSpeed = 0x2000, + fAlwaysSneak = 0x20000, + fAllowSwimming = 0x40000, + fIgnoreCombat = 0x100000, + fWeaponsUnequipped = 0x200000, + fWeaponDrawn = 0x800000, + fNoCombatAlert = 0x8000000, + fWearSleepOutfit = 0x20000000 + }; + + + + enum preferredSpeedTypes + { + tWalk = 0, + tJog = 1, + tRun = 2, + tFastWalk = 3 + }; + + enum locTypeType + { + eLocNearReference = 0, + eLocInCell = 1, + eLocNearCurrentLocation = 2, + eLocNearEditorLocation = 3, + eLocObjectID = 4, + eLocObjectType = 5 + }; + + enum targetTypeType + { + eTargetReference = 0, + eTargetObjectID = 1, + eTargetObjectType = 2 + }; + + public: + StringRecord EDID; //Editor ID + //TODO ADD VMAD + + OrderedSparseArray CTDA; //Conditions + + ReqSubRecord PKCU; //Template Info + ReqSubRecord PKDT; //General + ReqSubRecord PSDT; //Schedule + PACKTDAT TDAT; //Template data. + + PACKRecord(unsigned char *_recData=NULL); + PACKRecord(PACKRecord *srcRecord); + ~PACKRecord(); + + bool VisitFormIDs(FormIDOp &op); + + bool PACKRecord::isMustComplete(); + bool PACKRecord::isMaintainSpeedAtGoal(); + bool PACKRecord::isAtPackageStartUnlockDoors(); + bool PACKRecord::isAtPackageChangeUnlockDoors(); + bool PACKRecord::isOncePerDay(); + bool PACKRecord::isPreferredSpeed(); + bool PACKRecord::isAlwaysSneak(); + bool PACKRecord::isAllowSwimming(); + bool PACKRecord::isIgnoreCombat(); + bool PACKRecord::isWeaponsUnequipped(); + bool PACKRecord::isWeaponDrawn(); + bool PACKRecord::isNoCombatAlert(); + bool PACKRecord::isWearSleepOutfit(); + void PACKRecord::addLocationTemplateSetting(PACKRecord::PACKPLDT location, int unamRecordIndex); + void PACKRecord::addBoolTemplateSetting(bool setting, int unamRecordIndex); + void PACKRecord::addIntTemplateSetting(int setting, int unamRecordIndex); + void PACKRecord::addFloatTemplateSetting(float setting, int unamRecordIndex); + void PACKRecord::addTargetTemplateSetting(char * name, PACKRecord::PACKPTDA target, int unamRecordIndex); + void PACKRecord::addObjectListTemplateSetting(float setting, int unamRecordIndex); + + + //uint32_t GetFieldAttribute(DEFAULTED_FIELD_IDENTIFIERS, uint32_t WhichAttribute=0); + //void * GetField(DEFAULTED_FIELD_IDENTIFIERS, void **FieldValues=NULL); + //bool SetField(DEFAULTED_FIELD_IDENTIFIERS, void *FieldValue=NULL, uint32_t ArraySize=0); + //void DeleteField(DEFAULTED_FIELD_IDENTIFIERS); + + uint32_t GetType(); + char * GetStrType(); + + int32_t ParseRecord(unsigned char *buffer, unsigned char *end_buffer, bool CompressedOnDisk=false); + int32_t Unload(); + int32_t WriteRecord(FileWriter &writer); + + bool operator ==(const PACKRecord &other) const; + bool operator !=(const PACKRecord &other) const; + bool equals(Record *other); + + }; +} \ No newline at end of file diff --git a/src/Skyrim/Records/WRLDRecord.cpp b/src/Skyrim/Records/WRLDRecord.cpp index 3c3d744..6b58ba9 100644 --- a/src/Skyrim/Records/WRLDRecord.cpp +++ b/src/Skyrim/Records/WRLDRecord.cpp @@ -61,6 +61,7 @@ WRLDRecord::WRLDRecord(WRLDRecord *srcRecord): NAM2 = srcRecord->NAM2; NAM3 = srcRecord->NAM3; NAM4 = srcRecord->NAM4; + MODL = srcRecord->MODL; DNAM = srcRecord->DNAM; ICON = srcRecord->ICON; MICO = srcRecord->MICO; @@ -105,6 +106,10 @@ bool WRLDRecord::VisitFormIDs(FormIDOp &op) op.Accept(CNAM.value); op.Accept(NAM2.value); op.Accept(NAM3.value); + + if (MODL.IsLoaded()) + MODL->Textures.VisitFormIDs(op); + if(INAM.IsLoaded()) op.Accept(INAM.value); if(ZNAM.IsLoaded()) @@ -418,6 +423,18 @@ int32_t WRLDRecord::ParseRecord(unsigned char *buffer, unsigned char *end_buffer case REV32(UNAM): // 53 bytes, Data\Textures\Landscape\Mountains\MountainSlab02_N.dds UNAM.Read(buffer, subSize, CompressedOnDisk); break; + case REV32(MODL): + MODL.Load(); + MODL->MODL.Read(buffer, subSize, CompressedOnDisk); + break; + case REV32(MODT): + MODL.Load(); + MODL->MODT.Read(buffer, subSize, CompressedOnDisk); + break; + case REV32(MODS): + MODL.Load(); + MODL->Textures.Read(buffer, subSize); + break; default: //printer("FileName = %s\n", FileName); printer(" WRLD: %08X - Unknown subType = %04x [%c%c%c%c]\n", formID, subType, (subType >> 0) & 0xFF, (subType >> 8) & 0xFF, (subType >> 16) & 0xFF, (subType >> 24) & 0xFF); @@ -444,6 +461,7 @@ int32_t WRLDRecord::Unload() NAM2.Unload(); NAM3.Unload(); NAM4.Unload(); + MODL.Unload(); DNAM.Unload(); ICON.Unload(); MICO.Unload(); @@ -477,6 +495,7 @@ int32_t WRLDRecord::WriteRecord(FileWriter &writer) WRITE(NAM2); WRITE(NAM3); WRITE(NAM4); + MODL.Write(writer); WRITE(DNAM); WRITE(ICON); WRITE(MICO); @@ -510,6 +529,7 @@ bool WRLDRecord::operator ==(const WRLDRecord &other) const NAM3 == other.NAM3 && NAM4 == other.NAM4 && DNAM == other.DNAM && + MODL == other.MODL && MNAM == other.MNAM && ONAM == other.ONAM && INAM == other.INAM && diff --git a/src/Skyrim/Records/WRLDRecord.h b/src/Skyrim/Records/WRLDRecord.h index 85724c9..b18682f 100644 --- a/src/Skyrim/Records/WRLDRecord.h +++ b/src/Skyrim/Records/WRLDRecord.h @@ -91,6 +91,7 @@ class WRLDRecord : public TES5Record //Worldspace RawRecord OFST; //Unknown RawRecord RNAM; //Unknown (Skyrim) RawRecord NAMA; //Unknown (Skyrim) + OptSubRecord MODL; // Model StringRecord TNAM; //Texture Filename (Skyrim) StringRecord UNAM; //Normal Texture Filename (Skyrim) diff --git a/src/Skyrim/SkyrimChunks.cpp b/src/Skyrim/SkyrimChunks.cpp index 94e2896..4a86c63 100644 --- a/src/Skyrim/SkyrimChunks.cpp +++ b/src/Skyrim/SkyrimChunks.cpp @@ -237,7 +237,7 @@ bool SKCTDA::VisitFormIDs(FormIDOp &op) if (IsUseGlobal()) op.Accept(compValue); - if (curCTDAFunction != Function_Arguments.end()) + if (curCTDAFunction != SKFunction_Arguments.end()) { const FunctionArguments &CTDAFunction = curCTDAFunction->second; if (CTDAFunction.first == eFORMID) diff --git a/src/Skyrim/SkyrimCommon.cpp b/src/Skyrim/SkyrimCommon.cpp index 4be398b..3fac4ad 100644 --- a/src/Skyrim/SkyrimCommon.cpp +++ b/src/Skyrim/SkyrimCommon.cpp @@ -96,7 +96,8 @@ bool StringLookups::Open(char * ModName) delete [] StringsFileName; delete [] DLStringsFileName; delete [] ILStringsFileName; - throw; + return false; + //throw; } delete [] StringsFileName; diff --git a/src/Skyrim/TES5File.cpp b/src/Skyrim/TES5File.cpp index 1ed9c25..de255d3 100644 --- a/src/Skyrim/TES5File.cpp +++ b/src/Skyrim/TES5File.cpp @@ -382,12 +382,12 @@ int32_t TES5File::Load(RecordOp &read_parser, RecordOp &indexer, std::vectorINFO.push_back(DIAL.info_pool.construct(SourceRecord, ParentRecord, false)); return ((Sk::DIALRecord *)ParentRecord)->INFO.back(); + /* case REV32(ACHR): if(ParentRecord == NULL || ParentRecord->GetType() != REV32(CELL)) { @@ -1437,8 +1442,10 @@ Record * TES5File::CreateRecord(const uint32_t &RecordType, char * const &Record return QUST.pool.construct(SourceRecord, this, true); case REV32(IDLE): return IDLE.pool.construct(SourceRecord, this, true); + */ case REV32(PACK): return PACK.pool.construct(SourceRecord, this, true); + /* case REV32(CSTY): return CSTY.pool.construct(SourceRecord, this, true); case REV32(LSCR): @@ -1780,6 +1787,7 @@ int32_t TES5File::DeleteRecord(Record *&curRecord, RecordOp &deindexer) deindexer.Accept(curRecord); DEBR.pool.destroy(curRecord); return 1; + */ case REV32(DIAL): { Sk::DIALRecord *dial_record = (Sk::DIALRecord *)curRecord; @@ -1797,7 +1805,8 @@ int32_t TES5File::DeleteRecord(Record *&curRecord, RecordOp &deindexer) deindexer.Accept(curRecord); DLBR.pool.destroy(curRecord); return 1; - case REV32(DLVW): + /* + case REV32(DLVW): deindexer.Accept(curRecord); DLVW.pool.destroy(curRecord); return 1; @@ -1895,6 +1904,7 @@ int32_t TES5File::DeleteRecord(Record *&curRecord, RecordOp &deindexer) deindexer.Accept(curRecord); IMGS.pool.destroy(curRecord); return 1; + */ case REV32(INFO): { Sk::DIALRecord *dial_record = (Sk::DIALRecord *)curRecord->GetParentRecord(); @@ -1918,6 +1928,7 @@ int32_t TES5File::DeleteRecord(Record *&curRecord, RecordOp &deindexer) DIAL.info_pool.destroy(curRecord); } return 1; + /* case REV32(INGR): deindexer.Accept(curRecord); INGR.pool.destroy(curRecord); @@ -2068,11 +2079,11 @@ int32_t TES5File::DeleteRecord(Record *&curRecord, RecordOp &deindexer) deindexer.Accept(curRecord); OTFT.pool.destroy(curRecord); return 1; - /* case REV32(PACK): deindexer.Accept(curRecord); PACK.pool.destroy(curRecord); return 1; + /* case REV32(PERK): deindexer.Accept(curRecord); PERK.pool.destroy(curRecord); @@ -2430,10 +2441,10 @@ int32_t TES5File::Save(char * const &SaveName, std::vector &Ex // formCount += NAVI.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); formCount += CELL.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); formCount += WRLD.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod, FormIDHandler, CELL, indexer); - // formCount += DIAL.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); + formCount += DIAL.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += QUST.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += IDLE.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); - // formCount += PACK.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); + formCount += PACK.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += CSTY.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += LSCR.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); formCount += LVSP.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); @@ -2468,7 +2479,7 @@ int32_t TES5File::Save(char * const &SaveName, std::vector &Ex // formCount += SMBN.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += SMQN.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += SMEN.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); - // formCount += DLBR.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); + formCount += DLBR.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += MUST.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); // formCount += DLVW.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); formCount += WOOP.Write(writer, Expanders, expander, collapser, bMastersChanged, CloseMod); @@ -2548,10 +2559,10 @@ void TES5File::VisitAllRecords(RecordOp &op) // DEBR.pool.VisitRecords(op); // DIAL { - // DIAL.info_pool.VisitRecords(op); - // DIAL.dial_pool.VisitRecords(op); + DIAL.info_pool.VisitRecords(op); + DIAL.dial_pool.VisitRecords(op); } - // DLBR.pool.VisitRecords(op); + DLBR.pool.VisitRecords(op); // DLVW.pool.VisitRecords(op); // DOBJ.pool.VisitRecords(op); // DOOR.pool.VisitRecords(op); @@ -2605,7 +2616,7 @@ void TES5File::VisitAllRecords(RecordOp &op) // NAVM - in CELL // NPC_.pool.VisitRecords(op); OTFT.pool.VisitRecords(op); - // PACK.pool.VisitRecords(op); + PACK.pool.VisitRecords(op); // PERK.pool.VisitRecords(op); // PGRE - in CELL // PHZD.pool.VisitRecords(op); // in CELL? @@ -2754,10 +2765,10 @@ void TES5File::VisitRecords(const uint32_t &RecordType, RecordOp &op) case REV32(DEBR): // DEBR.pool.VisitRecords(op);break; case REV32(DIAL): - // DIAL.dial_pool.VisitRecords(op); + DIAL.dial_pool.VisitRecords(op); break; case REV32(DLBR): - // DLBR.pool.VisitRecords(op); + DLBR.pool.VisitRecords(op); break; case REV32(DLVW): // DLVW.pool.VisitRecords(op); @@ -2832,7 +2843,7 @@ void TES5File::VisitRecords(const uint32_t &RecordType, RecordOp &op) // IMGS.pool.VisitRecords(op); break; case REV32(INFO): - // DIAL.info_pool.VisitRecords(op); + DIAL.info_pool.VisitRecords(op); break; case REV32(INGR): // INGR.pool.VisitRecords(op); @@ -2919,7 +2930,7 @@ void TES5File::VisitRecords(const uint32_t &RecordType, RecordOp &op) OTFT.pool.VisitRecords(op); break; case REV32(PACK): - // PACK.pool.VisitRecords(op); + PACK.pool.VisitRecords(op); break; case REV32(PERK): // PERK.pool.VisitRecords(op); diff --git a/src/Skyrim/TES5File.h b/src/Skyrim/TES5File.h index 058f842..3810059 100644 --- a/src/Skyrim/TES5File.h +++ b/src/Skyrim/TES5File.h @@ -68,8 +68,8 @@ // #include "Records/CPTHRecord.h" // #include "Records/CSTYRecord.h" // #include "Records/DEBRRecord.h" -// #include "Records/DIALRecord.h" -// #include "Records/DLBRRecord.h" +#include "Records/DIALRecord.h" +#include "Records/DLBRRecord.h" // #include "Records/DLVWRecord.h" // #include "Records/DOBJRecord.h" // #include "Records/DOORRecord.h" @@ -122,7 +122,7 @@ // #include "Records/NAVIRecord.h" // #include "Records/NPC_Record.h" #include "Records/OTFTRecord.h" -// #include "Records/PACKRecord.h" +#include "Records/PACKRecord.h" // #include "Records/PERKRecord.h" // #include "Records/PROJRecord.h" // #include "Records/PWATRecord.h" // Empty GRUP @@ -197,8 +197,8 @@ class TES5File : public ModFile // GRUP(CPTH); // GRUP(CSTY); // GRUP(DEBR); - // GRUP(DIAL); - // GRUP(DLBR); + GRUP(DIAL); + GRUP(DLBR); // GRUP(DLVW); // GRUP(DOBJ); // GRUP(DOOR); @@ -251,7 +251,7 @@ class TES5File : public ModFile // GRUP(NAVI); // GRUP(NPC_); GRUP(OTFT); - // GRUP(PACK); + GRUP(PACK); // GRUP(PERK); // GRUP(PROJ); // GRUP(PWAT); // Empty GRUP