Jump to content

[HELP] Getting rid of Maxwell, retaining the world generation


Zethariel

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?

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
Link to comment
Share on other sites

 

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 @_@

Link to comment
Share on other sites

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")
Link to comment
Share on other sites

 

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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)

Link to comment
Share on other sites

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,	}})
Link to comment
Share on other sites

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).
Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...