Page 201 of 396

Re: Ask a simple question, get a simple answer

Posted: Mon May 01, 2017 7:15 pm
by Marebre
Is it possible to change, or at least rename BaseStats and their descriptions? For example, rename Strength into Constitution, or remove resistance bonus from stats, or change their description, or add brand new stat to the game (so characters will have 5 or more stats)?

Re: Ask a simple question, get a simple answer

Posted: Wed May 03, 2017 12:20 pm
by Badgert
Good afternoon!
I'm trying to make an alternative ending for my mod and there was a question.
Is it possible to do so that, when entering the portal, the second video (the current where the heroes do not depart on the ship) starts to play?
And if you can, how exactly?

Re: Ask a simple question, get a simple answer

Posted: Wed May 03, 2017 1:55 pm
by Isaac
Badgert wrote:Good afternoon!
I'm trying to make an alternative ending for my mod and there was a question.
Is it possible to do so that, when entering the portal, the second video (the current where the heroes do not depart on the ship) starts to play?
And if you can, how exactly?
The Portal asset is defined with the ending video; you need to redefine the default asset, or define a new portal asset.

Code: Select all

defineObject{
	name = "portal",
	baseObject = "portal",
	components = {
		{
			class = "Portal",
			onArrival = function()
				--GameMode.completeGame("assets/videos/outro1.ivf")  --original
				GameMode.completeGame("mod_assets/videos/custom_ending_1.ivf")  --custom
			end,
		},
	},
}
You can make a slideshow video for the ending. You must encode the video with the VP8 codec.
http://www.grimrock.net/modding/creating-cinematics/

Re: Ask a simple question, get a simple answer

Posted: Wed May 03, 2017 3:59 pm
by Badgert
Isaac, many thanks!

Re: Ask a simple question, get a simple answer

Posted: Thu May 04, 2017 2:38 am
by gmsantashelper
Loaded up one of my dungeons in the editor after about a year and upon activating a simple dig script the play tester crashes with the error shown in the linked image. It used to work perfectly fine. Nothing has changed except maybe steam updating LoG2 over the past year. Cannot figure out what is going on here. Given it is line 55 of the init.lua, I think it will happen any time 'onRest' is called up. Fairly certain I am using the latest GrimTK available on the Nexus as it hasn't been updated since 2015. https://steamuserimages-a.akamaihd.net/ ... 996C14DEC/

What is going on/How do I fix this?

*edit*
Can confirm simply resting will cause the crash as well, same thing:

mod_assets/ext/grimtk/init.lua:55: attempt to index field 'GUI' (a nil value)

segment containing called out line:

Code: Select all

if fw_hook == nil then

	defineObject{
		name = "party",
		baseObject = "party",
		components = {
			{
				class = "Party",
				onDrawGui = function(party, g)
					
				end,
				onRest = function(party)
					if ( findEntity("GTK") ) then
						if ( GTK.Core.GUI:isPartyLocked() ) then           <--- Line 55 (this comment obviously not in the code)
							return false;
						end
					end			
				end,
				onWakeUp = function(party)
					if ( findEntity("GTK") ) then
						if ( GTK.Core.GUI:isPartyLocked() ) then
							return false;
						end
					end
				end
			}
		}
	}

end

Re: Ask a simple question, get a simple answer

Posted: Thu May 04, 2017 7:54 am
by akroma222
the onRest (and onWakeUp) hooks will both crash it - but they work fine
the field GUI is coming up with nil, GUI is a huge table of custom functions within core.lua ,
("mod_assets/grimtk/scripts/gtk/core.lua")
Have you checked to make sure grimtk's init file is being imported from your mods init.lua ?
grimtk's init.lua defines the "grimtk" object, which is a script entity object that creates more script components - loading a bunch of .lua files
SpoilerShow

Code: Select all

defineObject{
	name = "grimtk",
	baseObject = "script_entity",
	components = {
		{
			class = "Null",
			onInit = function(self)
				if ( findEntity("GTK") == nil ) then
					local gtk = spawn("script_entity", 1, 1, 1, 1, 1, "GTK");
					gtk.script:loadFile("mod_assets/grimtk/scripts/hook.lua");
					gtk:createComponent("Script", "Constants"):loadFile("mod_assets/grimtk/scripts/gtk/constants.lua");
					gtk:createComponent("Script", "Input"):loadFile("mod_assets/grimtk/scripts/gtk/input.lua");					
					gtk:createComponent("Script", "Core"):loadFile("mod_assets/grimtk/scripts/gtk/core.lua");
					gtk:createComponent("Script", "Widgets"):loadFile("mod_assets/grimtk/scripts/gtk/widgets.lua");

					if ( Editor.isRunning() ) then
						gtk:createComponent("Script", "Debug"):loadFile("mod_assets/grimtk/scripts/gtk/debug.lua");
					end

					delayedCall("GTK", 0.01, "emitGtkDidLoad");
				end
				
				if ( findEntity("GTKGui") == nil ) then
					local gtkgui = spawn("script_entity", 1, 1, 1, 1, 1, "GTKGui");
					gtkgui:createComponent("Script", "Basic"):loadFile("mod_assets/grimtk/scripts/gtkgui/basic.lua");
					gtkgui:createComponent("Script", "Basic_modded"):loadFile("mod_assets/grimtk/scripts/gtkgui/basic_modded.lua");
					gtkgui:createComponent("Script", "Dialogue"):loadFile("mod_assets/grimtk/scripts/gtkgui/dialogue.lua");
					gtkgui:createComponent("Script", "Cinematic"):loadFile("mod_assets/grimtk/scripts/gtkgui/cinematic.lua");					
				end
			end
		}
	}
}
double check that that is all still there and working

Re: Ask a simple question, get a simple answer

Posted: Thu May 04, 2017 9:11 am
by minmay
akroma222 wrote:Have you checked to make sure grimtk's init file is being imported?
It would be hard for an error to occur in grimtk/init.lua if grimtk/init.lua wasn't being imported...

Definitely look at core.lua.

Re: Ask a simple question, get a simple answer

Posted: Thu May 04, 2017 9:48 am
by akroma222
minmay wrote:
akroma222 wrote:Have you checked to make sure grimtk's init file is being imported?
It would be hard for an error to occur in grimtk/init.lua if grimtk/init.lua wasn't being imported...
:lol: you're probably right, ya know! :lol:
Honestly, I think Ive rewritten that^^ message 7 times - and still missed that!
(its one of those days)

Re: Ask a simple question, get a simple answer

Posted: Thu May 04, 2017 10:50 pm
by gmsantashelper
The core.lua does define GUI, and it is a lot of stuff. Not sure why it would be seen as nil if it has an abundance of values. What does it even mean by trying to index a nil value? I feel like this is turning out to not be a simple question, and needs more than just a simple answer, hah.

For sake of clarity, here is the entire grimtk init.lua, and yeah, it is definitely imported correctly, lol.

Code: Select all

defineObject{
	name = "grimtk",
	baseObject = "script_entity",
	components = {
		{
			class = "Null",
			onInit = function(self)
				if ( findEntity("GTK") == nil ) then
					local gtk = spawn("script_entity", 1, 1, 1, 1, 1, "GTK");
					gtk.script:loadFile("mod_assets/ext/grimtk/scripts/hook.lua");
					gtk:createComponent("Script", "Constants"):loadFile("mod_assets/ext/grimtk/scripts/gtk/constants.lua");
					gtk:createComponent("Script", "Input"):loadFile("mod_assets/ext/grimtk/scripts/gtk/input.lua");					
					gtk:createComponent("Script", "Core"):loadFile("mod_assets/ext/grimtk/scripts/gtk/core.lua");
					gtk:createComponent("Script", "Widgets"):loadFile("mod_assets/ext/grimtk/scripts/gtk/widgets.lua");

					if ( Editor.isRunning() ) then
						gtk:createComponent("Script", "Debug"):loadFile("mod_assets/ext/grimtk/scripts/gtk/debug.lua");
					end

					delayedCall("GTK", 0.01, "emitGtkDidLoad");
				end
				
				if ( findEntity("GTKGui") == nil ) then
					local gtkgui = spawn("script_entity", 1, 1, 1, 1, 1, "GTKGui");
					gtkgui:createComponent("Script", "Basic"):loadFile("mod_assets/ext/grimtk/scripts/gtkgui/basic.lua");
					gtkgui:createComponent("Script", "Dialogue"):loadFile("mod_assets/ext/grimtk/scripts/gtkgui/dialogue.lua");
					gtkgui:createComponent("Script", "Cinematic"):loadFile("mod_assets/ext/grimtk/scripts/gtkgui/cinematic.lua");					
				end
			end
		}
	}
}


--
-- If the Log2 Framework has been included before this script, then we will use the framework instead.
-- Otherwise, the default behaviour is to override these hooks.
-- NOTE: If you are using the framework, you MUST define an onDrawGui hook SOMEWHERE (even an empty one).
--

if fw_hook == nil then

	defineObject{
		name = "party",
		baseObject = "party",
		components = {
			{
				class = "Party",
				onDrawGui = function(party, g)
					
				end,
				onRest = function(party)
					if ( findEntity("GTK") ) then
						if ( GTK.Core.GUI:isPartyLocked() ) then
							return false;
						end
					end			
				end,
				onWakeUp = function(party)
					if ( findEntity("GTK") ) then
						if ( GTK.Core.GUI:isPartyLocked() ) then
							return false;
						end
					end
				end
			}
		}
	}

end
Also, here is the segment in the core.lua that defines GUI:

Code: Select all

GUI = {
	_tkContext = TKContext.create(),
	_debugMessages = { },
	_windows = { },
	_images = { },
	_updateables = { },
	_shortcuts = { },
	_nextAutoId = 1,
	_focusWidget = nil,
	_partyLocks = 0,
	_keyboardLocks = 0,
	_aiLocks = 0,
	_lastUpdateTime = 0,
	_deltaTime = 0,
	_maxDeltaTime = 0.25,
	_delayedCalls = { },
	isEnabled = true,
	dimBackground = false,
	mouseState = GTK.Input.MouseState.create(),
	keyboardState = GTK.Input.KeyboardState.create(),
	
	getContext = function(self)
		return self._tkContext;
	end,

	addWindow = function(self, window)
		if ( window:name() == nil ) then 
			Console.warn("Cannot create Root window without a name.");
			return false;
		end

		if ( self._windows[window:name()] ~= nil ) then
			Console.warn("Root window already exists with that name.");
			return false;
		end

		self._windows[window:name()] = window;
		self:showWindow(window:name());
		return true;
	end,
	
	createWindow = function(self, args)
		local window = GTK.Widgets.GWindow.create(args);
		
		if ( self:addWindow(window) == true ) then
			return window;
		end

		return nil;
	end,

	destroyWindow = function(self, window)
		local windowName = nil;

		if ( type(window) == "table" ) then
			windowName = window:name();
		elseif ( type(window) == "string" ) then
			windowName = window;
		end

		if ( windowName and self._windows[windowName] ) then
			self:hideWindow(windowName);
			self._windows[windowName] = nil;
		end
	end,
	
	getWindow = function(self, windowName) 
		return self._windows[windowName];
	end,
	
	showWindow = function(self, windowName)
		local window = self._windows[windowName];
		
		if ( window ) then 
			window:setVisible(true);
		end
	end,
	
	hideWindow = function(self, windowName)
		local window = self._windows[windowName];
		
		if ( window ) then 
			window:setVisible(false);
		end
	end,

	addUpdateable = function(self, updateable)
		if ( updateable.update == nil or type(updateable.update) ~= "function" or updateable.updateableId == nil ) then
			Console.warn("[GTK] Attempted to register invalid updateable");
			return;
		end

		if ( self._updateables[updateable.updateableId] ~= nil ) then
			Console.warn("[GTK] An updateable with that name already exists.");
			return;
		end

		if ( updateable.startUpdates ~= nil ) then
			updateable:startUpdates();
		end

		self._updateables[updateable.updateableId] = updateable;
	end,

	removeUpdateable = function(self, updateable)
		local id = nil;

		if ( type(updateable) == "string" ) then
			id = updateable;
		elseif ( updateable.updateableId ~= nil ) then
			id = updateable.updateableId;
		end

		if ( id and self._updateables[id] ~= nil ) then
			if ( self._updateables[id].endUpdates ~= nil ) then
				self._updateables[id]:endUpdates();
			end

			self._updateables[id] = nil;
		end
	end,
	
	update = function(self, guiContext)
		if ( self.isEnabled == false ) then
			return
		end

		local playTime = GameMode.getStatistic("play_time");
		self._deltaTime = playTime - self._lastUpdateTime;
		self._lastUpdateTime = playTime;

		if ( self._deltaTime > self._maxDeltaTime ) then 
			self._deltaTime = self._maxDeltaTime; 
		end

		if ( #self._delayedCalls > 0 ) then
			local toRemove = { };

			for i=#self._delayedCalls,1,-1 do
				local v = self._delayedCalls[i];
				v["delay"] = v["delay"] - self._deltaTime;

				if ( v["delay"] < 0 ) then
					if ( v["func"] ) then
						v["func"](v["param"]);
					end

					table.remove(self._delayedCalls, i);
				end
			end
		end

		for _,updateable in pairs(self._updateables) do
			updateable:update(self._deltaTime);
		end
						
		self._tkContext:start(guiContext);
		self.mouseState:reset(self._tkContext);
		self.keyboardState:reset(self._tkContext);

		local dimScreen = false;
		local screenSize = self._tkContext:size();
		
		for _,window in pairs(self._windows) do
			if ( window.data.dimScreen ) then
				dimScreen = true;
			end
		end
		
		if ( dimScreen ) then
			self._tkContext:drawRect({ position={0,0}, size=screenSize, bgColor={0, 0, 0, 160} });
		end
		
		for _,window in pairs(self._windows) do
			if ( window.data.visible == true ) then
				if ( (window.data.fullscreen == true) and ((window.data.size[1] == screenSize[1]) or (window.data.size[2] ~= screenSize[2])) ) then
					window:setSize(screenSize[1], screenSize[2]);
				end
				
				self:visit(window);				
			end
		end
		
		if ( #self._debugMessages > 0 ) then
			self._tkContext:drawText({ position={10, 10}, size={1200, screenSize[2]-20}, text=table.concat(self._debugMessages, "\n"), textColor={255,255,255,255}, font="tiny" });
		end

		self.keyboardState:commit();
		self.mouseState:commit();
		self._tkContext:finish();
	end,
		
	visit = function(self, widget)		
		if ( widget == nil or widget.data.visible == false ) then
			return
		end
				
		widget:updatePositionInParent(self._tkContext);

		-- Slightly annoying that we do mouse stuff here (and it's not completely separate)
		-- but it's more efficient to only walk the tree of workspaces once...
		self.mouseState:visitWidget(self._tkContext, widget);
		self.keyboardState:visitWidget(self._tkContext, widget);

		widget:update(self._tkContext, self._deltaTime);
		
		self._tkContext:setWorkspaceOpacity(widget.data.opacity);
		widget:draw(self._tkContext);
	
		self._tkContext:pushWorkspace(widget.data.position, widget.data.size);
		
		for _,child in ipairs(widget._children) do
			self:visit(child);
		end

		self._tkContext:popWorkspace();
	end,

	addImage = function(self, args)
		local image = { };

		if ( (args.name == nil) or (args.path == nil) or (args.size == nil)) then
			Console.warn("[addImage] requires at least a name, a path and a size.");
		end

		if ( args.path:sub(-4):lower() ~= ".tga" ) then
			Console.warn("[addImage] '" .. args.path .. "' does not end in .tga");
		end

		if ( args.path:find("//") ) then
			Console.warn("[addImage] '" .. args.path .. "' conains '//' which WILL FAIL when exported!");
		end

		if ( (args.path:sub(1, 6) ~= "assets") and (args.path:sub(1, 10) ~= "mod_assets") ) then
			Console.warn("[addImage] '" .. args.path .. "' does not start with assets or mod_assets." );
		end

		image.name = args.name;
		image.path = args.path;
		image.size = args.size;
		image.margin = iff(args.margin ~= nil, args.margin, {8, 8, 8, 8});
		image.origin = iff(args.origin ~= nil, args.origin, {0,0});		

		self._images[image.name] = image;
	end,

	getImage = function(self, name) 
		return self._images[name];
	end,
	
	getImageSize = function(self, name)
		local image = self._images[name];
		if ( image == nil ) then return {0, 0}; end
		return image.size;
	end,

	nextAutoWidgetId = function(self)
		local id = "widget_" .. self._nextAutoId;
		self._nextAutoId = self._nextAutoId + 1;
		return id;
	end,
	
	setFocus = function(self, widget)
		if ( self._focusWidget ~= nil ) then
			self:unlockKeyboard();
			self:unlockParty();
			self.keyboardState:finishTextEntry();
			self._focusWidget:_triggerPlug("onLoseFocus");
			self._focusWidget:doLoseFocus();
			self._focusWidget = nil;			
		end
			
		if ( widget ~= nil ) then
			self:lockKeyboard();
			self:lockParty();
			self.keyboardState:startTextEntry(widget);
			self._focusWidget = widget;
			self._focusWidget:doGainFocus();
			self._focusWidget:_triggerPlug("onGainFocus");
			GameMode.setGameFlag("DisableKeyboardShortcuts", true);
		end
	end,

	focusWidget = function(self)
		return self._focusWidget;
	end,

	delayedCall = function(self, delay, param, func)
		table.insert(self._delayedCalls, {delay = delay, func = func, param = param});
	end,
	
	lockParty = function(self)
		self._partyLocks = self._partyLocks + 1;
		GameMode.setGameFlag("DisableMovement", true);
		GameMode.setGameFlag("DisableMouseLook", true);
	end,
	
	unlockParty = function(self)
		self._partyLocks = self._partyLocks - 1;

		if ( self._partyLocks <= 0 ) then
			GameMode.setGameFlag("DisableMovement", false);
			GameMode.setGameFlag("DisableMouseLook", false);
			self._partyLocks = 0;
		end
	end,
	
	isPartyLocked = function(self)
		return self._partyLocks > 0;
	end,

	lockKeyboard = function(self)
		self._keyboardLocks = self._keyboardLocks + 1;
		GameMode.setGameFlag("DisableKeyboardShortcuts", true);
	end,

	unlockKeyboard = function(self)
		self._keyboardLocks = self._keyboardLocks - 1;

		if ( self._keyboardLocks <= 0 ) then
			self._keyboardLocks = 0;

			self:delayedCall(0.1, self, function(self) 
				if ( self._keyboardLocks == 0 ) then
					GameMode.setGameFlag("DisableKeyboardShortcuts", false); 
				end
			end);
		end
	end,

	isKeyboardLocked = function(self)
		return self._keyboardLocks > 0;
	end,

	freezeAI = function(self)
		self._aiLocks = self._aiLocks + 1;
		GameMode.setGameFlag("DisableMonsterAI", true);
	end,

	unfreezeAI = function(self)
		self._aiLocks = self._aiLocks - 1;

		if ( self._aiLocks <= 0 ) then
			GameMode.setGameFlag("DisableMonsterAI", false);
			self._aiLocks = 0;
		end
	end,

	isAIFrozen = function(self)
		return self._aiLocks > 0;
	end,

	log = function(self, message)
		if ( #self._debugMessages > 50 ) then
			table.remove(self._debugMessages, 1);
		end

		table.insert(self._debugMessages, message);
	end,
	
	clearDebug = function(self)
		self._debugMessages = { };
	end,

	toggleDebug = function(self)
		if ( self._tkContext.debugMode == false) then
			self._tkContext.debugMode = true;

			if ( Editor.isRunning() )  then
				GTK.Debug.showDebugWindow();
			end
		else
			self._tkContext.debugMode = false;

			if ( Editor.isRunning() ) then
				GTK.Debug.destroyDebugWindow();
			end
		end
	end,
	
}
I'd simply pull out GrimTK but I planned to use it for dialogue popups to give hints/story elements without having to locate and read a note in places that don't really have that option. Honestly I don't remember what all uses it already, been so long.

Re: Ask a simple question, get a simple answer

Posted: Fri May 05, 2017 12:51 am
by minmay
It means you're trying to index nil. Indexing operators are ., :, and []. It is happening because GTK.Core.GUI is nil at the time that line executes.
This problem arises from a weakness in GrimTK, specifically in how it converts its source files to ScriptComponents. In certain contexts, after createComponent() returns, it's already too late to call loadFile(); the source you "load" won't actually load and run, because the ScriptComponent has already compiled. As a general rule, createComponent [...] loadFile will work at dungeon initialization time, but not afterwards. So if you're spawning the grimtk object dynamically instead of placing it in the dungeon editor, for example, you will probably run into this bug.

In short, place the grimtk object using the dungeon editor instead of trying to spawn it later.