finished Sprite_scopes (mostly)
This commit is contained in:
parent
b3e91825a5
commit
00ea0ff13e
15
classes/Bullet.lua
Normal file
15
classes/Bullet.lua
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
Bullet = Instantiatable_class:inherit({
|
||||
registered = {},
|
||||
range = 100,
|
||||
force_mmRHA = 1,
|
||||
dropoff_mmRHA = 0,
|
||||
damage = 0,
|
||||
itemstring = "",
|
||||
construct = function(def)
|
||||
assert(not def.instance, "attempt to create instance of a template")
|
||||
assert(rawget(def, "itemstring"), "no string provided to new bullet template")
|
||||
assert(minetest.registered_items[def.itemstring], "bullet item is not registered. Check dependencies?")
|
||||
|
||||
end
|
||||
})
|
@ -11,8 +11,6 @@ local ray = {
|
||||
ITERATION_DISTANCE = .3,
|
||||
damage = 0
|
||||
}
|
||||
function ray:validate_location()
|
||||
end
|
||||
|
||||
function ray:record_state()
|
||||
table.insert(self.history, {
|
||||
@ -115,10 +113,6 @@ function ray:cast()
|
||||
--set "last" values.
|
||||
return pointed, next_penetration_val, next_state, end_pos, continue
|
||||
end
|
||||
function ray:apply_damage(obj)
|
||||
local damage = math.floor((self.damage*(self.force_mmRHA/self.init_force_mmRHA))+1)
|
||||
obj:punch(self.player, nil, {damage_groups = {fleshy = damage, penetration_mmRHA=self.force_mmRHA}}, self.dir)
|
||||
end
|
||||
function ray:iterate(initialized)
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
local pointed, penetration, next_state, end_pos, continue = self:cast()
|
||||
@ -134,7 +128,7 @@ function ray:iterate(initialized)
|
||||
if pointed.type == "node" then
|
||||
self.last_node_name = minetest.get_node(pointed.under).name
|
||||
elseif pointed.type == "object" then
|
||||
ray:apply_damage(pointed.ref)
|
||||
ray:hit_entity(pointed.ref)
|
||||
end
|
||||
end
|
||||
table.insert(self.history, {
|
||||
@ -149,7 +143,7 @@ function ray:iterate(initialized)
|
||||
end
|
||||
if not initialized then
|
||||
for i, v in pairs(self.history) do
|
||||
--[[local hud = self.player:hud_add({
|
||||
local hud = self.player:hud_add({
|
||||
hud_elem_type = "waypoint",
|
||||
text = "mmRHA:"..tostring(math.floor(v.force_mmRHA or 0)).." ",
|
||||
number = 255255255,
|
||||
@ -161,7 +155,7 @@ function ray:iterate(initialized)
|
||||
})
|
||||
minetest.after(40, function(hud)
|
||||
self.player:hud_remove(hud)
|
||||
end, hud)]]
|
||||
end, hud)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -174,6 +168,8 @@ function ray.construct(def)
|
||||
assert(def.range, "no range")
|
||||
assert(def.force_mmRHA, "no force")
|
||||
assert(def.dropoff_mmRHA, "no force dropoff")
|
||||
--assert(def.on_node_hit, "no node hit behavior")
|
||||
assert(def.hit_entity, "no entity hit behavior")
|
||||
def.init_force_mmRHA = def.force_mmRHA
|
||||
def.dir = vector.new(def.dir)
|
||||
def.pos = vector.new(def.pos)
|
||||
|
@ -21,44 +21,63 @@ local controls = Guns4d.control_handler
|
||||
--[[-modify controls (future implementation if needed)
|
||||
function controls.modify()
|
||||
end]]
|
||||
--this function always ends up a mess. I rewrote it here 2 times,
|
||||
--and in 3dguns I rewrote it at least 3 times. It's always just...
|
||||
--impossible to understand. So if you see ALOT of comments, that's why.
|
||||
function controls:update(dt)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
self.player_pressed = self.player:get_player_control()
|
||||
local pressed = self.player_pressed
|
||||
local call_queue = {} --so I need to have a "call" queue so I can tell the functions the names of other active controls (busy_list)
|
||||
local busy_list = {} --list of controls that have their conditions met
|
||||
local busy_list = self.busy_list --list of controls that have their conditions met. Has to be reset at END of update, so on_use and on_secondary_use can be marked
|
||||
for i, control in pairs(self.controls) do
|
||||
local def = control
|
||||
local data = control.data
|
||||
local conditions_met = true
|
||||
for _, key in pairs(control.conditions) do
|
||||
if not pressed[key] then conditions_met = false break end
|
||||
end
|
||||
if not conditions_met then
|
||||
busy_list[i] = true
|
||||
data.held = false
|
||||
--detect interrupts
|
||||
if data.timer ~= def.timer then
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=true, data=data})
|
||||
data.timer = def.timer
|
||||
if not (i=="on_use") and not (i=="on_secondary_use") then
|
||||
local def = control
|
||||
local data = control.data
|
||||
local conditions_met = true
|
||||
--check no conditions are false
|
||||
for _, key in pairs(control.conditions) do
|
||||
if not pressed[key] then conditions_met = false break end
|
||||
end
|
||||
else
|
||||
data.timer = data.timer - dt
|
||||
--when time is over, if it wasnt held (or loop is active) then reset and call the function.
|
||||
if data.timer <= 0 and ((not data.held) or def.loop) then
|
||||
data.held = true
|
||||
table.insert(call_queue, {control=def, active=true, interrupt=false, data=data})
|
||||
elseif def.call_before_timer then
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=false, data=data})
|
||||
if conditions_met then
|
||||
data.timer = data.timer - dt
|
||||
--when time is over, if it wasnt held (or loop is active) then reset and call the function.
|
||||
--held indicates wether the function was called (as active) before last step.
|
||||
if data.timer <= 0 and ((not data.held) or def.loop) then
|
||||
data.held = true
|
||||
table.insert(call_queue, {control=def, active=true, interrupt=false, data=data})
|
||||
elseif def.call_before_timer then --this is useful for functionst that need to play animations for their progress.
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=false, data=data})
|
||||
end
|
||||
else
|
||||
busy_list[i] = true
|
||||
data.held = false
|
||||
--detect interrupts, check if the timer was in progress
|
||||
if data.timer ~= def.timer then
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=true, data=data})
|
||||
data.timer = def.timer
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local count = 0
|
||||
for i, v in pairs(busy_list) do
|
||||
count = count + 1
|
||||
end
|
||||
if count == 0 then busy_list = nil end --so funcs can quickly deduce if they can call
|
||||
--busy list is so we can tell if a function should be allowed or not
|
||||
if #busy_list == 0 then busy_list = nil end
|
||||
for i, tbl in pairs(call_queue) do
|
||||
tbl.control.func(tbl.active, tbl.interrupt, tbl.data, busy_list, Guns4d.players[self.player:get_player_name()].handler)
|
||||
tbl.control.func(tbl.active, tbl.interrupt, tbl.data, busy_list, self.handler)
|
||||
end
|
||||
self.busy_list = {}
|
||||
end
|
||||
function controls:on_use(itemstack, pointed_thing)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.controls.on_use then
|
||||
self.controls.on_use(itemstack, self.handler, pointed_thing)
|
||||
end
|
||||
end
|
||||
function controls:on_secondary_use(itemstack, pointed_thing)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.controls.on_secondary_use then
|
||||
self.controls.on_secondary_use(itemstack, self.handler, pointed_thing)
|
||||
end
|
||||
end
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
@ -67,12 +86,16 @@ function controls.construct(def)
|
||||
assert(def.controls, "no controls provided")
|
||||
assert(def.player, "no player provided")
|
||||
def.controls = table.deep_copy(def.controls)
|
||||
def.busy_list = {}
|
||||
def.handler = Guns4d.players[def.player:get_player_name()].handler
|
||||
for i, control in pairs(def.controls) do
|
||||
control.timer = control.timer or 0
|
||||
control.data = {
|
||||
timer = control.timer,
|
||||
held = false
|
||||
}
|
||||
if not (i=="on_use") and not (i=="on_secondary_use") then
|
||||
control.timer = control.timer or 0
|
||||
control.data = {
|
||||
timer = control.timer,
|
||||
held = false
|
||||
}
|
||||
end
|
||||
end
|
||||
table.sort(def.controls, function(a,b)
|
||||
return #a.conditions > #b.conditions
|
||||
|
218
classes/Gun.lua
218
classes/Gun.lua
@ -22,8 +22,8 @@ local gun = {
|
||||
player_axial = 1,
|
||||
},
|
||||
angular_velocity_max = {
|
||||
gun_axial = 2,
|
||||
player_axial = 2,
|
||||
gun_axial = 1,
|
||||
player_axial = 1,
|
||||
},
|
||||
angular_velocity = {
|
||||
gun_axial = {x=0, y=0},
|
||||
@ -34,8 +34,8 @@ local gun = {
|
||||
player_axial = {x=1, y=0},
|
||||
},
|
||||
target_correction_max_rate = { --the cap for time_since_fire*target_correction_factor
|
||||
gun_axial = 10000,
|
||||
player_axial = 10000,
|
||||
gun_axial = 1,
|
||||
player_axial = 1,
|
||||
},
|
||||
},
|
||||
sway = {
|
||||
@ -57,7 +57,7 @@ local gun = {
|
||||
firerateRPM = 10000,
|
||||
controls = {}
|
||||
},
|
||||
transforms = {
|
||||
offsets = {
|
||||
pos = Vec.new(),
|
||||
player_rotation = Vec.new(),
|
||||
dir = Vec.new(),
|
||||
@ -99,6 +99,7 @@ local gun = {
|
||||
--magic number BEGONE
|
||||
consts = {
|
||||
HIP_PLAYER_GUN_ROT_RATIO = .75,
|
||||
AIM_OUT_AIM_IN_SPEED_RATIO = 2.5,
|
||||
HIPFIRE_BONE = "guns3d_hipfire_bone",
|
||||
AIMING_BONE = "guns3d_aiming_bone",
|
||||
HAS_RECOIL = true,
|
||||
@ -112,10 +113,11 @@ local gun = {
|
||||
rechamber_time = 0,
|
||||
muzzle_flash = Guns4d.muzzle_flash
|
||||
}
|
||||
|
||||
function gun:fire()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.rechamber_time <= 0 then
|
||||
local dir = self:get_dir()
|
||||
local dir = self.dir
|
||||
local pos = self:get_pos()
|
||||
Guns4d.bullet_ray:new({
|
||||
player = self.player,
|
||||
@ -124,13 +126,18 @@ function gun:fire()
|
||||
range = 100,
|
||||
gun = self,
|
||||
force_mmRHA = 1,
|
||||
dropoff_mmRHA = 0
|
||||
dropoff_mmRHA = 0,
|
||||
hit_entity = function(pointed)
|
||||
local damage = math.floor((self.damage*(self.force_mmRHA/self.init_force_mmRHA))+1)
|
||||
pointed.ref:punch(self.player, nil, {damage_groups = {fleshy = damage, penetration_mmRHA=self.force_mmRHA}}, self.dir)
|
||||
end
|
||||
})
|
||||
self:recoil()
|
||||
self:muzzle_flash()
|
||||
self.rechamber_time = 60/self.properties.firerateRPM
|
||||
end
|
||||
end
|
||||
|
||||
function gun:recoil()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
for axis, recoil in pairs(self.velocities.recoil) do
|
||||
@ -140,34 +147,37 @@ function gun:recoil()
|
||||
end
|
||||
self.time_since_last_fire = 0
|
||||
end
|
||||
function gun:get_dir(gun_relative)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local player = self.player
|
||||
local player_rotation
|
||||
if gun_relative then
|
||||
player_rotation = Vec.new(gun_relative)
|
||||
else
|
||||
player_rotation = Vec.new(self.transforms.player_rotation.x, self.transforms.player_rotation.y, 0)
|
||||
end
|
||||
local rotation = self.transforms.total_offset_rotation
|
||||
local dir = Vec.new(Vec.rotate({x=0, y=0, z=1}, {y=0, x=((rotation.gun_axial.x+rotation.player_axial.x+player_rotation.x)*math.pi/180), z=0}))
|
||||
dir = Vec.rotate(dir, {y=((rotation.gun_axial.y+rotation.player_axial.y+player_rotation.y)*math.pi/180), x=0, z=0})
|
||||
--[[local hud_pos = dir+player:get_pos()+{x=0,y=player:get_properties().eye_height,z=0}+vector.rotate(player:get_eye_offset()/10, {x=0,y=player_rotation.y*math.pi/180,z=0})
|
||||
if not false then
|
||||
local hud = player:hud_add({
|
||||
hud_elem_type = "image_waypoint",
|
||||
text = "muzzle_flash2.png",
|
||||
world_pos = hud_pos,
|
||||
scale = {x=10, y=10},
|
||||
alignment = {x=0,y=0},
|
||||
offset = {x=0,y=0},
|
||||
})
|
||||
minetest.after(0, function(hud)
|
||||
player:hud_remove(hud)
|
||||
end, hud)
|
||||
end]]
|
||||
|
||||
function gun:get_dir(rltv)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local player = self.player
|
||||
local player_rotation
|
||||
if rltv then
|
||||
player_rotation = Vec.new()
|
||||
else
|
||||
player_rotation = Vec.new(self.offsets.player_rotation.x, self.offsets.player_rotation.y, 0)
|
||||
end
|
||||
local rotation = self.offsets.total_offset_rotation
|
||||
local dir = Vec.new(Vec.rotate({x=0, y=0, z=1}, {y=0, x=((rotation.gun_axial.x+rotation.player_axial.x+player_rotation.x)*math.pi/180), z=0}))
|
||||
dir = Vec.rotate(dir, {y=((rotation.gun_axial.y+rotation.player_axial.y+player_rotation.y)*math.pi/180), x=0, z=0})
|
||||
local hud_pos = dir+player:get_pos()+{x=0,y=player:get_properties().eye_height,z=0}+vector.rotate(player:get_eye_offset()/10, {x=0,y=player_rotation.y*math.pi/180,z=0})
|
||||
if not false then
|
||||
local hud = player:hud_add({
|
||||
hud_elem_type = "image_waypoint",
|
||||
text = "muzzle_flash2.png",
|
||||
world_pos = hud_pos,
|
||||
scale = {x=10, y=10},
|
||||
alignment = {x=0,y=0},
|
||||
offset = {x=0,y=0},
|
||||
})
|
||||
minetest.after(0, function(hud)
|
||||
player:hud_remove(hud)
|
||||
end, hud)
|
||||
end
|
||||
return dir
|
||||
end
|
||||
|
||||
|
||||
function gun:get_pos(added_pos)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
added_pos = Vec.new(added_pos)
|
||||
@ -175,18 +185,18 @@ function gun:get_pos(added_pos)
|
||||
local handler = self.handler
|
||||
local bone_location = Vec.new(handler.model_handler.offsets.arm.right)/10
|
||||
local gun_offset = Vec.new(self.properties.hip.offset)
|
||||
local player_rotation = Vec.new(self.transforms.player_rotation.x, self.transforms.player_rotation.y, 0)
|
||||
if handler.controls.ads then
|
||||
local player_rotation = Vec.new(self.offsets.player_rotation.x, self.offsets.player_rotation.y, 0)
|
||||
if handler.control_bools.ads then
|
||||
gun_offset = self.properties.ads.offset
|
||||
bone_location = Vec.new(0, handler:get_properties().eye_height, 0)+player:get_eye_offset()/10
|
||||
else
|
||||
--minetest is really wacky.
|
||||
bone_location.x = -bone_location.x
|
||||
player_rotation.x = self.transforms.player_rotation.x*self.consts.HIP_PLAYER_GUN_ROT_RATIO
|
||||
player_rotation.x = self.offsets.player_rotation.x*self.consts.HIP_PLAYER_GUN_ROT_RATIO
|
||||
end
|
||||
gun_offset = gun_offset+added_pos
|
||||
--dir needs to be rotated twice seperately to avoid weirdness
|
||||
local rotation = self.transforms.total_offset_rotation
|
||||
local rotation = self.offsets.total_offset_rotation
|
||||
local bone_pos = Vec.rotate(bone_location, {x=0, y=player_rotation.y*math.pi/180, z=0})
|
||||
local gun_offset = Vec.rotate(Vec.rotate(gun_offset, {x=(rotation.player_axial.x+player_rotation.x)*math.pi/180,y=0,z=0}), {x=0,y=(rotation.player_axial.y+player_rotation.y)*math.pi/180,z=0})
|
||||
--[[local hud_pos = bone_pos+gun_offset+handler:get_pos()
|
||||
@ -206,6 +216,7 @@ function gun:get_pos(added_pos)
|
||||
--world pos, position of bone, offset of gun from bone (with added_pos)
|
||||
return bone_pos+gun_offset+handler:get_pos(), bone_pos, gun_offset
|
||||
end
|
||||
|
||||
function gun:add_entity()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
self.entity = minetest.add_entity(self.player:get_pos(), self.name.."_visual")
|
||||
@ -213,21 +224,23 @@ function gun:add_entity()
|
||||
obj.parent_player = self.player
|
||||
obj:on_step()
|
||||
end
|
||||
|
||||
function gun:has_entity()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if not self.entity then return false end
|
||||
if not self.entity:get_pos() then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
--update the gun, da meat and da potatoes
|
||||
function gun:update(dt)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if not self:has_entity() then self:add_entity() end
|
||||
self.dir = self:get_dir()
|
||||
self.pos = self:get_pos()
|
||||
local handler = self.handler
|
||||
local look_rotation = {x=handler.look_rotation.x,y=handler.look_rotation.y}
|
||||
local total_rot = self.transforms.total_offset_rotation
|
||||
local player_rot = self.transforms.player_rotation
|
||||
local total_rot = self.offsets.total_offset_rotation
|
||||
local player_rot = self.offsets.player_rotation
|
||||
local constant = 1.4
|
||||
|
||||
--player look rotation
|
||||
@ -237,6 +250,7 @@ function gun:update(dt)
|
||||
else
|
||||
player_rot.x = look_rotation.x
|
||||
end
|
||||
--timers
|
||||
if self.rechamber_time > 0 then
|
||||
self.rechamber_time = self.rechamber_time - dt
|
||||
else
|
||||
@ -244,53 +258,29 @@ function gun:update(dt)
|
||||
end
|
||||
self.time_since_creation = self.time_since_creation + dt
|
||||
self.time_since_last_fire = self.time_since_last_fire + dt
|
||||
|
||||
--update some vectors
|
||||
if self.consts.HAS_SWAY then self:update_sway(dt) end
|
||||
if self.consts.HAS_RECOIL then self:update_recoil(dt) end
|
||||
if self.consts.HAS_BREATHING then self:update_breathing(dt) end
|
||||
if self.consts.HAS_WAG then self:update_wag(dt) end
|
||||
self.dir = self:get_dir()
|
||||
self.local_dir = self:get_dir(true)
|
||||
|
||||
--sprite scope
|
||||
if self.properties.sprite_scope then
|
||||
if not self.sprite_scope then
|
||||
self.sprite_scope = self.properties.sprite_scope:new({
|
||||
gun = self
|
||||
})
|
||||
end
|
||||
self.sprite_scope:update()
|
||||
end
|
||||
|
||||
player_rot.y = -handler.look_rotation.y
|
||||
local offsets = self.transforms
|
||||
local offsets = self.offsets
|
||||
total_rot.player_axial = offsets.recoil.player_axial + offsets.walking.player_axial + offsets.sway.player_axial + {x=offsets.breathing.player_axial,y=0,z=0} + {x=0,y=0,z=0}
|
||||
total_rot.gun_axial = offsets.recoil.gun_axial + offsets.walking.gun_axial + offsets.sway.gun_axial
|
||||
local dir = vector.gun
|
||||
if self.handler.controls.ads then
|
||||
if not self.useless_hud then
|
||||
self.useless_hud = {}
|
||||
self.useless_hud.reticle = self.player:hud_add{
|
||||
hud_elem_type = "image",
|
||||
position = {x=.5,y=.5},
|
||||
scale = {x=1.5,y=1.5},
|
||||
text = "gun_mrkr.png",
|
||||
}
|
||||
self.useless_hud.fore = self.player:hud_add{
|
||||
hud_elem_type = "image",
|
||||
position = {x=.5,y=.5},
|
||||
scale = {x=10,y=10},
|
||||
text = "scope_fore.png",
|
||||
}
|
||||
self.useless_hud.back = self.player:hud_add{
|
||||
hud_elem_type = "image",
|
||||
position = {x=.5,y=.5},
|
||||
scale = {x=10,y=10},
|
||||
text = "scope_back.png",
|
||||
}
|
||||
end
|
||||
local wininfo = minetest.get_player_window_information(self.player:get_player_name())
|
||||
if wininfo then
|
||||
local dir = self:get_dir({x=0,y=0,z=0})
|
||||
--local dir2 = self:get_dir({x=0,y=0,z=0})
|
||||
local ratio = wininfo.size.x/wininfo.size.y
|
||||
local v = Point_to_hud(dir, 80, ratio)
|
||||
self.player:hud_change(self.useless_hud.reticle, "position", {x=v.x, y=v.y})
|
||||
self.player:hud_change(self.useless_hud.fore, "position", {x=((v.x-.5)/1.1)+.5, y=((v.x-.5)/1.1)+.5})
|
||||
self.player:hud_change(self.useless_hud.back, "position", {x=((2*total_rot.player_axial.y/(80*2))+.5), y=(((2*total_rot.player_axial.x)/(80*2))+.5)})
|
||||
end
|
||||
elseif self.useless_hud then
|
||||
for i, v in pairs(self.useless_hud) do
|
||||
self.player:hud_remove(v)
|
||||
end
|
||||
self.useless_hud = nil
|
||||
end
|
||||
end
|
||||
function gun:update_wag(dt)
|
||||
local handler = self.handler
|
||||
@ -299,7 +289,7 @@ function gun:update_wag(dt)
|
||||
else
|
||||
self.walking_tick = 0
|
||||
end
|
||||
local walking_offset = self.transforms.walking
|
||||
local walking_offset = self.offsets.walking
|
||||
for _, i in pairs({"x","y"}) do
|
||||
for axis, _ in pairs(walking_offset) do
|
||||
if handler.walking then
|
||||
@ -325,9 +315,9 @@ function gun:update_wag(dt)
|
||||
end
|
||||
end
|
||||
function gun:update_recoil(dt)
|
||||
for axis, _ in pairs(self.transforms.recoil) do
|
||||
for axis, _ in pairs(self.offsets.recoil) do
|
||||
for _, i in pairs({"x","y"}) do
|
||||
local recoil = self.transforms.recoil[axis][i]
|
||||
local recoil = self.offsets.recoil[axis][i]
|
||||
local recoil_vel = math.clamp(self.velocities.recoil[axis][i],-self.properties.recoil.angular_velocity_max[axis],self.properties.recoil.angular_velocity_max[axis])
|
||||
local old_recoil_vel = recoil_vel
|
||||
recoil = recoil + recoil_vel
|
||||
@ -357,7 +347,7 @@ function gun:update_recoil(dt)
|
||||
end
|
||||
end
|
||||
self.velocities.recoil[axis][i] = recoil_vel
|
||||
self.transforms.recoil[axis][i] = recoil
|
||||
self.offsets.recoil[axis][i] = recoil
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -369,13 +359,13 @@ function gun:update_breathing(dt)
|
||||
local scale = 1
|
||||
--now if it's above math.pi we know it's in the pause half of the cycle. For smoothness, we cut the sine off early and decay the value linearly.
|
||||
if x > math.pi*(8/9) then
|
||||
self.transforms.breathing.player_axial=self.transforms.breathing.player_axial-(self.transforms.breathing.player_axial*2*dt)
|
||||
self.offsets.breathing.player_axial=self.offsets.breathing.player_axial-(self.offsets.breathing.player_axial*2*dt)
|
||||
else
|
||||
self.transforms.breathing.player_axial = scale*(math.sin(x))
|
||||
self.offsets.breathing.player_axial = scale*(math.sin(x))
|
||||
end
|
||||
end
|
||||
function gun:update_sway(dt)
|
||||
for axis, sway in pairs(self.transforms.sway) do
|
||||
for axis, sway in pairs(self.offsets.sway) do
|
||||
local sway_vel = self.velocities.sway[axis]
|
||||
local ran
|
||||
ran = Vec.apply(Vec.new(), function(i,v)
|
||||
@ -390,14 +380,16 @@ function gun:update_sway(dt)
|
||||
sway=Vec.normalize(sway)*self.properties.sway.max_angle[axis]
|
||||
sway_vel = Vec.new()
|
||||
end
|
||||
self.transforms.sway[axis] = sway
|
||||
self.offsets.sway[axis] = sway
|
||||
self.velocities.sway[axis] = sway_vel
|
||||
end
|
||||
end
|
||||
function gun:prepare_deletion()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self:has_entity() then self.entity:remove() end
|
||||
if self.sprite_scope then self.sprite_scope:prepare_deletion() end
|
||||
end
|
||||
--construction for the gun class
|
||||
gun.construct = function(def)
|
||||
if def.instance then
|
||||
--remember to give gun an id
|
||||
@ -412,11 +404,12 @@ gun.construct = function(def)
|
||||
else
|
||||
def.id = meta:get_string("guns4d_id")
|
||||
end
|
||||
--make sure there's nothing missing
|
||||
--make sure there's nothing missing, aka copy over all of the properties.
|
||||
def.properties = table.fill(gun.properties, def.properties)
|
||||
--Vecize
|
||||
def.transforms = table.deep_copy(gun.transforms)
|
||||
for i, tbl in pairs(def.transforms) do
|
||||
--so, we copy the offsets table so we have all of the offsets
|
||||
--then we create new vectors for gun_axial and player_axial.
|
||||
def.offsets = table.deep_copy(gun.offsets)
|
||||
for i, tbl in pairs(def.offsets) do
|
||||
if tbl.gun_axial and tbl.player_axial and (not i=="breathing") then
|
||||
tbl.gun_axial = Vec.new(tbl.gun_axial)
|
||||
tbl.player_axial = Vec.new(tbl.player_axial)
|
||||
@ -433,6 +426,26 @@ gun.construct = function(def)
|
||||
local props = def.properties
|
||||
assert(def.name, "no name provided")
|
||||
assert(def.itemstring, "no itemstring provided")
|
||||
assert(minetest.registered_items[def.itemstring], "item is not registered, check dependencies.")
|
||||
|
||||
--override methods so control handler can do it's job
|
||||
local old_on_use = minetest.registered_items[def.itemstring].on_use
|
||||
local old_on_s_use = minetest.registered_items[def.itemstring].on_secondary_use
|
||||
minetest.override_item(def.itemstring, {
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if old_on_use then
|
||||
old_on_use(itemstack, user, pointed_thing)
|
||||
end
|
||||
Guns4d.players[user:get_player_name()].handler.control_handler:on_use(itemstack, pointed_thing)
|
||||
end,
|
||||
on_secondary_use = function(itemstack, user, pointed_thing)
|
||||
if old_on_s_use then
|
||||
old_on_s_use(itemstack, user, pointed_thing)
|
||||
end
|
||||
Guns4d.players[user:get_player_name()].handler.control_handler:on_secondary_use(itemstack, pointed_thing)
|
||||
end
|
||||
})
|
||||
|
||||
--(this tableref is ephermeral after constructor is called, see instantiatable_class)
|
||||
Guns4d.gun.registered[def.name] = def
|
||||
minetest.register_entity(def.name.."_visual", {
|
||||
@ -454,19 +467,24 @@ gun.construct = function(def)
|
||||
if not lua_object then obj:remove() return end
|
||||
--this is changing the point of rotation if not aiming, this is to make it look less shit.
|
||||
local axial_modifier = Vec.new()
|
||||
if not handler.controls.ads then
|
||||
local pitch = lua_object.transforms.total_offset_rotation.player_axial.x+lua_object.transforms.player_rotation.x
|
||||
if not handler.control_bools.ads then
|
||||
local pitch = lua_object.offsets.total_offset_rotation.player_axial.x+lua_object.offsets.player_rotation.x
|
||||
axial_modifier = Vec.new(pitch*(1-lua_object.consts.HIP_PLAYER_GUN_ROT_RATIO),0,0)
|
||||
end
|
||||
local axial_rot = lua_object.transforms.total_offset_rotation.gun_axial+axial_modifier
|
||||
local axial_rot = lua_object.offsets.total_offset_rotation.gun_axial+axial_modifier
|
||||
--attach to the correct bone, and rotate
|
||||
if handler.controls.ads == false then
|
||||
local visibility = true
|
||||
if lua_object.sprite_scope and lua_object.sprite_scope.hide_gun and (not (handler.ads_location == 0)) then
|
||||
visibility = false
|
||||
end
|
||||
if handler.control_bools.ads then
|
||||
|
||||
local normal_pos = (props.ads.offset+Vec.new(props.ads.horizontal_offset,0,0))*10
|
||||
obj:set_attach(player, gun.consts.AIMING_BONE, normal_pos, -axial_rot, visibility)
|
||||
else
|
||||
local normal_pos = Vec.new(props.hip.offset)*10
|
||||
-- Vec.multiply({x=normal_pos.x, y=normal_pos.z, z=-normal_pos.y}, 10)
|
||||
obj:set_attach(player, gun.consts.HIPFIRE_BONE, normal_pos, -axial_rot, true)
|
||||
else
|
||||
local normal_pos = (props.ads.offset+Vec.new(props.ads.horizontal_offset,0,0))*10
|
||||
obj:set_attach(player, gun.consts.AIMING_BONE, normal_pos, -axial_rot, true)
|
||||
obj:set_attach(player, gun.consts.HIPFIRE_BONE, normal_pos, -axial_rot, visibility)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
@ -11,7 +11,7 @@ local player_handler = {
|
||||
--model_handler = player_model_handler
|
||||
look_rotation = {x=0, y=0},
|
||||
look_offset = Vec.new(),
|
||||
ads_location = 0,
|
||||
ads_location = 0, --interpolation scalar for gun aiming location
|
||||
controls = {},
|
||||
horizontal_offset = 0
|
||||
}
|
||||
@ -20,37 +20,54 @@ function player_handler:update(dt)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local player = self.player
|
||||
self.wielded_item = self.player:get_wielded_item()
|
||||
local held_gun = self:holding_gun() --get the gun class that is associated with the held gun
|
||||
local held_gun = self:is_holding_Gun() --get the gun class that is associated with the held gun
|
||||
if held_gun then
|
||||
--was there a gun last time? did the wield index change?
|
||||
local old_index = self.wield_index
|
||||
self.wield_index = player:get_wield_index()
|
||||
--if gun has changed or was not held, then reset.
|
||||
|
||||
--initialize all handlers and objects
|
||||
if (not self.gun) or (self.gun.id ~= self.wielded_item:get_meta():get_string("guns4d_id")) then
|
||||
--initialize all handlers
|
||||
----gun handler----
|
||||
|
||||
----gun (handler w/physical manifestation)----
|
||||
if self.gun then --delete gun object if present
|
||||
self.gun:prepare_deletion()
|
||||
self.gun = nil
|
||||
end
|
||||
self.gun = held_gun:new({itemstack=self.wielded_item, player=self.player, handler=self}) --this will set itemstack meta, and create the gun based off of meta and other data.
|
||||
|
||||
----model handler----
|
||||
if self.model_handler then --if model_handler present, then delete
|
||||
self.model_handler:prepare_deletion()
|
||||
self.model_handler = nil
|
||||
end
|
||||
self.model_handler = model_handler.get_handler(self:get_properties().mesh):new({player=self.player})
|
||||
|
||||
----control handler----
|
||||
self.control_handler = Guns4d.control_handler:new({player=player, controls=self.gun.properties.controls})
|
||||
--reinitialize some handler data and set set_hud_flags
|
||||
self.horizontal_offset = self.gun.properties.ads.horizontal_offset
|
||||
player:hud_set_flags({wielditem = false, crosshair = false})
|
||||
|
||||
end
|
||||
|
||||
--update some properties.
|
||||
self.look_rotation.x, self.look_rotation.y = player:get_look_vertical()*180/math.pi, -player:get_look_horizontal()*180/math.pi
|
||||
if TICK % 10 == 0 then
|
||||
self.wininfo = minetest.get_player_window_information(self.player:get_player_name())
|
||||
end
|
||||
|
||||
--update handlers
|
||||
self.gun:update(dt) --gun should be updated first so self.dir is available.
|
||||
self.control_handler:update(dt)
|
||||
self.model_handler:update(dt)
|
||||
self.gun:update(dt)
|
||||
|
||||
--this has to be checked after control handler
|
||||
if TICK % 4 == 0 then
|
||||
self.touching_ground = self:get_is_on_ground()
|
||||
self.walking = self:get_is_walking()
|
||||
end
|
||||
elseif self.gun then
|
||||
self.control_handler = nil
|
||||
--delete gun object
|
||||
@ -62,23 +79,22 @@ function player_handler:update(dt)
|
||||
self.model_handler = nil
|
||||
player:hud_set_flags({wielditem = true, crosshair = true}) --reenable hud elements
|
||||
end
|
||||
--eye offsets
|
||||
if self.controls.ads and (self.ads_location<1) then
|
||||
|
||||
--eye offsets and ads_location
|
||||
if self.control_bools.ads and (self.ads_location<1) then
|
||||
--if aiming, then increase ADS location
|
||||
self.ads_location = math.clamp(self.ads_location + (dt/self.gun.properties.aim_time), 0, 1)
|
||||
elseif (not self.controls.ads) and self.ads_location>0 then
|
||||
local divisor = .4
|
||||
elseif (not self.control_bools.ads) and self.ads_location>0 then
|
||||
local divisor = .2
|
||||
if self.gun then
|
||||
divisor = self.gun.properties.aim_time
|
||||
divisor = self.gun.properties.aim_time/self.gun.consts.AIM_OUT_AIM_IN_SPEED_RATIO
|
||||
end
|
||||
self.ads_location = math.clamp(self.ads_location - (dt/divisor), 0, 1)
|
||||
end
|
||||
|
||||
self.look_offset.x = self.horizontal_offset*self.ads_location
|
||||
player:set_eye_offset(self.look_offset*10)
|
||||
--some status stuff
|
||||
if TICK % 2 == 0 then
|
||||
self.touching_ground = self:get_is_on_ground()
|
||||
end
|
||||
self.walking = self:get_is_walking()
|
||||
--stored properties and pos must be reset as they could be outdated.
|
||||
self.properties = nil
|
||||
self.pos = nil
|
||||
@ -111,7 +127,10 @@ function player_handler:get_is_walking()
|
||||
else
|
||||
controls = self.control_handler.player_pressed
|
||||
end
|
||||
if (vector.length(vector.new(velocity.x, 0, velocity.z)) > .1) and (controls.up or controls.down or controls.left or controls.right) and self.touching_ground then
|
||||
if (vector.length(vector.new(velocity.x, 0, velocity.z)) > .1)
|
||||
and (controls.up or controls.down or controls.left or controls.right)
|
||||
and self.touching_ground
|
||||
then
|
||||
walking = true
|
||||
end
|
||||
return walking
|
||||
@ -119,7 +138,7 @@ end
|
||||
--resets the controls bools table for the player_handler
|
||||
function player_handler:reset_controls_table()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
self.controls = table.deep_copy(default_active_controls)
|
||||
self.control_bools = table.deep_copy(default_active_controls)
|
||||
end
|
||||
--doubt I'll ever use this... but just in case I don't want to forget.
|
||||
function player_handler:get_pos()
|
||||
@ -144,7 +163,7 @@ function player_handler:set_properties(properties)
|
||||
self.player:set_properties(properties)
|
||||
self.properties = table.fill(self.properties, properties)
|
||||
end
|
||||
function player_handler:holding_gun()
|
||||
function player_handler:is_holding_Gun()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.wielded_item then
|
||||
for name, obj in pairs(Guns4d.gun.registered) do
|
||||
@ -189,7 +208,7 @@ function player_handler.construct(def)
|
||||
end
|
||||
end
|
||||
def.look_rotation = table.deep_copy(player_handler.look_rotation)
|
||||
def.controls = table.deep_copy(default_active_controls)
|
||||
def.control_bools = table.deep_copy(default_active_controls)
|
||||
end
|
||||
end
|
||||
Guns4d.player_handler = Instantiatable_class:inherit(player_handler)
|
||||
|
@ -34,9 +34,9 @@ function player_model:update()
|
||||
local player = self.player
|
||||
local handler = Guns4d.players[player:get_player_name()].handler
|
||||
local gun = handler.gun
|
||||
local player_axial_offset = gun.transforms.total_offset_rotation.player_axial
|
||||
local pitch = player_axial_offset.x+gun.transforms.player_rotation.x
|
||||
local combined = player_axial_offset+gun.transforms.total_offset_rotation.gun_axial+Vec.new(gun.transforms.player_rotation.x,0,0)
|
||||
local player_axial_offset = gun.offsets.total_offset_rotation.player_axial
|
||||
local pitch = player_axial_offset.x+gun.offsets.player_rotation.x
|
||||
local combined = player_axial_offset+gun.offsets.total_offset_rotation.gun_axial+Vec.new(gun.offsets.player_rotation.x,0,0)
|
||||
local eye_pos = vector.new(0, handler:get_properties().eye_height*10, 0)
|
||||
player:set_bone_position("guns3d_hipfire_bone", self.offsets.arm.rltv_right, vector.new(-(pitch*gun.consts.HIP_PLAYER_GUN_ROT_RATIO), 180-player_axial_offset.y, 0))
|
||||
player:set_bone_position("guns3d_aiming_bone", eye_pos, vector.new(pitch, 180-player_axial_offset.y, 0))
|
||||
|
88
classes/Sprite_scope.lua
Normal file
88
classes/Sprite_scope.lua
Normal file
@ -0,0 +1,88 @@
|
||||
Sprite_scope = Instantiatable_class:inherit({
|
||||
images = {
|
||||
fore = {
|
||||
texture = "scope_fore.png",
|
||||
scale = {x=10,y=10},
|
||||
movement_multiplier = 1,
|
||||
},
|
||||
back = {
|
||||
texture = "scope_back.png",
|
||||
scale = {x=10,y=10},
|
||||
movement_multiplier = -1,
|
||||
},
|
||||
reticle = {
|
||||
texture = "gun_mrkr.png",
|
||||
scale = {x=1,y=1},
|
||||
movement_multiplier = 1,
|
||||
misalignment_opacity_threshold_angle = 3,
|
||||
misalignment_opacity_maximum_angle = 8,
|
||||
},
|
||||
--mask = "blank.png",
|
||||
},
|
||||
hide_gun = true,
|
||||
construct = function(def)
|
||||
if def.instance then
|
||||
assert(def.gun, "no gun instance provided")
|
||||
def.player = def.gun.player
|
||||
def.handler = def.gun.handler
|
||||
def.elements = {}
|
||||
local new_images = table.deep_copy(def.images)
|
||||
if def.images then
|
||||
def.images = table.fill(new_images, def.images)
|
||||
end
|
||||
def.elements.reticle = def.player:hud_add{
|
||||
hud_elem_type = "image",
|
||||
position = {x=.5,y=.5},
|
||||
scale = def.images.reticle.scale,
|
||||
text = "blank.png",
|
||||
}
|
||||
def.elements.fore = def.player:hud_add{
|
||||
hud_elem_type = "image",
|
||||
position = {x=.5,y=.5},
|
||||
scale = def.images.fore.scale,
|
||||
text = "blank.png",
|
||||
}
|
||||
def.elements.back = def.player:hud_add{
|
||||
hud_elem_type = "image",
|
||||
position = {x=.5,y=.5},
|
||||
scale = def.images.back.scale,
|
||||
text = "blank.png",
|
||||
}
|
||||
end
|
||||
end
|
||||
})
|
||||
function Sprite_scope:update()
|
||||
local handler = self.handler
|
||||
if handler.wininfo and self.handler.control_bools.ads then
|
||||
local dir = self.gun.local_dir
|
||||
local ratio = handler.wininfo.size.x/handler.wininfo.size.y
|
||||
local added_pos
|
||||
if handler.ads_location ~= 1 then
|
||||
dir = dir + (self.gun.properties.ads.offset+vector.new(self.gun.properties.ads.horizontal_offset,0,0))*0
|
||||
end
|
||||
local v = Point_to_hud(dir, 80, ratio)
|
||||
self.player:hud_change(self.elements.reticle, "position", {x=(v.x*self.images.reticle.movement_multiplier)+.5, y=(v.y*self.images.reticle.movement_multiplier)+.5})
|
||||
self.player:hud_change(self.elements.fore, "position", {x=(v.x*self.images.fore.movement_multiplier)+.5, y=(v.y*self.images.fore.movement_multiplier)+.5})
|
||||
self.player:hud_change(self.elements.back, "position", {x=(v.x*self.images.back.movement_multiplier)+.5, y=(v.y*self.images.back.movement_multiplier)+.5})
|
||||
--update textures
|
||||
end
|
||||
for i, v in pairs(self.elements) do
|
||||
local def = self.images[i]
|
||||
local tex = def.texture
|
||||
--"smoother is better" it's not. Apparently, this creates a new image each time. It is, however, cached. So i'd rather have
|
||||
--25 possible images, instead of 255.
|
||||
local factor = 1
|
||||
if def.misalignment_opacity_threshold_angle then
|
||||
local angle = math.sqrt(self.gun.offsets.total_offset_rotation.gun_axial.x^2+self.gun.offsets.total_offset_rotation.gun_axial.y^2)
|
||||
if def.misalignment_opacity_threshold_angle < angle then
|
||||
factor = (factor - ((angle-def.misalignment_opacity_threshold_angle)/def.misalignment_opacity_maximum_angle))
|
||||
end
|
||||
end
|
||||
self.player:hud_change(v, "text", tex.."^[opacity:"..tostring(math.ceil((25.5*handler.ads_location*factor))*10))
|
||||
end
|
||||
end
|
||||
function Sprite_scope:prepare_deletion()
|
||||
for i, v in pairs(self.elements) do
|
||||
self.player:hud_remove(v)
|
||||
end
|
||||
end
|
1
docs/known bugs.txt
Normal file
1
docs/known bugs.txt
Normal file
@ -0,0 +1 @@
|
||||
when spamming on_use, sometimes RMB in get_player_control will become stuck
|
38
docs/required_features.txt
Normal file
38
docs/required_features.txt
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
VFX, SFX:
|
||||
Bullet hit node FX (steal mostly from 3dguns)
|
||||
Bullet fly-by SFX
|
||||
HUD system (most can once again be pulled from 3dguns)
|
||||
reload progress
|
||||
ammunition left
|
||||
ammo type
|
||||
gun animations (take 3dguns as an example, then completely rewrite)
|
||||
+player model & gun model reading
|
||||
gun sounds
|
||||
|
||||
gun features
|
||||
firemodes
|
||||
gun ammo:
|
||||
magazine relaoding
|
||||
fractional reloading
|
||||
magless flat reload
|
||||
!!fix gimbal lock (ironsights broken)
|
||||
"3d" optics
|
||||
attachments (last before beta)
|
||||
fix shooting through walls be pressing against them
|
||||
|
||||
bullets
|
||||
bullet class system
|
||||
add blunt force properties
|
||||
on_hitnode function callback
|
||||
|
||||
|
||||
auxillary (beta+/never)
|
||||
player hitboxes
|
||||
|
||||
server to client lag prediction
|
||||
possible user CSM for lag prediction
|
||||
bullet drop (maybe bullet wind?)
|
||||
bullet tracers
|
||||
inverse kinematics
|
||||
stamina
|
310
docs/structure_spec (app.diagrams.net).drawio
Normal file
310
docs/structure_spec (app.diagrams.net).drawio
Normal file
@ -0,0 +1,310 @@
|
||||
<mxfile host="app.diagrams.net" modified="2023-08-08T02:26:17.905Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36" etag="44jzb9uK1u4jJbBgrsUi" version="21.6.6" type="device">
|
||||
<diagram name="Page-1" id="hjH4469px_Ex89IZIbiB">
|
||||
<mxGraphModel dx="1049" dy="561" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-12">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="520" y="680" />
|
||||
<mxPoint x="405" y="680" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-12" value="Instantiate" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="XBcHE4cyeVAlC1C74syX-11">
|
||||
<mxGeometry x="0.4996" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-102" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;entryX=0.25;entryY=0;entryDx=0;entryDy=0;exitX=0.75;exitY=1;exitDx=0;exitDy=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-73" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="676" y="630" as="sourcePoint" />
|
||||
<mxPoint x="714" y="775" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="550" y="720" />
|
||||
<mxPoint x="700" y="720" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-5" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="740" y="580" as="targetPoint" />
|
||||
<mxPoint x="830" y="545" as="sourcePoint" />
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-15" value="Creates and updates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="W6xmUVEbs_vsLZUt_kYx-10">
|
||||
<mxGeometry x="-0.261" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-5" target="W6xmUVEbs_vsLZUt_kYx-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-37" value="Creates &amp; updates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="W6xmUVEbs_vsLZUt_kYx-11" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.3348" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="-17" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-5" target="W6xmUVEbs_vsLZUt_kYx-14" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="820" y="510" as="sourcePoint" />
|
||||
<mxPoint x="950" y="580" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="990" y="510" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-61" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0;entryDx=0;entryDy=0;fillColor=#d80073;strokeColor=#A50040;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-5" target="W6xmUVEbs_vsLZUt_kYx-14" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="960" y="530" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-64" value="Pass gun controls def" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="W6xmUVEbs_vsLZUt_kYx-61" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.3137" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-5" value="Player handler" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="680" y="480" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-9" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="600" y="560" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-32" value="Bone info" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="W6xmUVEbs_vsLZUt_kYx-28" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1556" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="-12" y="1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-72" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.582;entryY=-0.003;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryPerimeter=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-71" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="520" y="680" />
|
||||
<mxPoint x="590" y="680" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0;entryDx=0;entryDy=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-71" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="550" y="670" />
|
||||
<mxPoint x="550" y="670" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-78" value="Bone info &amp;<br>gun direction" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="W6xmUVEbs_vsLZUt_kYx-77" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1298" y="-2" relative="1" as="geometry">
|
||||
<mxPoint y="-5" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-75" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-73" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="520" y="680" />
|
||||
<mxPoint x="730" y="680" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-76" value="Creates &amp; updates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="W6xmUVEbs_vsLZUt_kYx-75" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.8968" y="-1" relative="1" as="geometry">
|
||||
<mxPoint x="1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-95" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;entryX=0.875;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-8" target="W6xmUVEbs_vsLZUt_kYx-88" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-8" value="Gun" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="460" y="580" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-9" value="model handler" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="680" y="580" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="W6xmUVEbs_vsLZUt_kYx-12" target="W6xmUVEbs_vsLZUt_kYx-19">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-12" value="Bullet ray(s)" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="345" y="790" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.75;entryDx=0;entryDy=0;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-14" target="W6xmUVEbs_vsLZUt_kYx-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="990" y="660" />
|
||||
<mxPoint x="615" y="660" />
|
||||
<mxPoint x="615" y="625" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-7" value="call :fire() or other methods" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="wAXQPkzS34ZOuWmKrVVe-5" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.0751" relative="1" as="geometry">
|
||||
<mxPoint x="-20" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-14" value="Control handler" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="930" y="580" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" target="W6xmUVEbs_vsLZUt_kYx-5" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="740" y="330" as="sourcePoint" />
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-35" value="Creates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="W6xmUVEbs_vsLZUt_kYx-17" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.1753" y="2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-16" value="on joinplayer" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="680" y="270" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-19" value="Target or node" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="260" y="790" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-38" value="Creates &amp; updates" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="869.9966666666667" y="510" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-58" target="W6xmUVEbs_vsLZUt_kYx-121" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-58" value="Gun class" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;" parent="1" vertex="1">
|
||||
<mxGeometry x="867.5" y="245" width="80" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.385;entryY=0.052;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="W6xmUVEbs_vsLZUt_kYx-67" target="W6xmUVEbs_vsLZUt_kYx-83">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-67" value="attachments" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
|
||||
<mxGeometry x="1045" y="230" width="80" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-71" value="Sprite scope" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="520" y="790" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-73" value="Physical scope" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
|
||||
<mxGeometry x="670" y="790" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-83" target="W6xmUVEbs_vsLZUt_kYx-121" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-35" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-88" target="W6xmUVEbs_vsLZUt_kYx-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-10" value="Predict client<br>view or request<br>directly" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="wAXQPkzS34ZOuWmKrVVe-35">
|
||||
<mxGeometry x="-0.1935" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-88" value="External server side modifications" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
|
||||
<mxGeometry x="210" y="565" width="135" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-109" value="<h1><i><u>guns4d structure specification diagram</u></i></h1>" style="text;html=1;strokeColor=#FFFFFF;fillColor=#fff2cc;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;align=center;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="30" width="510" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-114" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="90" width="120" height="250" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-115" value="process" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="50" y="110" width="100" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-118" value="class&nbsp; &nbsp; &nbsp; &nbsp;" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;" parent="1" vertex="1">
|
||||
<mxGeometry x="50" y="165" width="100" height="45" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-120" value="Instance" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="50" y="230" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-121" value="<font style="font-size: 12px;"><span style="background-color: rgb(255, 255, 255);">create correct gun by finding correct class and modifying properties by item metadata</span></font>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="835" y="375" width="145" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-127" value="" style="endArrow=classic;startArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="W6xmUVEbs_vsLZUt_kYx-5" target="W6xmUVEbs_vsLZUt_kYx-121" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="775" y="460" as="sourcePoint" />
|
||||
<mxPoint x="825" y="410" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="770" y="455" />
|
||||
<mxPoint x="770" y="415" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-130" value="inactive" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=#C3ABD0;fillColor=#e1d5e7;" parent="1" vertex="1">
|
||||
<mxGeometry x="50" y="290" width="100" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.991;entryY=0.611;entryDx=0;entryDy=0;entryPerimeter=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1226.08" y="609.92" as="sourcePoint" />
|
||||
<mxPoint x="1050.0000000000005" y="609.5799999999998" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1226.08" y="609.92" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-17" value="Player controls" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="wAXQPkzS34ZOuWmKrVVe-21">
|
||||
<mxGeometry x="0.0076" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1260" y="449.9999999999999" as="targetPoint" />
|
||||
<mxPoint x="1260" y="530" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-131" value="Gun holder" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="1235" y="540" width="50" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-8" value="" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;rotation=-180;position2=1;base=45;strokeColor=none;fillColor=#fff2cc;" parent="1" vertex="1">
|
||||
<mxGeometry x="800" y="670" width="120" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-11" value="<font style="font-size: 8px;">Note that this is the behavior from the API layer (via properties.controls), but in the base class there's no interaction between these two components by default</font>" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="800" y="710" width="115" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W6xmUVEbs_vsLZUt_kYx-83" value="held item string and metadata" style="ellipse;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="1045" y="380" width="105" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" target="W6xmUVEbs_vsLZUt_kYx-83" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1200" y="414.9999999999999" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-43" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.75;entryY=0;entryDx=0;entryDy=0;exitX=0.181;exitY=0.967;exitDx=0;exitDy=0;exitPerimeter=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="wAXQPkzS34ZOuWmKrVVe-42" target="W6xmUVEbs_vsLZUt_kYx-14" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="1225" y="448" />
|
||||
<mxPoint x="1225" y="510" />
|
||||
<mxPoint x="1020" y="510" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-45" value="on_use (etc) <br>callbacks" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="wAXQPkzS34ZOuWmKrVVe-43" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.0218" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="wAXQPkzS34ZOuWmKrVVe-42" value="Item / Itemstack" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="1200" y="390" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="497.5" y="470" as="sourcePoint" />
|
||||
<mxPoint x="497" y="580" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-9" value="Bullet definition" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="XBcHE4cyeVAlC1C74syX-8">
|
||||
<mxGeometry x="-0.6286" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-7" value="held item string and metadata" style="ellipse;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
|
||||
<mxGeometry x="445" y="400" width="105" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="XBcHE4cyeVAlC1C74syX-18" target="XBcHE4cyeVAlC1C74syX-7">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="XBcHE4cyeVAlC1C74syX-18" value="Bullet class" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="457.5" y="230" width="80" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
92
docs/using controls.txt
Normal file
92
docs/using controls.txt
Normal file
@ -0,0 +1,92 @@
|
||||
This document contains (hopefully) all you need to know about
|
||||
the control_handler, and any other relevant input systems
|
||||
|
||||
The control system is designed to be simple but versatile,
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
basic information
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
IMPORTANT: `on_use` and `on_secondary_use` are RESERVED indexes. They
|
||||
have different behaviors and function parameters. (see special actions)
|
||||
|
||||
control action example:
|
||||
------------------------------------------------------------------------
|
||||
(The default aim taken from gun_api.lua)
|
||||
aim = {
|
||||
conditions = {"RMB"},
|
||||
loop = false,
|
||||
timer = 0,
|
||||
func = function(active, interrupted, data, busy_list, handler)
|
||||
if active then
|
||||
handler.control_bools.ads = not handler.control_bools.ads
|
||||
end
|
||||
end
|
||||
},
|
||||
------------------------------------------------------------------------
|
||||
|
||||
here's the breakdown:
|
||||
|
||||
`conditions = {"RMB"}` is the list of conditions (see get_player_control
|
||||
in minetest's lua_api.txt) that need to be fufulled for the control to
|
||||
be activated
|
||||
|
||||
`timer = 0` tells the handler that if condtions are met for 0 seconds
|
||||
that it is active.
|
||||
|
||||
`loop = false` indicates the it only will call once if the key(s) are
|
||||
held for the the specified amount of time `timer = 0`. In short, this
|
||||
tells the handler to run the function one time instead of calling it
|
||||
in (as the name implies) a loop.
|
||||
|
||||
additional properties:
|
||||
|
||||
`call_before_timer = false` if true, then the handler calls the function
|
||||
while the timer is in progress, this is very useful if you want something
|
||||
like a reload animation, or maybe a bow with a cocking animation, etc.
|
||||
use the function parameters (as follows) for better information.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
standard function parameters
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
function parameters for normal actions (see special actions)
|
||||
|
||||
`active` indicates wether conditions or timers were met/finished, the
|
||||
function can be called for reasons other then conditions being finished.
|
||||
use this to check if you actually want to do an action (such as firing)
|
||||
or finalizing reloads.
|
||||
|
||||
`interrupted` indicates if conditions were no longer met while the timer
|
||||
was in progress. This cannot not be called with active as true.
|
||||
|
||||
`data` is actually the Control_handler's table for the control action,
|
||||
it has `timer` which is the time left on the action and `held` which
|
||||
indicates if the keyboard and mouse conditions are met.
|
||||
|
||||
`busy_list` is a list of other active actions, use this if you want to
|
||||
only act if
|
||||
|
||||
`handler` is the Player_handler, this is guns4d's *everything* handler.
|
||||
to get the gun use `handler.gun`, to get the player use `handler.player`
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
special action
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
The indexes `on_use` and `on_secondary_use` are reserved for calls from
|
||||
the default on_use and on_secondary_use of tools. By default, the on_use
|
||||
and on_secondary_use of the itemstring provided is overwritten to contain
|
||||
this call.
|
||||
|
||||
set these as functions (with the following parameters) for on_use and
|
||||
on_secondary_use. It's not set in busy list by defaults, so if you
|
||||
wish (or otherwise need to) add a `self.busy_list.on_use = true` to it.
|
||||
note that the busy list is cleared each update by default.
|
||||
|
||||
function parameters:
|
||||
`itemstack`, `handler`, `pointed_thing`
|
||||
see lua_api.txt for details on `itemstack` and `pointed_thing` and
|
||||
see "standard function parameters" for handler info.
|
||||
|
28
gun_api.lua
28
gun_api.lua
@ -29,8 +29,8 @@ local default_def = {
|
||||
player_axial = 0,
|
||||
},
|
||||
angular_velocity = {
|
||||
gun_axial = {x=.2, y=.25},
|
||||
player_axial = {x=.25, y=.4},
|
||||
gun_axial = {x=.1, y=.1},
|
||||
player_axial = {x=.1, y=.1},
|
||||
},
|
||||
},
|
||||
firerateRPM = 600,
|
||||
@ -41,7 +41,7 @@ local default_def = {
|
||||
timer = 0,
|
||||
func = function(active, interrupted, data, busy_list, handler)
|
||||
if active then
|
||||
handler.controls.ads = not handler.controls.ads
|
||||
handler.control_bools.ads = not handler.control_bools.ads
|
||||
end
|
||||
end
|
||||
},
|
||||
@ -50,9 +50,17 @@ local default_def = {
|
||||
loop = true,
|
||||
timer = 0,
|
||||
func = function(active, interrupted, data, busy_list, handler)
|
||||
handler.gun:fire()
|
||||
if not handler.control_handler.busy_list.on_use then
|
||||
handler.gun:fire()
|
||||
end
|
||||
print(handler.control_handler.busy_list.on_use)
|
||||
end
|
||||
}
|
||||
},
|
||||
on_use = function(itemstack, handler, pointed_thing)
|
||||
print("use")
|
||||
handler.gun:fire()
|
||||
handler.control_handler.busy_list.on_use = true
|
||||
end
|
||||
},
|
||||
consts = {
|
||||
HIP_PLAYER_GUN_ROT_RATIO = .6
|
||||
@ -85,10 +93,12 @@ function Guns4d.register_gun_default(def)
|
||||
--validate controls
|
||||
if new_def.properties.controls then
|
||||
for i, control in pairs(new_def.properties.controls) do
|
||||
assert(control.conditions, "no conditions provided for control")
|
||||
for _, condition in pairs(control.conditions) do
|
||||
if not valid_ctrls[condition] then
|
||||
assert(false, "invalid key: '"..condition.."'")
|
||||
if not (i=="on_use") and not (i=="on_secondary_use") then
|
||||
assert(control.conditions, "no conditions provided for control")
|
||||
for _, condition in pairs(control.conditions) do
|
||||
if not valid_ctrls[condition] then
|
||||
assert(false, "invalid key: '"..condition.."'")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
8
init.lua
8
init.lua
@ -11,6 +11,7 @@ path = path .. "/classes"
|
||||
dofile(path.."/Instantiatable_class.lua")
|
||||
dofile(path.."/Bullet_ray.lua")
|
||||
dofile(path.."/Control_handler.lua")
|
||||
dofile(path.."/Sprite_scope.lua")
|
||||
dofile(path.."/Gun.lua")
|
||||
dofile(path.."/Player_model_handler.lua")
|
||||
dofile(path.."/Player_handler.lua")
|
||||
@ -18,11 +19,7 @@ dofile(path.."/Player_handler.lua")
|
||||
--load after
|
||||
path = minetest.get_modpath("guns4d")
|
||||
|
||||
|
||||
local player_handler = Guns4d.player_handler
|
||||
local gun = Guns4d.gun
|
||||
|
||||
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local pname = player:get_player_name()
|
||||
@ -31,11 +28,14 @@ minetest.register_on_joinplayer(function(player)
|
||||
}
|
||||
player:set_fov(80)
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local pname = player:get_player_name()
|
||||
Guns4d.players[pname].handler:prepare_deletion()
|
||||
Guns4d.players[pname] = nil
|
||||
end)
|
||||
|
||||
--ticks are rarely used, but still ideal for rare checks with minimal overhead.
|
||||
TICK = 0
|
||||
minetest.register_globalstep(function(dt)
|
||||
TICK = TICK + 1
|
||||
|
@ -150,5 +150,5 @@ function Point_to_hud(pos, fov, aspect)
|
||||
local x = (pos.x/pos.z)*a1
|
||||
local y = (pos.y/pos.z)*a6
|
||||
local z = (pos.z/pos.z)*a11
|
||||
return vector.new((x / 2)+.5, (-y / 2)+.5, z)
|
||||
return vector.new(x / 2, -y / 2, z)
|
||||
end
|
0
register_magazine.lua
Normal file
0
register_magazine.lua
Normal file
@ -4,7 +4,7 @@ function Guns4d.muzzle_flash(self)
|
||||
if self.particle_spawners.muzzle_smoke and self.particle_spawners.muzzle_smoke ~= -1 then
|
||||
minetest.delete_particlespawner(self.particle_spawners.muzzle_smoke, self.player:get_player_name())
|
||||
end
|
||||
local dir, offset_pos = self:get_dir(), self:get_pos(self.properties.flash_offset)
|
||||
local dir, offset_pos = self.dir, self:get_pos(self.properties.flash_offset)
|
||||
offset_pos=offset_pos+self.player:get_pos()
|
||||
local min = vector.rotate(vector.new(-2, -2, -.3), vector.dir_to_rotation(dir))
|
||||
local max = vector.rotate(vector.new(2, 2, .3), vector.dir_to_rotation(dir))
|
||||
|
Loading…
x
Reference in New Issue
Block a user