MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
I'm trying to create a way to export/import a party member to get around the 50 player limit by making MMExtension lua scripts in MM8 (specifically the World of Enroth MM 6,7,8 merge; community master branch). Problem is, I don't know if I have access to all of the elements of a party member's data tables needed to make the script I want. I discovered 'Party' is the player sorta/kinda struct that contains from which I can modify or get player data, e.g. "Party[#]" appended with .Name or .Experience, seems to indicate it's the array struct for party members.
In Greyface's help page for MMExtension v2.2, notably "dump(Party[0].Stats)" is given as an example to output player stats. I wish I'd seen that first because I was taking shots in the dark browsing deeper in the help page, forums, and MM8 script files. Anyway, if that contains everything, then I should be able to make it work; unless someone smarter here sees a reason why it's doomed to fail?
In Greyface's help page for MMExtension v2.2, notably "dump(Party[0].Stats)" is given as an example to output player stats. I wish I'd seen that first because I was taking shots in the dark browsing deeper in the help page, forums, and MM8 script files. Anyway, if that contains everything, then I should be able to make it work; unless someone smarter here sees a reason why it's doomed to fail?
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
I've been working on a script for the MM 6,7,8 merge to get around the 50 party member limit of MM8 by importing and exporting them to text files. So far, this is what I've got. I'm still in my first year of school for software engineering, so it's not great, or completely finished, but as is, it mostly works. The problem is, I have to use an entry on roster.txt in order to import/export. I have no idea how to implement reserving a space on the roster for importing characters from text files.
Code: Select all
--EXPORT-----------------------------------
function EPM()--TO DO: Create a way to export party members
local filename = "test" --TO DO: Rename the file using character specific info
local filepath = string.format(".\\Adventurers\\%s.txt", filename)
local file = io.open(filepath,"w")
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++START Character Info\n")
file:write( string.format("Name:\t%s\n", Party[Game.CurrentPlayer].Name) )
file:write( string.format("Class #:\t%d\n", Party[Game.CurrentPlayer].Class) )
file:write( string.format("Race #:\t%d\n", Party[Game.CurrentPlayer].Attrs.Race) )
file:write( string.format("Birth Year:\t%d\n", Party[Game.CurrentPlayer].BirthYear) )
file:write( string.format("Biography:\t%s\n", Party[Game.CurrentPlayer].Biography) )
file:write( string.format("Level:\t%d\n", Party[Game.CurrentPlayer].LevelBase) )
file:write( string.format("Experience:\t%d\n", Party[Game.CurrentPlayer].Experience) )
file:write( string.format("Face #:\t%d\n", Party[Game.CurrentPlayer].Face) )
file:write( string.format("Voice #:\t%d\n", Party[Game.CurrentPlayer].Voice) )
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Attributes\t\n")
file:write( string.format("Might:\t%d\n", Party[Game.CurrentPlayer].MightBase) )
file:write( string.format("Intellect:\t%d\n", Party[Game.CurrentPlayer].IntellectBase) )
file:write( string.format("Personality:\t%d\n", Party[Game.CurrentPlayer].PersonalityBase) )
file:write( string.format("Endurance:\t%d\n", Party[Game.CurrentPlayer].EnduranceBase) )
file:write( string.format("Accuracy:\t%d\n", Party[Game.CurrentPlayer].AccuracyBase) )
file:write( string.format("Speed:\t%d\n", Party[Game.CurrentPlayer].SpeedBase) )
file:write( string.format("Luck:\t%d\n", Party[Game.CurrentPlayer].LuckBase) )
file:write( string.format("Hit Points:\t%d\n", Party[Game.CurrentPlayer].HP) )
file:write( string.format("Spell Points:\t%d\n", Party[Game.CurrentPlayer].SP) )
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Resistances\n")
file:write( string.format("Fire Resistance:\t%d\n", Party[Game.CurrentPlayer].FireResistanceBase) )
file:write( string.format("Air Resistance:\t%d\n", Party[Game.CurrentPlayer].AirResistanceBase) )
file:write( string.format("Water Resistance:\t%d\n", Party[Game.CurrentPlayer].WaterResistanceBase) )
file:write( string.format("Earth Resistance:\t%d\n", Party[Game.CurrentPlayer].EarthResistanceBase) )
file:write( string.format("Mind Resistance:\t%d\n", Party[Game.CurrentPlayer].MindResistanceBase) )
file:write( string.format("Body Resistance:\t%d\n", Party[Game.CurrentPlayer].BodyResistanceBase) )
file:write( string.format("Spirit Resistance:\t%d\n", Party[Game.CurrentPlayer].SpiritResistanceBase) )
local r = 0
while r<11 do
file:write( string.format("Resistance #%d:\t%d\n", r+1, Party[Game.CurrentPlayer].Resistances[r].Base) )
r = r + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Skills\n")
file:write( string.format("Skill Points to Spend:\t%d\n", Party[Game.CurrentPlayer].SkillPoints) )
local sk = 0
while sk<39 do
file:write( string.format("Skill #%d:\t%d\n", sk+1, Party[Game.CurrentPlayer].Skills[sk]) )
sk = sk + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Condition\n")
file:write( string.format("Additional Years Aged:\t%d\n", Party[Game.CurrentPlayer].AgeBonus) )
file:write( string.format("Cursed:\t%d\n", Party[Game.CurrentPlayer].Conditions[0]) )
file:write( string.format("Weak:\t%d\n", Party[Game.CurrentPlayer].Conditions[1]) )
file:write( string.format("Asleep:\t%d\n", Party[Game.CurrentPlayer].Conditions[2]) )
file:write( string.format("Afraid:\t%d\n", Party[Game.CurrentPlayer].Conditions[3]) )
file:write( string.format("Drunk:\t%d\n", Party[Game.CurrentPlayer].Conditions[4]) )
file:write( string.format("Insane:\t%d\n", Party[Game.CurrentPlayer].Conditions[5]) )
file:write( string.format("Poison1:\t%d\n", Party[Game.CurrentPlayer].Conditions[6]) )
file:write( string.format("Disease1:\t%d\n", Party[Game.CurrentPlayer].Conditions[7]) )
file:write( string.format("Poison2:\t%d\n", Party[Game.CurrentPlayer].Conditions[8]) )
file:write( string.format("Disease2:\t%d\n", Party[Game.CurrentPlayer].Conditions[9]) )
file:write( string.format("Poison3:\t%d\n", Party[Game.CurrentPlayer].Conditions[10]) )
file:write( string.format("Disease3:\t%d\n", Party[Game.CurrentPlayer].Conditions[11]) )
file:write( string.format("Paralyzed:\t%d\n", Party[Game.CurrentPlayer].Conditions[12]) )
file:write( string.format("Unconscious:\t%d\n", Party[Game.CurrentPlayer].Conditions[13]) )
file:write( string.format("Dead:\t%d\n", Party[Game.CurrentPlayer].Conditions[14]) )
file:write( string.format("Stoned:\t%d\n", Party[Game.CurrentPlayer].Conditions[15]) )
file:write( string.format("Eradicated:\t%d\n", Party[Game.CurrentPlayer].Conditions[16]) )
file:write( string.format("Zombie:\t%d\n", Party[Game.CurrentPlayer].Conditions[17]) )
file:write( string.format("Unkown1:\t%d\n", Party[Game.CurrentPlayer].Conditions[18]) )
file:write( string.format("Unkown2:\t%d\n", Party[Game.CurrentPlayer].Conditions[19]) )
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Equipment\n")
file:write( string.format("Left Hand:\t%d\n", Party[Game.CurrentPlayer].ItemExtraHand) )
file:write( string.format("Right Hand:\t%d\n", Party[Game.CurrentPlayer].ItemMainHand) )
file:write( string.format("Bow:\t%d\n", Party[Game.CurrentPlayer].ItemBow) )
file:write( string.format("Armor:\t%d\n", Party[Game.CurrentPlayer].ItemArmor) )
file:write( string.format("Head:\t%d\n", Party[Game.CurrentPlayer].ItemHelm) )
file:write( string.format("Belt:\t%d\n", Party[Game.CurrentPlayer].ItemBelt) )
file:write( string.format("Cloak:\t%d\n", Party[Game.CurrentPlayer].ItemCloak) )
file:write( string.format("Gloves:\t%d\n", Party[Game.CurrentPlayer].ItemGountlets) )
file:write( string.format("Boots:\t%d\n", Party[Game.CurrentPlayer].ItemBoots) )
file:write( string.format("Amulet:\t%d\n", Party[Game.CurrentPlayer].ItemAmulet) )
file:write( string.format("Ring 1:\t%d\n", Party[Game.CurrentPlayer].ItemRing1) )
file:write( string.format("Ring 2:\t%d\n", Party[Game.CurrentPlayer].ItemRing2) )
file:write( string.format("Ring 3:\t%d\n", Party[Game.CurrentPlayer].ItemRing3) )
file:write( string.format("Ring 4:\t%d\n", Party[Game.CurrentPlayer].ItemRing4) )
file:write( string.format("Ring 5:\t%d\n", Party[Game.CurrentPlayer].ItemRing5) )
file:write( string.format("Ring 6:\t%d\n", Party[Game.CurrentPlayer].ItemRing6) )
local i = 0
local j = 0
local k = 0
local l = 0
local m = 0
local n = 0
local o = 0
local p = 1
local q = 0
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Inventory\n")
while j<126 do
file:write( string.format("Row %d/9, Slot %d/14:\t%d\n", math.ceil((j+1) / 14), (j+14) % 14 + 1, Party[Game.CurrentPlayer].Inventory[j]) )
j = j + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Item Data\n")
while p<138 do
file:write( string.format("Item %d Body Location:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].BodyLocation) )
file:write( string.format("Item %d Bonus 1:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].Bonus) )
file:write( string.format("Item %d Bonus 2:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].Bonus2) )
file:write( string.format("Item %d Bonus Expiration Time:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].BonusExpireTime) )
file:write( string.format("Item %d Bonus Strength:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].BonusStrength) )
file:write( string.format("Item %d Broken:\t%s\n", p, tostring(Party[Game.CurrentPlayer].Items[p].Broken)) )
file:write( string.format("Item %d Charges:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].Charges) )
file:write( string.format("Item %d Condition:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].Condition) )
file:write( string.format("Item %d Hardened:\t%s\n", p, tostring(Party[Game.CurrentPlayer].Items[p].Hardened)) )
file:write( string.format("Item %d Identified:\t%s\n", p, tostring(Party[Game.CurrentPlayer].Items[p].Identified)) )
file:write( string.format("Item %d Max Charges:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].MaxCharges) )
file:write( string.format("Item %d Number:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].Number) )
file:write( string.format("Item %d Owner:\t%d\n", p, Party[Game.CurrentPlayer].Items[p].Owner) )
file:write( string.format("Item %d Stolen:\t%s\n", p, tostring(Party[Game.CurrentPlayer].Items[p].Stolen)) )
file:write( string.format("Item %d Temporary Bonus:\t%s\n", p, tostring(Party[Game.CurrentPlayer].Items[p].TemporaryBonus)) )
p = p + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Spell Book\n")
while i<137 do
file:write( string.format("Knows Spell %d:\t%s\n", i+1, tostring(Party[Game.CurrentPlayer].Spells[i]) ) )
i = i + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Spell Vars\n")
file:write( string.format("Current Spell Book Page:\t%d\n", Party[Game.CurrentPlayer].SpellBookPage) )
file:write( string.format("Current Quick Spell:\t%d\n", Party[Game.CurrentPlayer].QuickSpell) )
file:write( string.format("Armageddon Casts:\t%d\n", Party[Game.CurrentPlayer].ArmageddonCasts) )
file:write( string.format("Divine Intervention Casts:\t%d\n", Party[Game.CurrentPlayer].DevineInterventionCasts) )
file:write( string.format("Fire Spike Casts:\t%d\n", Party[Game.CurrentPlayer].FireSpikeCasts) )
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Lloyd's Beacons\n")
while n<5 do
file:write( string.format("Beacon %d Active:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].Active) )
file:write( string.format("Beacon %d Direction:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].Direction) )
file:write( string.format("Beacon %d Expire Time:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].ExpireTime) )
file:write( string.format("Beacon %d Look Angle:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].LookAngle) )
file:write( string.format("Beacon %d Map:\t%s\n", n+1, tostring(Party[Game.CurrentPlayer].Beacons[n].Map) ) )
file:write( string.format("Beacon %d Map Index:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].MapIndex) )
while o<3 do
file:write( string.format("Beacon %d Pos %d:\t%d\n", n+1, o+1, Party[Game.CurrentPlayer].Beacons[n].Pos[o]) )
o = o + 1
end
file:write( string.format("Beacon %d X:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].X) )
file:write( string.format("Beacon %d Y:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].Y) )
file:write( string.format("Beacon %d Z:\t%d\n", n+1, Party[Game.CurrentPlayer].Beacons[n].Z) )
n = n + 1
o = 0
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Black Potions Used\n")
while k<7 do
file:write( string.format("Black Potion %d:\t%s\n", k+1, tostring(Party[Game.CurrentPlayer].UsedBlackPotions[k+264]) ) )
k = k + 1
end
--TO DO: Figure out how to get the number of potential promotion awards there are to make this loop complete the number of iterations needed
--[[file:write("\nPromotion Awards\n")
while l< #Party[Game.CurrentPlayer].Attrs.PromoAwards do
file:write( string.format("Promotion Award d%:\t%s\n", l+1, tostring(Party[Game.CurrentPlayer].Attrs.PromoAwards[l]) ) )
l = l + 1
end--]]
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++General Awards\n")
while m<104 do
file:write( string.format("Award %d:\t%s\n", m+1, tostring(Party[Game.CurrentPlayer].Awards[m]) ) )
m = m + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++Player Bits\n")
while q<511 do
file:write( string.format("Player Bit %d:\t%s\n", q+1, tostring(Party[Game.CurrentPlayer].PlayerBits[q]) ) )
q = q + 1
end
file:write("\t++++++++++++++++++++++++++++++++++++++++++++++END")
file:close()
end
--IMPORT-----------------------------------
function IPM()
local lastHired = -1
for _, pl in Party do
lastHired = lastHired + 1
end
HireCharacter(49)
local filename = "test"
local filepath = string.format(".\\Adventurers\\%s.txt", filename)
local file = io.open(filepath,"r")
if file ~= nil then
local lines = {}
for line in io.lines(filepath) do
lines[#lines + 1] = line
end
file:close()
--Test to see everything is there
--for k, v in pairs(lines) do
-- print(k, v)
--end
for k, v in pairs(lines) do
lines[k] = string.format(string.sub(string.sub(lines[k],string.find( lines[k], "\t"),string.len(lines[k])),2))
end
--Test to see everything is STILL there
--for k, v in pairs(lines) do
-- print(k, v)
--end
--Character Info Section
Party[lastHired].Name = lines[2]
Party[lastHired].Class = tonumber(lines[3])
Party[lastHired].Race = tonumber(lines[4])
Party[lastHired].BirthYear = tonumber(lines[5])
Party[lastHired].Biography = lines[6]
Party[lastHired].LevelBase = tonumber(lines[7])
Party[lastHired].Experience = tonumber(lines[8])
Party[lastHired].Face = tonumber(lines[9])
Party[lastHired].Voice = tonumber(lines[10])
--Stats
Party[lastHired].MightBase = tonumber(lines[12])
Party[lastHired].IntellectBase = tonumber(lines[13])
Party[lastHired].PersonalityBase = tonumber(lines[14])
Party[lastHired].EnduranceBase = tonumber(lines[15])
Party[lastHired].AccuracyBase = tonumber(lines[16])
Party[lastHired].SpeedBase = tonumber(lines[17])
Party[lastHired].LuckBase = tonumber(lines[18])
Party[lastHired].HP = tonumber(lines[19])
Party[lastHired].SP = tonumber(lines[20])
--Resistances
Party[lastHired].FireResistanceBase = tonumber(lines[22])
Party[lastHired].AirResistanceBase = tonumber(lines[23])
Party[lastHired].WaterResistanceBase = tonumber(lines[24])
Party[lastHired].EarthResistanceBase = tonumber(lines[25])
Party[lastHired].MindResistanceBase = tonumber(lines[26])
Party[lastHired].BodyResistanceBase = tonumber(lines[27])
Party[lastHired].SpiritResistanceBase = tonumber(lines[28])
local r = 0
while r<11 do
Party[lastHired].Resistances[r].Base = tonumber(lines[29+r])
r = r + 1
end
--Skills
Party[lastHired].SkillPoints = tonumber(lines[41])
local i = 0
while i<39 do
Party[lastHired].Skills[i] = tonumber(lines[42+i])
i = i + 1
end
--Conditions
Party[lastHired].AgeBonus = tonumber(lines[82])
local c = 0
while c<20 do
Party[lastHired].Conditions[c] = tonumber(lines[83+c])
c = c + 1
end
--Equipment
Party[lastHired].ItemExtraHand = tonumber(lines[104])
Party[lastHired].ItemMainHand = tonumber(lines[105])
Party[lastHired].ItemBow = tonumber(lines[106])
Party[lastHired].ItemArmor = tonumber(lines[107])
Party[lastHired].ItemHelm = tonumber(lines[108])
Party[lastHired].ItemBelt = tonumber(lines[109])
Party[lastHired].ItemCloak = tonumber(lines[110])
Party[lastHired].ItemGountlets = tonumber(lines[111])
Party[lastHired].ItemBoots = tonumber(lines[112])
Party[lastHired].ItemAmulet = tonumber(lines[113])
Party[lastHired].ItemRing1 = tonumber(lines[114])
Party[lastHired].ItemRing2 = tonumber(lines[115])
Party[lastHired].ItemRing3 = tonumber(lines[116])
Party[lastHired].ItemRing4 = tonumber(lines[117])
Party[lastHired].ItemRing5 = tonumber(lines[118])
Party[lastHired].ItemRing6 = tonumber(lines[119])
--Inventory
local j = 0
while j<126 do
Party[lastHired].Inventory[j] = tonumber(lines[121+j])
j = j + 1
end
--Item Data
local p = 0
local z = 0
while p<137 do
Party[lastHired].Items[p+1].BodyLocation = tonumber(lines[248+z])
Party[lastHired].Items[p+1].Bonus = tonumber(lines[249+z])
Party[lastHired].Items[p+1].Bonus2 = tonumber(lines[250+z])
Party[lastHired].Items[p+1].BonusExpireTime = tonumber(lines[251+z])
Party[lastHired].Items[p+1].BonusStrength = tonumber(lines[252+z])
if string.match(tostring(lines[253+z]),"false") then
Party[lastHired].Items[p+1].Broken = false
else
Party[lastHired].Items[p+1].Broken = true
end
Party[lastHired].Items[p+1].Charges = tonumber(lines[254+z])
Party[lastHired].Items[p+1].Condition = tonumber(lines[255+z])
if string.match(tostring(lines[253+z]),"false") then
Party[lastHired].Items[p+1].Hardened = false
else
Party[lastHired].Items[p+1].Hardened = true
end
if string.match(tostring(lines[253+z]),"false") then
Party[lastHired].Items[p+1].Identified = false
else
Party[lastHired].Items[p+1].Identified = true
end
Party[lastHired].Items[p+1].MaxCharges = tonumber(lines[258+z])
Party[lastHired].Items[p+1].Number = tonumber(lines[259+z])
Party[lastHired].Items[p+1].Owner = tonumber(lines[260+z])
if string.match(tostring(lines[253+z]),"false") then
Party[lastHired].Items[p+1].Stolen = false
else
Party[lastHired].Items[p+1].Stolen = true
end
if string.match(tostring(lines[253+z]),"false") then
Party[lastHired].Items[p+1].TemporaryBonus = false
else
Party[lastHired].Items[p+1].TemporaryBonus = true
end
p = p + 1
z = z + 15
end
--Spellbook
i = 0
while i<137 do
Party[lastHired].Spells[i] = tonumber(lines[121+i])
i = i + 1
end
else
file:close()
MessageBox("%s does not exist", filename)
end
end
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
The problem is lloyd beacon images and also any MMExt scripts that may have some info stored for each player based on index. Code patching would be required to deal with lloyd beacons.
The player structure can be backed up like this:
local pl = Party.PlayersArray[49]
vars.PlayerBackup = mem.string(pl, pl['?size'], true)
And restored like this:
local pl = Party.PlayersArray[49]
mem.copy(pl, vars.PlayerBackup)
[edit] Looks like CODE tag is broken
My patches: MM6 MM7 MM8. MMExtension. Tools. Also, I love Knytt Stories and Knytt Underground. I'm also known as sergroj.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
I finished making the script and posted a Google Drive Link in the MM 6 7 8 Merge thread. I would like to see if the Adventurer's Inn could be changed to use my script to view exported party members that I have stored in text files and have the dismiss button also trigger my script to export a player.GrayFace wrote: ↑04 Nov 2021, 00:46The problem is lloyd beacon images and also any MMExt scripts that may have some info stored for each player based on index. Code patching would be required to deal with lloyd beacons.
The player structure can be backed up like this:
local pl = Party.PlayersArray[49]
vars.PlayerBackup = mem.string(pl, pl['?size'], true)
And restored like this:
local pl = Party.PlayersArray[49]
mem.copy(pl, vars.PlayerBackup)
[edit] Looks like CODE tag is broken
I haven't encountered any problems with Lloyd's Beacon; probably because so far, only the main character has Lloyd's Beacon. For my own personal use, if the picture for the location doesn't work, I'm not too concerned. I would imagine that one could create a new script to handle the creation of Lloyd's Beacon Images instead of whatever already exists. Then, all that my export/import functions would need is to throw the images into a file system sorted by each exported player full of .bmp or .tga images.
You mention info stored based on the player index, but I have played for over 40 hours swapping characters in and out of text files with no major issues; the only minor issue is that it seems like the fountains and shrines that have onetime bonuses do not work on repeat encounters after swapping out a character using my script. I think this issue should persist with NPCMercenaries script since new mercenaries are using the same player roster index, but I haven't tested enough to see how the game remembers who's visited what. I'm not sure how to get around that, but for now, I just manually track who's visited shrines so I can add the bonus using the MMExt console.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
That's because MMExt doesn't expose every aspect of a character and you probably don't save everything that in exposes. I gave you the code to use, you just need to save that string into a binary file instead of vars.PlayerBackup. Why don't you just save them into the save file though?StormyG7 wrote: ↑04 Nov 2021, 19:15the only minor issue is that it seems like the fountains and shrines that have onetime bonuses do not work on repeat encounters after swapping out a character using my script. I think this issue should persist with NPCMercenaries script since new mercenaries are using the same player roster index, but I haven't tested enough to see how the game remembers who's visited what. I'm not sure how to get around that, but for now, I just manually track who's visited shrines so I can add the bonus using the MMExt console.
My patches: MM6 MM7 MM8. MMExtension. Tools. Also, I love Knytt Stories and Knytt Underground. I'm also known as sergroj.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
This is all fairly new to me and right now the script I'm using is working fairly well. Now that you've told me MMExt doesn't give me all the character's data, I'm more interested in creating something that does, by implementing those four lines of code you posted. The problem is, I don't think I know how to create a binary file using lua, and I'm unsure why a binary is preferable to a script. About the saving characters into the save file, I am interested, but I like being able to open a character file in text format and change things easily. I don't know how to save them into the save file or how the save file is structured or even accessed.GrayFace wrote: ↑08 Nov 2021, 04:09 That's because MMExt doesn't expose every aspect of a character and you probably don't save everything that in exposes. I gave you the code to use, you just need to save that string into a binary file instead of vars.PlayerBackup. Why don't you just save them into the save file though?
I'm on a playthrough that might be my last for a long time before I move on to something else. Since you made MMExt, I'm just curious, besides the fountains, do you know what else is left out? Is it anything that matters? As I said, so far my current playthrough is working out great with this script. I import and export characters regularly and; but I would hate for it to be ruined and to have to start all over because I missed something important that won't get exported. It sure seems like I got everything that matters besides the fountains. I know I don't have the honorary promotion awards, because World of Enroth merge stores them in a way that I didn't take time to familiarize myself with and it didn't matter to me for my personal use.
EDIT I was wrong about the fountains and shrines. Somehow it must be in player bits or something I exported, but the game remembers who's visited what fountain from character to character using my export/import script.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Yes, it's stored in player bits. You can check if a bit is set with evt.Cmp("PlayerBits", <number>) (will return true if set) and set a bit with evt.Set("PlayerBits", <number>). Idk how they exactly work though.
Unfinished mod by me: MM7 Rev4 mod, MMMerge version.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Bits are packed into bytes, nothing surprising. So 512 player bits are stored as 64 bytes. There are procedures in mm8.exe that check/set specific bit of specific byte based on given number and offset of the field. Note in MMExtension 2.2 you have to subtract 1 from player bit to get its index in array ('Party[0].PlayerBits[3]' is 'evt.Cmp("PlayerBits", 4)').
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Like this: io.SaveString([[c:\file.dat]], s), where s is that binary string: s = mem.string(pl, pl['?size'], true)
Then loading: s = io.LoadString([[c:\file.dat]])
"vars" table is saved in save file, so you'd need to create a subtable like vars.SavedPlayers and organize players in it however you want.
No, I don't. Can't tell anything off the back of my head.
They too are probably stored outside the player structure for MM6 and MM7. There might be a shortage of PlayerBits to fit all 3 games.
My patches: MM6 MM7 MM8. MMExtension. Tools. Also, I love Knytt Stories and Knytt Underground. I'm also known as sergroj.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Won't you please add some compressor (LZMA maybe)?
All three games combined use less than 100 PlayerBits. 512 is much more than that. But one can't speak about fountains in general - not every one is stored into PlayerBits.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
For Lua data to base MMExt? How much does it weigh in the MMMerge?
My patches: MM6 MM7 MM8. MMExtension. Tools. Also, I love Knytt Stories and Knytt Underground. I'm also known as sergroj.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Right now it is small - up to 300k. But I can easily increase it up to 4M.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Forgot to say I've added compression the day I asked about it. Of course, no LZMA, just ZLib that's already in the game. EnableLuaDataCompression(true) enables it.
My patches: MM6 MM7 MM8. MMExtension. Tools. Also, I love Knytt Stories and Knytt Underground. I'm also known as sergroj.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Hello! Why this not work?
evt.CastSpell{Spell = 77, Mastery = const.Master, Skill = 64, FromX = 0, FromY = 0, FromZ = 0, ToX = 0, ToY = 0, ToZ = 0} - Power Cure
Where i 'm wrong?
evt.CastSpell{Spell = 77, Mastery = const.Master, Skill = 64, FromX = 0, FromY = 0, FromZ = 0, ToX = 0, ToY = 0, ToZ = 0} - Power Cure
Where i 'm wrong?
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
IIRC only some spells are implemented in the evt.CastSpell command, mostly those that are actually used in events (pedestals, traps, etc.) Power Cure is evidently not one of them. To cast Power Cure on the party, ideally you'll need to call the player-casts-spell function, but I don't know where (or even if) it's found in MMExtension. Otherwise, you can just replicate its effects instead, but that's obviously more work.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Depends on what you're using but 'Skill = 64' will most probably call an error. Try to reduce it to 63.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Wow you guys have knowledge way beyond my comprehension. I know nothing about how lua scripting works. But I've read somewhere else that you can edit the respawn timer of each zone using the mapstats.txt. Sadly I don't know where is the location of that file. Maybe I need to create it, right? I'm using de mm678 merge so I know that mmextension is installed along with the editor. I just wanted the monsters to respawn every 2 in game months lmao.
Also is it possible to edit the duration of training? It takes 8 days per level trained. I just want the mm6 version, 8 days per training, it doesn't matter how many levels you train.
Also is it possible to edit the duration of training? It takes 8 days per level trained. I just want the mm6 version, 8 days per training, it doesn't matter how many levels you train.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Wow you guys have knowledge way beyond my comprehension. I know nothing about how lua scripting works. But I've read somewhere else that you can edit the respawn timer of each zone using the mapstats.txt. Sadly I don't know where is the location of that file. Maybe I need to create it, right? I'm using de mm678 merge so I know that mmextension is installed along with the editor. I just wanted the monsters to respawn every 2 in game months lmao.
Also is it possible to edit the duration of training? It takes 8 days per level trained. I just want the mm6 version, 8 days per training, it doesn't matter how many levels you train.
Also is it possible to edit the duration of training? It takes 8 days per level trained. I just want the mm6 version, 8 days per training, it doesn't matter how many levels you train.
Re: MMExtension v2.2 + MMEditor v2.1 Level Editor [June 4, 2019]
Table files like mapstats.txt are in lod archives in the Data directory. You'll need MMArchive or a similar tool to open them. Create DataFiles directory next to Data, extract the txt file there, and then you can edit it. The specific archive depends on the version of Merge you're using, usually it's something.T.lod.
Training time is not easily editable. You'd need an assembly patch or perhaps some time-rewinding MMExt hack, and both are evidently not your specialty. Relatedly, I actually intend to make this exact change in the next version of my MM7 mod (I have a very strong opinion that the MM6 way was better here), but I haven't got around to it yet.
Training time is not easily editable. You'd need an assembly patch or perhaps some time-rewinding MMExt hack, and both are evidently not your specialty. Relatedly, I actually intend to make this exact change in the next version of my MM7 mod (I have a very strong opinion that the MM6 way was better here), but I haven't got around to it yet.
Who is online
Users browsing this forum: Bing [Bot] and 4 guests