You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/old_d_version/esmtool.d

378 lines
11 KiB
D

/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (esmtool.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 esmtool;
import std.stdio;
import core.memory;
import esm.esmmain;
import monster.util.string;
import mscripts.setup;
import std.gc;
import gcstats;
// Not used, but we have to link it in along with the C++ stuff.
import input.events;
void poolSize()
{
GCStats gc;
getStats(gc);
writefln("Pool size: ", comma(gc.poolsize));
writefln("Used size: ", comma(gc.usedsize));
}
//alias int[Dialogue*] TopicList;
void main(char[][] args)
{
char[][] files;
bool raw;
bool scptList; // List scripts
bool scptShow; // Show a script
char[] scptName; // Script to show
bool ciList; // List interior cells
bool ceList; // List exterior cells that have names
bool weList; // List weapons
bool gmst; // List game settings
bool numbers; // List how many there are of each record type
foreach(char[] a; args[1..$])
if(a == "-r") raw = true;
else if(a == "-sl") scptList = true;
else if(a == "-s") scptShow = true;
else if(scptShow && scptName == "") scptName = a;
else if(a == "-g") gmst = true;
else if(a == "-cil") ciList = true;
else if(a == "-cel") ceList = true;
else if(a == "-wl") weList = true;
else if(a == "-n") numbers = true;
else if(a.begins("-")) writefln("Ignoring unknown option %s", a);
else files ~= a;
int help(char[] msg)
{
writefln("%s", msg);
writefln("Syntax: %s [options] esm-file [esm-file ... ]", args[0]);
writefln(" Options:");
writefln(" -r Display all records in raw format");
writefln(" -n List the number of each record type");
writefln(" -sl List scripts");
writefln(" -g List game settings (GMST)");
writefln(" -s name Show given script");
writefln(" -cil List interior cells");
writefln(" -cel List exterior cells with names");
writefln(" -wl List weapons");
return 1;
}
if(files.length == 0) return help("No input files given");
if(scptShow && scptName == "") return help("No script name given");
initializeMemoryRegions();
initMonsterScripts();
if(raw)
{
foreach(int fileNum, char[] filename; files)
{
try
{
esFile.open(filename, esmRegion);
printRaw();
}
catch(Exception e)
{
try {writefln(e);}
catch {}
writefln("Error on file %s", filename);
}
catch
{
writefln("Error: Unkown failure on file %s", filename);
}
}
return;
}
// Disable resource lookups.
resources.dummy = true;
try loadTESFiles(files);
catch(Exception e)
{
writefln(e);
}
catch { writefln("Error: Unkown failure"); }
// List weapons
if(weList) foreach(n, m; weapons.names)
{
alias Weapon.Type WT;
switch(m.data.type)
{
case WT.ShortBladeOneHand: writef("Short Sword"); break;
case WT.LongBladeOneHand: writef("Long Sword, One-Handed"); break;
case WT.LongBladeTwoHand: writef("Long Sword, Two-Handed"); break;
case WT.BluntOneHand: writef("Blunt, One-Handed"); break;
case WT.BluntTwoClose: writef("Blunt, Two-Handed"); break;
case WT.BluntTwoWide: writef("Blunt, Two-Handed Wide"); break;
case WT.SpearTwoWide: writef("Spear, Two-Handed"); break;
case WT.AxeOneHand: writef("Axe, One-Handed"); break;
case WT.AxeTwoHand: writef("Axe, Two-Handed"); break;
case WT.MarksmanBow: writef("Bow"); break;
case WT.MarksmanCrossbow: writef("Crossbow"); break;
case WT.MarksmanThrown: writef("Thrown weapon"); break;
case WT.Arrow: writef("Arrow"); break;
case WT.Bolt: writef("Bolt"); break;
default: assert(0);
}
writefln(" id '%s': name '%s'", n, m.name);
if(m.data.flags & Weapon.Flags.Magical)
writefln("Magical");
if(m.data.flags & Weapon.Flags.Silver)
writefln("Silver");
writefln("Weight: ", m.data.weight);
writefln("Value: ", m.data.value);
writefln("Health: ", m.data.health);
writefln("Speed: ", m.data.speed);
writefln("Reach: ", m.data.reach);
writefln("Enchantment points: ", m.data.enchant);
writefln("Combat: ", m.data.chop, m.data.slash, m.data.thrust);
if(m.enchant) writefln("Has enchantment '%s'", m.enchant.id);
if(m.script) writefln("Has script '%s'", m.script.id);
writefln();
}
if(numbers)
{
writefln("Activators: ", activators.length);
writefln("Doors: ", doors.length);
writefln("Globals: ", globals.length);
writefln("Sounds: ", sounds.length);
writefln("Game Settings: ", gameSettings.length);
writefln("Factions: ", factions.length);
writefln("Statics: ", statics.length);
writefln("Spells: ", spells.length);
writefln("Potions: ", potions.length);
writefln("Apparatus: ", appas.length);
writefln("Armors: ", armors.length);
writefln("Body parts: ", bodyParts.length);
writefln("Enchantments: ", enchants.length);
writefln("Books: ", books.length);
writefln("Birth signs: ", birthSigns.length);
writefln("Land texture files: ", landTextures.length);
writefln("Weapons: ", weapons.length);
writefln("Lockpicks: ", lockpicks.length);
writefln("Probes: ", probes.length);
writefln("Repairs: ", repairs.length);
writefln("Cells: ", cells.length);
writefln(" Interior: ", cells.numInt);
writefln(" Exterior: ", cells.numExt);
writefln("Regions: ", regions.length);
writefln("Lights: ", lights.length);
writefln("Skills: ", skills.length);
writefln("Sound generators: ", soundGens.length);
writefln("Races: ", races.length);
writefln("Misc items: ", miscItems.length);
writefln("Cloths: ", clothes.length);
writefln("Ingredients: ", ingreds.length);
writefln("Classes: ", classes.length);
writefln("Containers: ", containers.length);
writefln("Creatures: ", creatures.length);
writefln("Leveled item lists: ", itemLists.length);
writefln("Leveled creature lists: ", creatureLists.length);
writefln("NPCs: ", npcs.length);
writefln("Scripts: ", scripts.length);
writefln("Dialogues: ", dialogues.length);
writefln("Hyperlinks: ", hyperlinks.list.length);
writefln("Start scripts: ", startScripts.length);
writefln("\nTotal items: ", items.length);
writefln("Total actors: ", actors.length);
writefln("Total cell placable items: ", cellRefs.length);
}
if(gmst)
{
foreach(a, b; gameSettings.names)
{
writef(a, " (");
if(b.type == VarType.Int) writefln("int) = ", b.i);
else if(b.type == VarType.Float) writefln("float) = ", b.f);
else if(b.type == VarType.String) writefln("string) = '%s'", b.str);
else writefln("no value)", cast(int)b.type);
}
}
if(scptList) foreach(a, b; scripts.names) writefln(a);
if(ciList)
foreach(a, b; cells.in_cells)
writefln(a);
if(ceList)
foreach(uint i, c; .cells.ex_cells)
{
int x, y;
CellList.decompound(i, x, y);
if(c.name.length)
writefln("%s,%s: %s", x, y, c.name);
}
if(scptShow)
{
Script *p = scripts.names.lookup(scptName);
if(p)
writefln("Script '%s', text is:\n-------\n%s\n-------", p.id, p.scriptText);
else writefln("Script '%s' not found", scptName);
writefln();
}
writefln(esmRegion);
poolSize();
}
// Quick function that simply iterates through an ES file and prints
// out all the records and subrecords. Some of this code is really old
// (about 2004-2005)
void printRaw()
{
with(esFile)
{
// Variable length integer (this only works for unsigned ints!)
ulong getHVUint()
{
ulong l;
getSubHeader();
if( (getSubSize != 4) &&
(getSubSize != 2) &&
(getSubSize != 8) )
fail(format("Unknown integer size: ", getSubSize));
readExact(&l, getSubSize);
return l;
}
writefln("Filename: ", getFilename);
writef("Filetype: ");
switch(getFileType())
{
case FileType.Plugin: writefln("Plugin"); break;
case FileType.Master: writefln("Master"); break;
case FileType.Savegame: writefln("Savegame"); break;
case FileType.Unknown: writefln("Unknown"); break;
default: assert(0);
}
writef("Version: ");
if(isVer12()) writefln("1.2");
else if(isVer13()) writefln("1.3");
else writefln("Unknown");
writefln("Records: ", getRecords);
writefln("Master files:");
for(int i; i<getMasters.length; i++)
writefln(" %s", getMasters[i].name, ", ", getMasters[i].size, " bytes");
writefln("Author: %s", getAuthor);
//writefln("Description: %s", desc);
writefln("Total file size: %d\n", getFileSize);
writefln("List of records:");
while(hasMoreRecs())
{
uint flags;
// Read record header
char[] recName = getRecName();
getRecHeader(flags);
if(flags)
{
writef("Flags: ");
if(flags & RecordFlags.Persistent) writef("Persistent ");
if(flags & RecordFlags.Blocked) writef("Blocked ");
if(flags & RecordFlags.Flag6) writef("Flag6 ");
if(flags & RecordFlags.Flag13) writef("Flag13 ");
writefln();
if(flags & RecordFlags.Unknown)
writefln("UNKNOWN flags are set: %xh", flags);
}
// Process sub record
writef("%s %d bytes", recName, getRecLeft());
writefln();
while(hasMoreSubs())
{
getSubName();
char[] subName = retSubName();
writef(" %s = ", subName);
// Process header
if(subName == "NAME" || subName == "STRV" ||
subName == "FNAM" || subName == "MODL" ||
subName == "SCRI" || subName == "RGNN" ||
subName == "BNAM" || subName == "ONAM" ||
subName == "INAM" || subName == "SCVR" ||
subName == "RNAM" || subName == "DNAM" ||
subName == "ANAM")
//subName == "SCTX") // For script text
//getHString();
{
writefln("'%s'", getHString());
}
else if(subName == "FLTV" || subName == "XSCL")
{
float f = getHFloat();
writefln("f=", f, " i=", *(cast(int*)&f));
}
else if(subName == "INTV" /*|| subName == "NAM0"*/ || subName == "FRMR")
writefln(getHVUint());
else
{
int left = skipHSub();
writefln(left, " bytes");
}
}
writefln();
}
}
}