Page 1 of 1

[Item] Functioning scope

Posted: Mon May 18, 2015 7:56 pm
by alois
Hi. While playing a little bit with custom cameras, I created a functioning "scope". In order to have it, do as follows:
a) in item.lua add:

Code: Select all

defineObject{
	name = "party",
	baseObject = "party",
	components = {
		{
			class = "Party",
			name = "party",
			onDrawGui = function(self,g)
				return gui_script.script.onDrawGui(self,g)
			end,
		},
		{
			class = "Script",
			name = "data",
			source = [[
data = {}
function set(self,name,value)
	self.data[name] = value
end
function get(self,name)
	return self.data[name]
end
]]
		}
	},
}

defineObject{
	name = "scope_camera",
	baseObject = "base_item",
	components = {
		{
			class = "Camera",
			name = "camera",
			enabled = false,
		},
	},
}

defineObject{
	name = "new_scope",
	baseObject = "base_item",
	components = {
		{
			class = "Model",
			name = "model",
			model = "assets/models/items/scope.fbx",
		},
		{
			class = "Item",
			name = "item",
			weight = 0.7,
			uiName = "Scope",
			gfxIndex = 336,
			description = "A delicate instrument that greatly enhances clarity of sight.\n'q' and 'e' to look left/right\n'w' and 's' to raise/lower\n 'a' and 'd' to zoom in/out.",
		},
		{
			class = "UsableItem",
			name = "usableitem",
			onUseItem = function(self,champion)
				return gui_script.script.onUseItem(self,champion)
			end
		},
		{
			class = "Script",
			name = "data",
			source = [[
data = {active = false}
function set(self,name,value)
	self.data[name] = value
end
function get(self,name)
	return self.data[name]
end
]]
		},
	},
}

defineObject{
	name = "scope_timer",
	baseObject = "timer",
	components = {
		{
			class = "Timer",
			name = "timer",
			TimerInterval = 1,
			DisableSelf = false,
			onActivate = function(self)
				local count = self.go.data:get("count") + 1
				if (count < self.go.data:get("countmax")) then -- increase counter
					playSound("click_up")
					self.go.data:set("count",count)
				else
					playSound("click_down")
					GameMode.setCamera(nil) -- revert to standard camera
					findEntity(party.data:get("camera")):destroy() -- destroy the custom camera
					party.data:set("camera",nil) -- tell "data" that there is no camera
					GameMode.setGameFlag("DisableMovement",false) -- party can move
					GameMode.setGameFlag("DisableMouseLook",false) -- party can mouse-look
					self.go:destroy() -- destroy the timer
				end
			end,
		},
		{
			class = "Script",
			name = "data",
			source = [[
data = {count = 0, countmax = 15} -- 15 seconds = duration of the scope look
function set(self,name,value)
	self.data[name] = value
end
function get(self,name)
	return self.data[name]
end
]]
		},
	}
}
b) in a script_entity named "gui_script", put:

Code: Select all

function onDrawGui(self,g)
	if (self.go.data:get("camera")) then
		local cam = findEntity(self.go.data:get("camera"))
		if g.keyDown("e") then -- turn right
			local angles = self.go.data:get("angles")
			if (angles > -45) then
				cam:setWorldRotationAngles(0,angles-5,0)
				self.go.data:set("angles",angles-5)
			end
		end
		if g.keyDown("q") then -- turn left
			local angles = self.go.data:get("angles")
			if (angles < 45) then
				cam:setWorldRotationAngles(0,angles+5,0)
				self.go.data:set("angles",angles+5)
			end
		end
		if g.keyDown("w") then -- raise the camera
			local offset = cam:getWorldPosition()
			local poffset = party:getWorldPosition()
			if (math.abs(offset.y - poffset.y) < 6) then
				cam:setWorldPosition(vec(offset.x,offset.y+0.5,offset.z))
			end
		end
		if g.keyDown("s") then -- lower the camera
			local offset = cam:getWorldPosition()
			local poffset = party:getWorldPosition()
			if (math.abs(offset.y - poffset.y) > 0.55) then
				cam:setWorldPosition(vec(offset.x,offset.y-0.5,offset.z))
			end
		end
		if g.keyDown("d") then -- zoom in
			local fov = cam.camera:getFov()
			if (fov > 10) then
				cam.camera:setFov(fov - 5)
			end
		end
		if g.keyDown("a") then -- zoom out
			local fov = cam.camera:getFov()
			if (fov < 130) then
				cam.camera:setFov(fov + 5)
			end
		end
	end
	return true
end

function onUseItem(self,champion)
	if (findEntity("timer_" .. self.go.id)) then
		-- a timer is already active: scope already in use!
		return false
	else
		-- spawn the timer and the camera
		local timer = spawn("scope_timer",party.level,party.x,party.y,party.facing,party.elevation,"timer_" .. self.go.id)
		local cam = spawn("scope_camera",party.level,party.x,party.y,party.facing,party.elevation)
		-- set the position and the offset of the camera
		local dx,dy = getForward(party.facing)
		cam:setPosition(party.x+5*dx,party.y+5*dy,party.facing,party.elevation,party.level)
		local offset = cam:getWorldPosition()
		cam:setWorldPosition(vec(offset.x,offset.y+1.5,offset.z))
		-- set camera field of view
		cam.camera:setFov(100)
		-- disable movement and mouse look
		GameMode.setGameFlag("DisableMovement",true)
		GameMode.setGameFlag("DisableMouseLook",true)
		-- start the custom camera
		GameMode.setCamera(cam.camera)
		-- tell the party which camera is active
		party.data:set("camera",cam.id)
		-- and reset its angles
		party.data:set("angles",0)
		-- "false" to prevent the scope to be "consumed"
		return false
	end
end
c) put in your dungeon a "new_scope" object; it works by right-clicking on it (i.e., using it). Be careful that it does not check whether you are inside a dungeon or outside, or if the place you are zooming to is "admissible" (the resolution of these problems is left as an exercise to the reader...).

Alois :)

Re: [Item] Functioning scope

Posted: Mon May 18, 2015 9:23 pm
by Duncan1246
alois wrote:Hi. While playing a little bit with custom cameras, I created a functioning "scope".

Alois :)
Wow! What a job! I definitely had to test this scope in my mod! Thanks
Duncan