Jump to content

Recommended Posts

Ohai!

 

I'm working on a mod that (hopefully) will be a total conversion of the game.

 

So far I got a spider character up and working, but it behaves borky with Maxwell's intro speech. I've been looking all over the place, including the Screecher mod files, and the only thing I managed to find was the file that launched the intro. How would I go about making my mod ignore this entirely?

Edited by Zethariel

I have not looked to much into it but MY guess is it has something to do with gamelogic.ua and these lines

elseif (GetClock().numcycles == 0 and GetClock():GetNormTime() == 0) or Settings.maxwell ~= nil then				local max = SpawnPrefab("maxwellintro")				local speechName = "NULL_SPEECH"				if Settings.maxwell then					speechName = Settings.maxwell				elseif SaveGameIndex:GetCurrentMode() == "adventure" then					if savedata.map.override_level_string == true then						local level_id = 1						if GetWorld().meta then							level_id = GetWorld().meta.level_id or level_id 						end						speechName = "ADVENTURE_"..level_id					else						speechName = "ADVENTURE_"..SaveGameIndex:GetSlotWorld()					end				else					speechName = "SANDBOX_1"				end				max.components.maxwelltalker:SetSpeech(speechName)				max.components.maxwelltalker:Initialize()				max.task = max:StartThread(function()	max.components.maxwelltalker:DoTalk() end) 				--PlayNIS("maxwellintro", savedata.map.maxwell)			end
Edited by Nycidian

Ohai!

 

I'm working on a mod that (hopefully) will be a total conversion of the game.

 

So far I got a spider character up and working, but it behaves borky with Maxwell's intro speech. I've been looking all over the place, including the Screecher mod files, and the only thing I managed to find was the file that launched the intro. How would I go about making my mod ignore this entirely?

local function remove(inst)    inst:Remove()end AddPrefabPostInit("maxwellintro", remove)

should do the trick.

I'd start with prefabs/maxwellintro.lua I'm not exactly sure what to do either. An override would work, but there must be a better way. Perhaps grep the scripts folder for mentions of maxwellintro?

 

Yep, that was the script I was talking about. I even identified what was causing the trouble (the spider had different "sleep" tasks and no wakeup), but even after adding that to the stategraph it kept the camera zoomed in and generally bugged.

 

 

I have not looked to much into it but MY guess is it has something to do with gamelogic.ua and these lines

elseif (GetClock().numcycles == 0 and GetClock():GetNormTime() == 0) or Settings.maxwell ~= nil then				local max = SpawnPrefab("maxwellintro")				local speechName = "NULL_SPEECH"				if Settings.maxwell then					speechName = Settings.maxwell				elseif SaveGameIndex:GetCurrentMode() == "adventure" then					if savedata.map.override_level_string == true then						local level_id = 1						if GetWorld().meta then							level_id = GetWorld().meta.level_id or level_id 						end						speechName = "ADVENTURE_"..level_id					else						speechName = "ADVENTURE_"..SaveGameIndex:GetSlotWorld()					end				else					speechName = "SANDBOX_1"				end				max.components.maxwelltalker:SetSpeech(speechName)				max.components.maxwelltalker:Initialize()				max.task = max:StartThread(function()	max.components.maxwelltalker:DoTalk() end) 				--PlayNIS("maxwellintro", savedata.map.maxwell)			end

 

That was my guess too. Guess I'll have to override this file, in a smart way

 

local function remove(inst)    inst:Remove()end AddPrefabPostInit("maxwellintro", remove)

should do the trick.

 

 

This caused an error:

Zrzut%20ekranu%202013-10-29%2019.20.07.p

 

I guess I cant delete it, since it's used in adventure mode as well.

Sorry, I can't seem to edit posts, and the screen didnt go through:

error.png

Ah, I should've known it would have caused an issue. The reason why is because the game tries to give a speech. Because maxwellintro no longer exists, he can't give his speech. This is easy to fix. Just add this to remove(), before inst:Remove() happens. That will make him invisibile, then he'll stop his speech. (This is untested, but should be the right direction. You could always also do AddComponentPostInit() with the maxwelltalker component, and just clear out Initiliaze() so it ends before it can make maxwell talk.)

    inst:Hide()    if inst.components.talker then        inst.components.talker:ShutUp()    end
Edited by debugman18

 

Ah, I should've known it would have caused an issue. The reason why is because the game tries to give a speech. Because maxwellintro no longer exists, he can't give his speech. This is easy to fix. Just add this to remove(), before inst:Remove() happens. That will make him invisibile, then he'll stop his speech. (This is untested, but should be the right direction. You could always also do AddComponentPostInit() with the maxwelltalker component, and just clear out Initiliaze() so it ends before it can make maxwell talk.)

    inst:Hide()    if inst.components.talker then        inst.components.talker:ShutUp()    end

 

Excuse me if this sounds dumb (I'm fairly new to LUA and the structure of Don't Starve), but from what I gather, maxwellintro does not have any components. Would it be possible to override the init, script and cancel functions of maxwellintro? With that, I could just put empty ones and be done with that part :3

 

"Just add this to remove(), before inst:Remove() happens. That will make him invisibile, then he'll stop his speech." I did not understand. You mean the :Hide()? That would not prevent the script from being accessed, right?

Excuse me if this sounds dumb (I'm fairly new to LUA and the structure of Don't Starve), but from what I gather, maxwellintro does not have any components. Would it be possible to override the init, script and cancel functions of maxwellintro? With that, I could just put empty ones and be done with that part :3

 

"Just add this to remove(), before inst:Remove() happens. That will make him invisibile, then he'll stop his speech." I did not understand. You mean the :Hide()? That would not prevent the script from being accessed, right?

maxwellintro does indeed have components. This is the snippet from gamelogic.lua:

                 local max = SpawnPrefab("maxwellintro")                max.components.maxwelltalker:SetSpeech(speechName)                max.components.maxwelltalker:Initialize()

 

Here it says that max' will be the "maxwellintro" prefab. So when it says 'max', think of it as 'inst'. And Hide() simply hides maxwellintro. (When he disappears after his speech.)

 

And you can override all of maxwellintro, by putting your own into your mod folder structure. However, I don't suggest this, as gamelogic.lua will still try to run the maxwelltalker component, so you'll get a crash.

maxwellintro does indeed have components. This is the snippet from gamelogic.lua:

 

 

                local max = SpawnPrefab("maxwellintro")

                max.components.maxwelltalker:SetSpeech(speechName)

                max.components.maxwelltalker:Initialize()

 

Here it says that max' will be the "maxwellintro" prefab. So when it says 'max', think of it as 'inst'. And Hide() simply hides maxwellintro. (When he disappears after his speech.)

 

And you can override all of maxwellintro, by putting your own into your mod folder structure. However, I don't suggest this, as gamelogic.lua will still try to run the maxwelltalker component, so you'll get a crash.

 

 

Unused to this kind of syntax X_x It turns out that maxwell uses a maxwelltalker instead of a regular talker, so I tried to hook into that. But it didn't go so well:

local function shush(inst)	inst.components.maxwelltalker:OnCancel()end  AddPrefabPostInit("maxwellintro", shush)

error2.png

 

At this point I'd also like to thank you for your time and assistance ^^ You helped me understand a lot :3 Still some way to go for me to be able to make a total conversion though xD This will all probably have to be replaced by custom launching/generating code anyway... But this problem got me too hooked and I NEED to solve it @_@

Unused to this kind of syntax X_x It turns out that maxwell uses a maxwelltalker instead of a regular talker, so I tried to hook into that. But it didn't go so well:

local function shush(inst)	inst.components.maxwelltalker:OnCancel()end  AddPrefabPostInit("maxwellintro", shush)

error2.png

 

At this point I'd also like to thank you for your time and assistance ^^ You helped me understand a lot :3 Still some way to go for me to be able to make a total conversion though xD This will all probably have to be replaced by custom launching/generating code anyway... But this problem got me too hooked and I NEED to solve it @_@

I'd have to look at the code for maxwelltalker again, but I think that's causing the error because there is no speech to stop. Try adding this line above inst.components.maxwelltalker:OnCancel():

inst.components.maxwelltalker:SetSpeech("NULL_SPEECH")

 

I'd have to look at the code for maxwelltalker again, but I think that's causing the error because there is no speech to stop. Try adding this line above inst.components.maxwelltalker:OnCancel():

inst.components.maxwelltalker:SetSpeech("NULL_SPEECH")

Nope, still throws the same error, although it shouldn't. Weird.

 

My theory is, now that I look at the init code - the thing we are trying to modify is a local variable, one that is launched and then disposed of. The only real way to alter this, I THINK, is to hook up into this thread:

830 | max.components.maxwelltalker:SetSpeech(speechName)831 | max.components.maxwelltalker:Initialize()832 | max.task = max:StartThread(function()	max.components.maxwelltalker:DoTalk() end) 

And cancel it. Otherwise, all that we are currently doing is, after the world has already been initialized (and maxwell already fed his information and such) is working on a dummy that doesn't spawn properly, hence the errors and when I launch the game Maxwell still talks in the background. I suspect it is doable to get into the task manager and kill the task, yes?

Nope, still throws the same error, although it shouldn't. Weird.

 

My theory is, now that I look at the init code - the thing we are trying to modify is a local variable, one that is launched and then disposed of. The only real way to alter this, I THINK, is to hook up into this thread:

830 | max.components.maxwelltalker:SetSpeech(speechName)831 | max.components.maxwelltalker:Initialize()832 | max.task = max:StartThread(function()	max.components.maxwelltalker:DoTalk() end) 

And cancel it. Otherwise, all that we are currently doing is, after the world has already been initialized (and maxwell already fed his information and such) is working on a dummy that doesn't spawn properly, hence the errors and when I launch the game Maxwell still talks in the background. I suspect it is doable to get into the task manager and kill the task, yes?

But we're modifying every instance of 'maxwellintro'. 'max' in this case IS the maxwellintro prefab, since it says

max = SpawnPrefab("maxwellintro"). I'm not sure why it's not working.

 

And yes, the task can be killed.

But we're modifying every instance of 'maxwellintro'. 'max' in this case IS the maxwellintro prefab, since it says

max = SpawnPrefab("maxwellintro"). I'm not sure why it's not working.

 

And yes, the task can be killed.

Okay, now I get it. It worked differently than I assumed (I thought it did all the instructions and put them on a task/scheduler list for launching later; the more you know!)

 

According to the log, the speech does get changed to the value you told me to use:

local function shush(inst)		inst.components.maxwelltalker:SetSpeech("NULL_SPEECH")	print(inst.components.maxwelltalker.speech)	inst.components.maxwelltalker:OnCancel()end// Now for the log../mods/Hive/modmain.lua(24,1) NULL_SPEECH	scripts/mods.lua(17,1) error calling PrefabPostInit: maxwellintro in mod Hive (The Hive): ...ont_starve/data/scripts/components/maxwelltalker.lua:22: attempt to index field 'speech' (a nil value)

The thing that intrigues me though is how this is worded in the maxwelltalker:

if self.inst.speech.disableplayer and self.inst.wilson then	    if self.inst.wilson.sg.currentstate.name == "sleep" then				    self.inst.SoundEmitter:KillSound("talk")	--ensures any talking sounds have stopped		    if self.inst.speech.disappearanim then                if SaveGameIndex:GetCurrentMode(Settings.save_slot) == "adventure" then

So, speech has a parameter inside of itself? How does that work? Or is it just a node that's named disableplayer? Apparently this .disableplayer returns a nil

 

EDIT:

The funny thing is, that once the error about this appears, Maxwell STILL says his intro lines, despite them having being set to NULL before. That doesn't make sense, unless the engine discards all previous changes made by the mod

Edited by Zethariel

Okay, now I get it. It worked differently than I assumed (I thought it did all the instructions and put them on a task/scheduler list for launching later; the more you know!)

 

According to the log, the speech does get changed to the value you told me to use:

local function shush(inst)		inst.components.maxwelltalker:SetSpeech("NULL_SPEECH")	print(inst.components.maxwelltalker.speech)	inst.components.maxwelltalker:OnCancel()end// Now for the log../mods/Hive/modmain.lua(24,1) NULL_SPEECH	scripts/mods.lua(17,1) error calling PrefabPostInit: maxwellintro in mod Hive (The Hive): ...ont_starve/data/scripts/components/maxwelltalker.lua:22: attempt to index field 'speech' (a nil value)

The thing that intrigues me though is how this is worded in the maxwelltalker:

if self.inst.speech.disableplayer and self.inst.wilson then	    if self.inst.wilson.sg.currentstate.name == "sleep" then				    self.inst.SoundEmitter:KillSound("talk")	--ensures any talking sounds have stopped		    if self.inst.speech.disappearanim then                if SaveGameIndex:GetCurrentMode(Settings.save_slot) == "adventure" then

So, speech has a parameter inside of itself? How does that work? Or is it just a node that's named disableplayer? Apparently this .disableplayer returns a nil

 

EDIT:

The funny thing is, that once the error about this appears, Maxwell STILL says his intro lines, despite them having being set to NULL before. That doesn't make sense, unless the engine discards all previous changes made by the mod

Interesting. And self.inst.speech is what we set to "NULL_SPEECH".

 

I have an unorthodox solution. Try this in shush():

inst.task = inst:StartThread(function() print "This is not a speech" end)inst:Hide()

It may not work, since I think task gets overwritten, but it's worth trying, in my opinion. If that doesn't work I'd suggest changing the world overrides in a modworldgenmain.lua, by inserting maxwell = false into the world override tables. (Iirc)

Edited by debugman18

Interesting. And self.inst.speech is what we set to "NULL_SPEECH".

 

I have an unorthodox solution. Try this in shush():

inst.task = inst:StartThread(function() print "This is not a speech" end)inst:Hide()

It may not work, since I think task gets overwritten, but it's worth trying, in my opinion. If that doesn't work I'd suggest changing the world overrides in a modworldgenmain.lua, by inserting maxwell = false into the world override tables. (Iirc)

That didn't work, and I tried a few different variants of trying to alter the talker. Apparently, even if I put some debug prints into it, they didn't print, making me believe that somehow, somewhere, these scripts just don't get fired. I'm lost in the structure of it all

 

And either I overrode wrong, or Maxwell just doesn't give a damn about me .-.

GLOBAL.require("map/level") -- for LEVELTYPElocal LEVELTYPE = GLOBAL.LEVELTYPEAddLevel(LEVELTYPE.SURVIVAL, {	id="SURVIVAL_DEFAULT",	name="Hive map",	desc="Hive map",	overrides={				nomaxwell = true,	}})

Put this in modworldgenmain.lua (create it if it doesn't exist):

local levels = GLOBAL.require "map/levels"AddLevelPreInitAny(function(lvl)	for _, l in ipairs(levels.sandbox_levels) do		if l == lvl then			lvl.nomaxwell = true			break		end	endend)
But I don't believe there's a way for it to happen just when your character is used (instead of whenever your mod is enabled), because this tweak needs to be done at worldgen, when the information of which character was chosen is not yet available (it's stored in disk as savedata, but it hasn't been loaded yet). Edited by simplex

Is there a reason that you just don't overwrite the function that initiates maxwell in the gamelogic.lua?

 

I don't know how to do it but I assume there is a way to do it like you can in prefabs and components, if not you could always replace the entire file. It might make it less compatible mod wise but few mods mess with these files anyway.

 

 

Also is it not possible just to set Settings.maxwell to nil?

 

Wouldn't that cause it to skip the whole maxwell scene?

Edited by Nycidian

Is there a reason that you just don't overwrite the function that initiates maxwell in the gamelogic.lua?

 

I don't know how to do it but I assume there is a way to do it like you can in prefabs and components, if not you could always replace the entire file. It might make it less compatible mod wise but few mods mess with these files anyway.

 

 

Also is it not possible just to set Settings.maxwell to nil?

 

Wouldn't that cause it to skip the whole maxwell scene?

The thing is gamelogic.lua should only be loaded later, not when mods run. Replacing the file would work, but that's much worse.

When mods run, the Settings table has not (for its most part) been populated yet, so doing that wouldn't work. Not to mention Settings.maxwell only controls the speech used, not the appearance or not of Maxwell. The latter is defined by savedata.map.nomaxwell, where savedata is the table representing the savedata for the loaded slot.

Put this in modworldgenmain.lua (create it if it doesn't exist):

local levels = GLOBAL.require "map/levels"AddLevelPreInitAny(function(lvl)	for _, l in ipairs(levels.sandbox_levels) do		if l == lvl then			lvl.nomaxwell = true			break		end	endend)
But I don't believe there's a way for it to happen just when your character is used (instead of whenever your mod is enabled), because this tweak needs to be done at worldgen, when the information of which character was chosen is not yet available (it's stored in disk as savedata, but it hasn't been loaded yet).

 

Oh yesss, thank you a thousand times over! This snippet works perfectly and erases Maxwell out of the start ^^

 

You and debugman18 have been most helpfull, thank you so much! Later down the road I'll replace some of the main menu elements with custom ones, that will point exclusivelly to the character I want to use (similarly like in the Screecher).

 

Now I just need to understand what is happening here.From what I understand, levels.sandbox_levels works like a hashmap of sorts? The index is _ because it is never used, or can you use any ASCII character to denote it? I understand that when it find the current starting level, it just flips nomaxwell on and breaks the loop.

 

Guess I just need to read LUA documentation for this. Thanks again!

The thing is gamelogic.lua should only be loaded later, not when mods run. Replacing the file would work, but that's much worse.

When mods run, the Settings table has not (for its most part) been populated yet, so doing that wouldn't work. Not to mention Settings.maxwell only controls the speech used, not the appearance or not of Maxwell. The latter is defined by savedata.map.nomaxwell, where savedata is the table representing the savedata for the loaded slot.

 

Nope you can still do it all it requires is a delayed command I had to do the same type of thing with the charlie mod as the hud didn't exist yet but I needted to call it for the mod so in my component I did this...

self.inst:DoTaskInTime(0.001, function(inst, data) self:OnDelayed() end)function Gruesomeness:OnDelayed(inst)    --Place Widget    local status = GetPlayer().HUD.controls.status    status.gruesome = status:AddChild(GruesomeBadge(self.inst))    status.gruesome:SetPosition(0,15,0)    status.stomach:SetPosition(-40,-40,0)    status.heart:SetPosition(40,-40,0)    status.brain:SetPosition(0,-95,0)    status.gruesome.anim:GetAnimState():SetBank("sanity")    status.gruesome.anim:GetAnimState():SetBuild("gruesome")    status.gruesome:SetPercent(self.currentGrue/self.max, self.max)end

Oh yesss, thank you a thousand times over! This snippet works perfectly and erases Maxwell out of the start ^^

 

You and debugman18 have been most helpfull, thank you so much! Later down the road I'll replace some of the main menu elements with custom ones, that will point exclusivelly to the character I want to use (similarly like in the Screecher).

 

Now I just need to understand what is happening here.From what I understand, levels.sandbox_levels works like a hashmap of sorts? The index is _ because it is never used, or can you use any ASCII character to denote it? I understand that when it find the current starting level, it just flips nomaxwell on and breaks the loop.

 

Guess I just need to read LUA documentation for this. Thanks again!

levels.sandbox_levels is just the array of all sandbox levels. What I'm doing is iterating over it (using _ as the name for the index variable because I don't need it), seeing if any of them is equal to the current level being (possibly) tweaked. Usually, to determine if the current level is a sandbox one, you'd test

GLOBAL.SaveGameIndex:GetCurrentMode() == "survival"
but, as I mentioned before, the SaveGameIndex hasn't been initialized yet at that point of worldgen, so I took this alternate approach.

The purpose of that loop is just to ensure only survival levels will be tweaked, and not adventure ones.

Nope you can still do it all it requires is a delayed command I had to do the same type of thing with the charlie mod as the hud didn't exist yet but I needted to call it for the mod so in my component I did this...

No. All of this happens before the first frame of the game. Even a delay of 0 seconds would be too late.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...