From e5a64eeb5ecf4e4c707fb753f9644dbe1f1f3ea8 Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Thu, 25 Feb 2010 19:01:24 +0100 Subject: [PATCH] Fixed NPC_, LEVI and LEVC. Only DIAL and INFO left. --- esm/loadlevlist.hpp | 79 +++++++++++++ esm/loadnpc.hpp | 137 +++++++++++++++++++++ esm/records.hpp | 2 + old_d_version/esm/loadlevlist.d | 177 ---------------------------- old_d_version/esm/loadnpc.d | 203 -------------------------------- 5 files changed, 218 insertions(+), 380 deletions(-) create mode 100644 esm/loadlevlist.hpp create mode 100644 esm/loadnpc.hpp delete mode 100644 old_d_version/esm/loadlevlist.d delete mode 100644 old_d_version/esm/loadnpc.d diff --git a/esm/loadlevlist.hpp b/esm/loadlevlist.hpp new file mode 100644 index 000000000..046fd91ef --- /dev/null +++ b/esm/loadlevlist.hpp @@ -0,0 +1,79 @@ +#ifndef _ESM_LEVLISTS_H +#define _ESM_LEVLISTS_H + +#include "esm_reader.hpp" + +namespace ESM { + +/* + * Leveled lists. Since these have identical layout, I only bothered + * to implement it once. + * + * We should later implement the ability to merge leveled lists from + * several files. + */ + +struct LeveledListBase +{ + enum Flags + { + AllLevels = 0x01, // Calculate from all levels <= player + // level, not just the closest below + // player. + Each = 0x02 // Select a new item each time this + // list is instantiated, instead of + // giving several identical items + }; // (used when a container has more + // than one instance of one leveled + // list.) + int flags; + unsigned char chanceNone; // Chance that none are selected (0-255?) + + // Record name used to read references. Must be set before load() is + // called. + const char *recName; + + struct LevelItem + { + std::string id; + short level; + }; + + std::vector list; + + void load(ESMReader &esm) + { + esm.getHNT(flags, "DATA"); + esm.getHNT(chanceNone, "NNAM"); + + if(esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + list.resize(len); + } + else return; + + // TODO: Merge with an existing lists here. This can be done + // simply by adding the lists together, making sure that they are + // sorted by level. A better way might be to exclude repeated + // items. Also, some times we don't want to merge lists, just + // overwrite. Figure out a way to give the user this option. + + for(int i=0; i - WWW: http://openmw.snaptoad.com/ - - This file (loadlevlist.d) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -module esm.loadlevlist; -import esm.imports; -import esm.loadcrea; - -import monster.modules.random : randInt; - -/* - * Leveled lists. Since these have identical layout, I only bothered - * to implement it once. - * - * We should later implement the ability to merge leveled lists from - * several files. - * - */ - -// Moved here for template / DMD bug reasons... -struct _ListItem -{ - Item item; // Definded in records.d - short level; -} - -struct LeveledListT(bool creature) -{ - char[] id; - LoadState state; - - enum Flags - { - AllLevels = 0x01, // Calculate from all levels <= player - // level, not just the closest below - // player. - Each = 0x02 // Select a new item each time this - // list is instantiated, instead of - // giving several identical items - } // (used when a container has more - // than one instance of one leveled - // list.) - - alias _ListItem ListItem; - - Flags flags; - ubyte chanceNone; // Chance that none are selected (0-255??) - ListItem list[]; - - // Get a random creature from this list - Creature* instCreature(short PCLevel) - in - { - assert(creature); - } - body - { - int index = instIndex(PCLevel); - if(index == -1) return null; // No creature was selected - - Creature *c = cast(Creature*)list[index].item.getPtr(ItemType.Creature); - assert(c != null); - return c; - } - - // Get a random item from the list - Item *instItem(short PCLevel) - in - { - assert(!creature); - } - body - { - int index = instIndex(PCLevel); - if(index == -1) return null; - - return &list[index].item; - } - - // Get a random index in the right range - int instIndex(short PCLevel) - { - int top, bottom, i; - - // TODO: Find out if this is indeed correct. - // Test if no creature is to be selected - if(randInt(0, 255) < chanceNone) return -1; - - // Find the highest item below or equal to the Player level - for(i=list.length-1; i>=0; i--) - if(list[i].level <= PCLevel) break; - top = i; - - // Select none if the player level is too low - if(top < 0) return -1; - - // Now find the lowest element to select - if(flags & Flags.AllLevels) bottom = 0; - else - { - // Find the lowest index i such that item[i] has the same - // level as item[top]. - do { i--; } - while(i>=0 && list[i].level == list[top].level); - - bottom = i+1; - } - - // Select a random item - return randInt(bottom, top); - } - - void load() - {with(esFile){ - flags = cast(Flags)getHNUint("DATA"); - chanceNone = cast(ubyte) getHNByte("NNAM"); - - if(hasMoreSubs()) - list = getRegion().allocateT!(ListItem)(getHNInt("INDX")); - else list = null; - - // TODO: Merge the lists here. This can be done simply by adding - // the lists together, making sure that they are sorted by - // level. A better way might be to exclude repeated items. Also, - // some times we don't want to merge lists, just overwrite. Figure - // out a way to give the user this option. - - foreach(ref ListItem l; list) - { - static if(creature) - { - getSubNameIs("CNAM"); - l.item = actors.lookup(tmpHString()); - } - else - { - getSubNameIs("INAM"); - - // Morrowind.esm actually contains an invalid reference, - // to "imperial cuirass" in the list - // "random_imp_armor". We just ignore it to avoid - // irritating warning messages. - char[] tmp = tmpHString(); - if( (tmp != "imperial cuirass") || (id != "random_imp_armor") - || (getSpecial() != SpecialFile.Morrowind) ) - l.item = items.lookup(tmp); - //l.item = items.lookup(tmpHString()); - } - l.level = getHNShort("INTV"); - } - }} -} - -alias LeveledListT!(false) LeveledItems; -alias LeveledListT!(true) LeveledCreatures; - -ListID!(LeveledCreatures) creatureLists; -ListID!(LeveledItems) itemLists; diff --git a/old_d_version/esm/loadnpc.d b/old_d_version/esm/loadnpc.d deleted file mode 100644 index 59d2ff7b6..000000000 --- a/old_d_version/esm/loadnpc.d +++ /dev/null @@ -1,203 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (loadnpc.d) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -module esm.loadnpc; - -import esm.imports; - -import esm.loadcont; -import esm.loadrace; -import esm.loadclas; -import esm.loadfact; -import esm.loadbody; - -/* - * NPC definition - */ - -struct NPC -{ - // Services - enum Services : int - { - // Buys - Weapon = 0x00001, - Armor = 0x00002, - Clothing = 0x00004, - Books = 0x00008, - Ingredients = 0x00010, - Picks = 0x00020, - Probes = 0x00040, - Lights = 0x00080, - Apparatus = 0x00100, - RepairItem = 0x00200, - Misc = 0x00400, - - // Services - Spells = 0x00800, - MagicItems = 0x01000, - Potions = 0x02000, - Training = 0x04000, // What skills? - Spellmaking = 0x08000, - Enchanting = 0x10000, - Repair = 0x20000 - } - - enum Flags - { - Female = 0x0001, - Essential = 0x0002, - Respawn = 0x0004, - Autocalc = 0x0008, - Skeleton = 0x0400, // Skeleton blood effect (white) - Metal = 0x0800 // Metal blood effect (golden?) - } - - align(1) struct NPDTstruct52 - { - short level; - byte strength, intelligence, willpower, agility, - speed, endurance, personality, luck; - byte skills[27]; - short health, mana, fatigue; - byte disposition; - byte reputation; // Was "factionID", but that makes no sense. - byte rank, unknown, u2; - int gold; - } - align(1) struct NPDTstruct12 - { - short level; - byte disposition, reputation, rank, - unknown1, unknown2, unknown3; - int gold; // ?? Not sure - } - - align(1) struct AIDTstruct - { - // These are probabilities - byte hello, u1, fight, flee, alarm, u2, u3, u4; - // The u's might be the skills that this NPC can train you in - Services services; - - static assert(AIDTstruct.sizeof == 12); - } - - static assert(NPDTstruct52.sizeof==52); - static assert(NPDTstruct12.sizeof==12); - - union - { - NPDTstruct52 npdt52; - NPDTstruct12 npdt12; // Use this if npdt52.gold == -10 - } - - Flags flags; - - InventoryList inventory; - SpellList spells; - - AIDTstruct AI; - bool hasAI; - - mixin LoadT; - - MeshIndex model; - Race* race; - Class* cls; - Faction* faction; - Script* script; - BodyPart* hair, head; - - void load() - {with(esFile){ - npdt52.gold = -10; - - model = getOMesh(); - name = getHNOString("FNAM"); - - race = getHNPtr!(Race)("RNAM", races); - cls = getHNPtr!(Class)("CNAM", classes); - faction = getHNPtr!(Faction)("ANAM", factions); - head = getHNPtr!(BodyPart)("BNAM", bodyParts); - hair = getHNPtr!(BodyPart)("KNAM", bodyParts); - - script = getHNOPtr!(Script)("SCRI", scripts); - - getSubNameIs("NPDT"); - getSubHeader(); - if(getSubSize() == 52) readExact(&npdt52, npdt52.sizeof); - else if(getSubSize() == 12) readExact(&npdt12, npdt12.sizeof); - else fail("NPC_NPDT must be 12 or 52 bytes long"); - - flags = cast(Flags) getHNInt("FLAG"); - - inventory.load(); - spells.load(); - - if(isNextSub("AIDT")) - { - readHExact(&AI, AI.sizeof); - hasAI = true; - } - else hasAI = false; - - skipRecord(); - - makeProto(); - - // Clean this up a little later, eg. no point in storing the - // structs outside the function any longer. Same goes for most of - // the load*.d structures. - if(npdt52.gold == -10) - { - proto.setInt("level", npdt12.level); - proto.setInt("gold", npdt12.gold); - - proto.setInt("disposition", npdt12.disposition); - proto.setInt("reputation", npdt12.reputation); - proto.setInt("rank", npdt12.rank); - - // TODO: Autocalculate the rest? - } - else - { - proto.setInt("level", npdt52.level); - proto.setInt("gold", npdt52.gold); - - proto.setInt("baseStrength", npdt52.strength); - proto.setInt("baseIntelligence", npdt52.intelligence); - proto.setInt("baseWillpower", npdt52.willpower); - proto.setInt("baseAgility", npdt52.agility); - proto.setInt("baseSpeed", npdt52.speed); - proto.setInt("baseEndurance", npdt52.endurance); - proto.setInt("basePersonality", npdt52.personality); - proto.setInt("baseLuck", npdt52.luck); - - proto.setInt("baseMaxHealth", npdt52.health); - proto.setInt("baseMaxMana", npdt52.mana); - proto.setInt("baseMaxFatigue", npdt52.fatigue); - } - }} -} -ListID!(NPC) npcs;