--[[ This file is part of Ice Lua Components. Ice Lua Components is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Ice Lua Components is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Ice Lua Components. If not, see . ]] print("pkg/base/client_start.lua starting") print(...) USE_GLSL = true USE_FBO = true if not client.glsl_create then USE_GLSL = false end if not client.gfx_fbo_available then USE_FBO = false end map_fname = nil frame_delay_ctr = 0.0001 render_sec_current = nil VA_TEST = false -- Ensure we have VA support if VA_TEST then if not common.va_make then VA_TEST = false end end -- yeah this really should happen ASAP so we can boot people who suck dofile("pkg/base/lib_util.lua") -- Get the clientside VM up dofile("pkg/base/lib_cside.lua") --dofile("pkg/base/serpent.lua") -- serpent.block is a great debugging aid local loose, user_toggles, user_settings = parse_commandline_options({...}) local user_config_filename = user_settings['user'] or "clsave/pub/user.json" local controls_config_filename = user_settings['controls'] or "clsave/pub/controls.json" -- FIXME: we don't expose documentation for valid user settings anywhere user_config = common.json_load(user_config_filename) if MODE_NUB_KICKONJOIN and user_config.kick_on_join then error([[ Edit your clsave/pub/user.json file, and set kick_on_join to false.]]) end print("json done!") print("name:", user_config.name) print("bio desc:", user_config.bio and user_config.bio.description) if user_config.frame_limit and user_config.frame_limit > 0.01 then frame_delay_ctr = 1.0 / user_config.frame_limit if frame_delay_ctr <= 0.0001 then frame_delay_ctr = 0.0001 end print("frame delay:", frame_delay_ctr) end if user_config.glsl_shaders == false then USE_GLSL = false end if USE_GLSL then local ver = client.gfx_glsl_available() if ver == nil then USE_GLSL = false USE_GLSL_20 = false USE_GLSL_21 = false elseif ver == "2.0" then USE_GLSL_20 = true USE_GLSL_21 = false elseif ver == "2.1" then USE_GLSL_20 = true USE_GLSL_21 = true else -- For now assume we have GL 2.1 or higher. USE_GLSL_20 = true USE_GLSL_21 = true end dofile("pkg/base/lib_shader.lua") else function shader_new() return nil, "Shaders not supported by this GPU" end function shader_push_nil() end function shader_pop_nil() end end if not USE_GLSL then USE_FBO = false end if USE_FBO then print("FBO availability:", client.gfx_fbo_available()) if not client.gfx_fbo_available() then USE_FBO = false end end if USE_FBO then fbo_world = client.fbo_create(screen_width, screen_height, true) print("FBO:", fbo_world) end -- speed through stuff FAST_LOCAL_INIT = user_config.fast_load_screen if FAST_LOCAL_INIT and sandbox then sandbox.gfx_select(nil) end -- OK, *NOW* we can load stuff. dofile("pkg/base/lib_va.lua") dofile("pkg/base/common.lua") dofile("pkg/base/border.lua") dofile("pkg/base/lib_crosshair.lua") tracers = {head = 1, tail = 0, time = 0} client_tick_accum = 0. map_fname = "*MAP" if common.version.num < 5 then error("Your version is too old! Please upgrade to 0.0-5 at least!") end if common.version.num >= 19 and common.version.num <= 21 then error("0.0-19 through 0.0-21 have an incomplete OpenGL renderer. Due to the potential abuse, these versions are not allowed. Please upgrade to 0.0-22 at the least!") end -- define keys controls_config = common.json_load(controls_config_filename) or {} BTSK_FORWARD = controls_config.forward or SDLK_w BTSK_BACK = controls_config.back or SDLK_s BTSK_LEFT = controls_config.left or SDLK_a BTSK_RIGHT = controls_config.right or SDLK_d BTSK_JUMP = controls_config.jump or SDLK_SPACE BTSK_CROUCH = controls_config.crouch or SDLK_LCTRL BTSK_SNEAK = controls_config.sneak or SDLK_v BTSK_RELOAD = controls_config.reload or SDLK_r BTSK_CHATUP = controls_config.chatup or SDLK_PAGEUP BTSK_CHATDN = controls_config.chatdn or SDLK_PAGEDOWN BTSK_TOOLS = {} do local i local defvals = {49,50,51,52,53,54,55,56,57,48} for i=1,10 do BTSK_TOOLS[i] = (controls_config.tools and controls_config.tools[i]) or controls_config["tool"..i] or defvals[i] end end BTSK_TOOLLAST = controls_config.toollast or SDLK_q BTSK_COLORLEFT = controls_config.colorleft or SDLK_LEFT BTSK_COLORRIGHT = controls_config.colorright or SDLK_RIGHT BTSK_COLORUP = controls_config.colorup or SDLK_UP BTSK_COLORDOWN = controls_config.colordown or SDLK_DOWN BTSK_CHAT = controls_config.chat or SDLK_t BTSK_COMMAND = SDLK_SLASH BTSK_TEAMCHAT = controls_config.teamchat or SDLK_y BTSK_SQUADCHAT = controls_config.squadchat or SDLK_u BTSK_SCORES = controls_config.scores or SDLK_TAB BTSK_QUIT = controls_config.quit or SDLK_ESCAPE BTSK_YES = SDLK_y BTSK_NO = SDLK_n BTSK_SCREENSHOT = SDLK_F3 BTSK_DEBUG = SDLK_F1 BTSK_MAP = controls_config.map or SDLK_m BTSK_TEAM = controls_config.team or SDLK_COMMA BTSK_WPN = controls_config.wpn or SDLK_PERIOD --[[ For user messages and hooking up GUI elements, we have a need for mapping the key variables to names and back. We also need to seperate the internal names with the natural-language descriptions. (Someday desc could be localized.) ]] button_map = { forward={key=BTSK_FORWARD,desc="Forward"}, back={key=BTSK_BACK,desc="Back"}, left={key=BTSK_LEFT,desc="Left"}, right={key=BTSK_RIGHT,desc="Right"}, jump={key=BTSK_JUMP,desc="Jump"}, crouch={key=BTSK_CROUCH,desc="Crouch"}, sneak={key=BTSK_SNEAK,desc="Sneak"}, reload={key=BTSK_RELOAD,desc="Reload"}, color_left={key=BTSK_COLORLEFT,desc="Color Left"}, color_right={key=BTSK_COLORRIGHT,desc="Color Right"}, color_up={key=BTSK_COLORUP,desc="Color Up"}, color_down={key=BTSK_COLORDOWN,desc="Color Down"}, chat={key=BTSK_CHAT,desc="Chat"}, command={key=BTSK_COMMAND,desc="Command"}, teamchat={key=BTSK_TEAMCHAT,desc="Team Chat"}, scores={key=BTSK_SCORES,desc="Scoreboard"}, quit={key=BTSK_QUIT,desc="Quit"}, yes={key=BTSK_YES,desc="Yes"}, no={key=BTSK_NO,desc="No"}, screenshot={key=BTSK_SCREENSHOT,desc="Grab Screenshot"}, debug={key=BTSK_DEBUG,desc="Debug"}, map={key=BTSK_MAP,desc="Map"}, team={key=BTSK_TEAM,desc="Change Team"}, wpn={key=BTSK_WPN,desc="Change Weapon"}, } do local i for i=1,#BTSK_TOOLS do button_map["tool"..i]={key=BTSK_TOOLS[i],desc="Tool "..i} end end -- equivalent - find a button from a keybinding key_map = {} for k, v in pairs(button_map) do key_map[v.key] = {name=k, desc=v.desc} end -- map keysyms to their unicode values to fix keyup being an idiot keys = {} -- a list of arbitrary data with a "camera" that can render sublists. function scroll_list(data, cam_start, cam_height, scrollbackable) local this = {list={},cam={ start=cam_start or 1, height=cam_height-1 or 0}, scrollback = false, scrollbackable = scrollbackable, head = 1} -- return a subset of the list table based on the camera position and height function this.render(cam) cam = cam or this.cam local result = {} local i for i=cam.start, math.min(#this.list, cam.start+cam.height) do table.insert(result, this.list[i]) end return result end return this end chat_killfeed = scroll_list({}, 0, 10, false) chat_text = scroll_list({}, 0, 10, true) NET_MOVE_DELAY = 0.1 NET_ORIENT_DELAY = 0.1 t_net_move = nil t_net_orient = nil function tracer_add(x,y,z,ya,xa,time) x = x or 0 y = y or 0 z = z or 0 local tc = { x=x,y=y,z=z, ya=ya,xa=xa, time=time or tracers.time, chn=client.wav_play_global(wav_whoosh,x,y,z,4.0) } tracers.tail = tracers.tail + 1 tracers[tracers.tail] = tc end function tracer_prune(time) while tracers.head <= tracers.tail and tracers[tracers.head].time + 0.4 <= time do tracers[tracers.head] = nil tracers.head = tracers.head + 1 end if tracers.head > tracers.tail then tracers.head = 1 tracers.tail = 0 end tracers.time = time end function chat_add(scrollist, mtime, msg, color) table.insert(scrollist.list, #scrollist.list+1, { mtime = mtime, color = color, msg = msg, }) table.sort(scrollist.list, function(a, b) return a.mtime < b.mtime end) end function chat_prune(scrollist, mtime) -- prune lines over the stored limit -- prune lines that are old while scrollist.head <= #scrollist.list and (scrollist.list[scrollist.head].mtime <= mtime - MODE_CHAT_LINGER or #scrollist.list - (scrollist.head-1) > MODE_CHAT_MAX) do if scrollist.scrollbackable then scrollist.head = scrollist.head + 1 else table.remove(scrollist.list, scrollist.head) end end if not scrollist.scrollback then scrollist.cam.start = math.max(math.max(scrollist.cam.start, scrollist.head) , #scrollist.list - scrollist.cam.height) end end -- create map sprites log_mspr = {} mspr_player = gen_icon { -1,-3, 0,-3, 1,-3, -2,-2, 2,-2, -3,-1, 3,-1, -3, 0, 3, 0, -3, 1, 3, 1, -2, 2, 2, 2, -1, 3, 0, 3, 1, 3, } -- TODO: confirm the correct size of the intel + tent icons mspr_intel = gen_icon { -3,-3, -2,-3, -1,-3, 0,-3, 1,-3, 2,-3, 3,-3, -3,-2, 3,-2, -3,-1, 3,-1, -3, 0, 3, 0, -3, 1, 3, 1, -3, 2, 3, 2, -3, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, } mspr_tent = gen_icon { 0,-3, 0,-2, 0,-1, -3, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 0, 1, 0, 2, 0, 3, } -- TODO: up/down arrows -- set stuff rotpos = 0.0 sec_last = 0. delta_last = 0. debug_enabled = false do_screenshot = false mouse_released = false sensitivity = user_config.sensitivity or 1.0 sensitivity = sensitivity/1000.0 hold_to_zoom = user_config.hold_to_zoom or false mouse_skip = 3 input_events = {} gui_focus = nil window_activated = true show_scores = false -- load images img_crosshair, img_crosshairhit = crosshair_generate_images(user_config.crosshair) img_chevron = client.img_load("pkg/base/gfx/chevron.tga") -- load kv6 models texa_overview_hmap = {} -- TODO: remove the pmfs -- load/make models mdl_test = model_load({pmf={bdir=DIR_PKG_PMF, name="test.pmf"}},{"pmf"}) mdl_cube = model_load({pmf={bdir=DIR_PKG_PMF, name="cube.pmf"}},{"pmf"}) mdl_piano = model_load({pmf={bdir=DIR_PKG_PMF, name="piano.pmf"}},{"pmf"}) mdl_marker = model_load({pmf={bdir=DIR_PKG_PMF, name="marker.pmf"}},{"pmf"}) mdl_tracer = model_load({pmf={bdir=DIR_PKG_PMF, name="tracer.pmf"}},{"pmf"}) mdl_block = model_load({ kv6={bdir=DIR_PKG_KV6, name="block.kv6", scale=1.0/22.0}, pmf={bdir=DIR_PKG_PMF, name="block.pmf"}, },{"kv6","pmf"}) mdl_spade = model_load({ kv6={bdir=DIR_PKG_KV6, name="spade.kv6", scale=1.0/24.0}, pmf={bdir=DIR_PKG_PMF, name="spade.pmf"}, {}, },{"kv6","pmf"}) mdl_Xcube = model_load({ kv6={bdir=DIR_PKG_KV6, name="xcube.kv6", scale=1.0/256.0}, pmf={bdir=DIR_PKG_PMF, name="xcube.pmf"}, },{"kv6","pmf"}) mdl_test_inst = client and mdl_test {} mdl_cube_inst = client and mdl_cube {} mdl_spade_inst = client and mdl_spade {} mdl_piano_inst = client and mdl_piano {} mdl_Xcube_inst = client and mdl_Xcube {} mdl_marker_inst = client and mdl_marker {} mdl_tracer_inst = client and mdl_tracer {} -- quick hack to stitch a player model together if false then local head,body,arm,leg head = skin_load("pmf", "src/playerhead.pmf", DIR_PKG_PMF) body = skin_load("pmf", "src/playerbody.pmf", DIR_PKG_PMF) arm = skin_load("pmf", "src/playerarm.pmf", DIR_PKG_PMF) leg = skin_load("pmf", "src/playerleg.pmf", DIR_PKG_PMF) local mname, mdata, mbone local mbase = client.model_new(6) mname, mdata = client.model_bone_get(head, 0) mbase, mbone = client.model_bone_new(mbase) client.model_bone_set(mbase, mbone, "head", mdata) mname, mdata = client.model_bone_get(body, 0) mbase, mbone = client.model_bone_new(mbase) client.model_bone_set(mbase, mbone, "body", mdata) mname, mdata = client.model_bone_get(arm, 0) mbase, mbone = client.model_bone_new(mbase) client.model_bone_set(mbase, mbone, "arm", mdata) mname, mdata = client.model_bone_get(leg, 0) mbase, mbone = client.model_bone_new(mbase) client.model_bone_set(mbase, mbone, "leg", mdata) client.model_save_pmf(mbase, "clsave/vol/player.pmf") end --[[ mdl_bbox = client.model_new(1) mdl_bbox_bone_data1 = { {radius=10, x = -100, y = -70, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = -70, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = -100, y = -70, z = 100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = -70, z = 100, r = 255, g = 85, b = 85}, {radius=10, x = -100, y = 600, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = 600, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = -100, y = 600, z = 100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = 600, z = 100, r = 255, g = 85, b = 85}, } mdl_bbox_bone_data2 = { {radius=10, x = -100, y = -70, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = -70, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = -100, y = -70, z = 100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = -70, z = 100, r = 255, g = 85, b = 85}, {radius=10, x = -100, y = 410, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = 410, z = -100, r = 255, g = 85, b = 85}, {radius=10, x = -100, y = 410, z = 100, r = 255, g = 85, b = 85}, {radius=10, x = 100, y = 410, z = 100, r = 255, g = 85, b = 85}, } mdl_bbox, mdl_bbox_bone1 = client.model_bone_new(mdl_bbox) mdl_bbox, mdl_bbox_bone2 = client.model_bone_new(mdl_bbox) client.model_bone_set(mdl_bbox, mdl_bbox_bone1, "bbox_stand", mdl_bbox_bone_data1) client.model_bone_set(mdl_bbox, mdl_bbox_bone2, "bbox_crouch", mdl_bbox_bone_data2) ]] -- profile bone count if false then local bone_ctr = 0 function bone_ctr_reset() local ret = bone_ctr print("bones:", bone_ctr) bone_ctr = 0 return ret end local old_model_render_bone_global = client.model_render_bone_global local old_model_render_bone_local = client.model_render_bone_local function client.model_render_bone_global(...) bone_ctr = bone_ctr + 1 return old_model_render_bone_global(...) end function common.model_render_bone_global(...) bone_ctr = bone_ctr + 1 return old_model_render_bone_global(...) end function client.model_render_bone_local(...) bone_ctr = bone_ctr + 1 return old_model_render_bone_local(...) end function common.model_render_bone_local(...) bone_ctr = bone_ctr + 1 return old_model_render_bone_local(...) end end -- set hooks lflush = nil function h_tick_main(sec_current, sec_delta) -- TODO: DEPRECATED: FUTURE: HOW2LABELTHESETHINGS: Remove this check once sufficient time has passed that everyone should be above version 0.2.1-28 if sec_delta <= 0 then -- WHY THE FUCK IS SEC_DELTA <= 0?!? sec_delta = 0.000001 end if _CSIDE_G.hooks and _CSIDE_G.hooks.tick_pre then _CSIDE_G.hooks.tick_pre(sec_current, sec_delta) end render_sec_current = sec_current if bone_ctr_reset then bone_ctr_reset() end if (not lflush) or sec_current < lflush - 0.8 then lflush = sec_current end if sec_current >= lflush then net_send_flush() lflush = lflush + NET_FLUSH_C2S if sec_current <= lflush then lflush = sec_current end end --FIXME: why is this POS prototyping variable still here, it is being used to control the player model's leg swing >:( rotpos = rotpos + sec_delta*120.0 chat_prune(chat_text, sec_current) chat_prune(chat_killfeed, sec_current) local pkt, neth while true do pkt, neth = common.net_recv() if not pkt then break end local cid cid, pkt = common.net_unpack("B", pkt) --print("pkt", cid) local hdl = network.sys_tab_handlers[cid] if hdl then hdl.f(neth, cli, plr, sec_current, common.net_unpack(hdl.s, pkt)) else print(string.format("C: unhandled packet %02X", cid)) end end tracer_prune(sec_current) bhealth_prune(sec_current) local tickrate = 1/60. local lowest_fps = 7.5 -- some people have REALLY shit GPUs. might as well lower this requirement. local max_ticksize = 1/lowest_fps if sec_delta > max_ticksize then sec_delta = max_ticksize end tickrate = sec_delta local moment = sec_current - sec_delta client_tick_accum = client_tick_accum + sec_delta for i=1,players.max do local plr = players[i] if plr then plr.tick_listeners(sec_current, sec_delta) end end while client_tick_accum > tickrate do moment = moment + tickrate local i for i=1,players.max do local plr = players[i] if plr then plr.tick(moment, tickrate) end end for i=nades.head,nades.tail do if nades[i] then nades[i].tick(moment, tickrate) end end for i=particles.head,particles.tail do if particles[i] then particles[i].tick(moment, tickrate) end end for i=1,#borders do borders[i].tick(moment, tickrate) end nade_prune(sec_current) particles_prune(sec_current) for i=1,#miscents do miscents[i].tick(moment, tickrate) end client_tick_accum = client_tick_accum - tickrate end if players.current and players[players.current] then local plr = players[players.current] if t_net_move and sec_current >= t_net_move then t_net_move = nil end if t_net_orient and sec_current >= t_net_orient then t_net_orient = nil end if not t_net_move then t_net_move = sec_current + NET_MOVE_DELAY local x,y,z local vx,vy,vz x,y,z = plr.get_pos() vx,vy,vz = plr.get_vel() net_send(nil, common.net_pack("BBffffff" , PKT_PLR_POS, 0x00, x, y, z, vx, vy, vz)) end if not t_net_orient then t_net_orient = sec_current + NET_ORIENT_DELAY local ya,xa,keys ya,xa,keys = plr.get_orient() ya = ya*128/math.pi xa = xa*256/math.pi net_send(nil, common.net_pack("BBbbB" , PKT_PLR_ORIENT, 0x00, ya, xa, keys)) end plr.camera_firstperson(sec_current, sec_delta) else -- TODO: idle camera end input_events = {} sec_last = sec_current delta_last = sec_delta -- wait a bit local d = math.max(0.00001, frame_delay_ctr - delta_last) if _CSIDE_G.hooks and _CSIDE_G.hooks.tick_post then _CSIDE_G.hooks.tick_post(sec_current, sec_delta) end return d end function h_tick_init(sec_current, sec_delta) render_sec_current = sec_current local i --[[local squads = {[0]={},[1]={}} for i=1,4 do squads[0][i] = name_generate() squads[1][i] = name_generate() end]] players.current = nil --[[ for i=1,players.max do players[i] = new_player({ name = (players.current == i and user_config.name) or name_generate(), --[=[squad = squads[(i-1) % 2][ (math.floor((i-1)/2) % 4)+1],]=] squad = nil, team = (i-1) % 2, -- 0 == blue, 1 == green weapon = WPN_RIFLE, }) end ]] mode_create_client() chat_add(chat_text, sec_current, "Welcome to Iceball!", 0xFFFF00AA) --chat_add(chat_killfeed, sec_current, "If it's broken, fix it yourself", 0xFFFF00AA) chat_add(chat_killfeed, sec_current, "If you have any questions, check the subreddit.", 0xFFFF00AA) chat_add(chat_killfeed, sec_current, "If you find any bugs, file an issue on GitHub.", 0xFFFF00AA) mouse_released = false client.mouse_lock_set(true) client.mouse_visible_set(false) net_send(nil, common.net_pack("Bbbz", PKT_PLR_OFFER, -1, WPN_RIFLE, user_config.name or "")) client.hook_tick = h_tick_main net_send_flush() return client.hook_tick(sec_current, sec_delta) end local function push_keypress(key, state, modif, sym, uni) table.insert(input_events, {GE_KEY, {key=key,state=state,modif=modif,uni=uni}}) if key_map[sym] ~= nil then table.insert(input_events, {GE_BUTTON, {key=sym,button=key_map[sym],state=state,modif=modif,uni=uni}}) end end stored_pointer = {x=screen_width/4, y=screen_height*3/4} -- default to around the lower-left, where the text box is function enter_typing_state() in_typing_state = true chat_text.scrollback = true chat_text.cam.start = math.max(1, #chat_text.list - chat_text.cam.height) mouse_released = true if client.text_input_start then client.text_input_start() end client.mouse_lock_set(false) client.mouse_visible_set(true) if client.mouse_warp ~= nil then client.mouse_warp(stored_pointer.x, stored_pointer.y) end end function discard_typing_state(widget) in_typing_state = false gui_focus = nil if widget.clear_keyrepeat then widget.clear_keyrepeat() end chat_text.scrollback = false mouse_released = false if client.text_input_stop then client.text_input_stop() end client.mouse_lock_set(true) client.mouse_visible_set(false) if client.mouse_warp ~= nil then stored_pointer.x = mouse_xy.x stored_pointer.y = mouse_xy.y client.mouse_warp(screen_width/2, screen_height/2) mouse_skip = 2 end end function h_key(sym, state, modif, uni) local key = sym -- grab screenshot if state and key == BTSK_SCREENSHOT then do_screenshot = true end -- SDL1.2 backwards compat if in_typing_state and state and uni and not client.text_input_start then -- not worth supporting UTF-8 in the SDL1.2 clients -- we're about to chuck it out if uni >= 32 and uni < 127 then local uni_c = string.char(uni) push_text(uni_c) end end push_keypress(key, state, modif, sym, uni) -- disconnected ai if not players[players.current] then if state and key == BTSK_QUIT then client.hook_tick = nil end return end -- typing text if gui_focus ~= nil then mouse_released = true client.mouse_lock_set(false) client.mouse_visible_set(true) gui_focus.on_key(key, state, modif, uni) if state and chat_text.scrollback then if key == BTSK_CHATUP then chat_text.cam.start = math.max(1, chat_text.cam.start - math.floor(chat_text.cam.height/2+0.5)) elseif key == BTSK_CHATDN then chat_text.cam.start = math.max(1, math.min( chat_text.cam.start + math.floor(chat_text.cam.height/2+0.5), #chat_text.list - chat_text.cam.height)) end end return end if not window_activated then mouse_released = true client.mouse_lock_set(false) client.mouse_visible_set(true) return end -- player entity ai local plr = players[players.current] if plr then mouse_released = false client.mouse_lock_set(true) client.mouse_visible_set(false) return plr.on_key(key, state, modif, uni) end end function push_text(text) table.insert(input_events, {GE_TEXT, text}) end local function push_mouse_button(button, state) table.insert(input_events, {GE_MOUSE_BUTTON, {button=button,down=state}}) end local function push_mouse(x, y, dx, dy) table.insert(input_events, {GE_MOUSE, {x=x, y=y, dx=dx, dy=dy}}) end -- a nice little tool for checking the mouse state function mouse_prettyprint() local function xyp(n) local s = tostring(mouse_xy[n]) if #s == 1 then return n..s.." " elseif #s == 2 then return n..s.." " elseif #s == 3 then return n..s.." " elseif #s == 4 then return n..s.." " else return n..s end end local function pollp(n) if mouse_poll[n] then return n..'X ' else return n..' ' end end return xyp('x')..xyp('y')..xyp('dx')..xyp('dy').. " "..pollp(1)..pollp(2)..pollp(3)..pollp(4)..pollp(5) end mouse_poll = {false,false,false,false,false} mouse_xy = {x=0,y=0,dx=0,dy=0} function h_text(text) push_text(text) end function h_mouse_button(button, state) if mouse_poll[button] ~= state then mouse_poll[button] = state push_mouse_button(button, state) end if mouse_released and gui_focus == nil then mouse_released = false client.mouse_lock_set(true) client.mouse_visible_set(false) return end -- player entity ai -- FIXME: no reassignable mouse button controls? local plr = players[players.current] if plr and gui_focus == nil then return plr.on_mouse_button(button, state) end end function h_mouse_motion(x, y, dx, dy) mouse_xy.x = x mouse_xy.y = y mouse_xy.dx = dx mouse_xy.dy = dy push_mouse(x, y, dx, dy) -- player entity ai if not players[players.current] then return end if mouse_released then return end if mouse_skip > 0 then mouse_skip = mouse_skip - 1 return end local plr = players[players.current] if plr and gui_focus == nil then return plr.on_mouse_motion(x, y, dx, dy) end end function h_window_activate(active) window_activated = active if active then mouse_released = false client.mouse_lock_set(true) client.mouse_visible_set(false) else mouse_released = true client.mouse_lock_set(false) client.mouse_visible_set(true) end end -- load map map_loaded = common.map_load(map_fname, "auto") common.map_set(map_loaded) if client.map_set_render_format and USE_GLSL then client.map_set_render_format(map_loaded, "3v,3c,3n") end borders = {} -- set fog print(client.map_fog_get()) --client.map_fog_set(24,0,32,60) foglvl = user_config.fog or MODE_DEFAULT_FOG if foglvl <= 1 then foglvl = MODE_MAX_FOG end if MODE_MAX_FOG and foglvl > MODE_MAX_FOG then foglvl = MODE_MAX_FOG end if MODE_FOG_GL_EXTEND and client.renderer == "gl" then foglvl = foglvl * math.sqrt(2) end client.map_fog_set(192,238,255,foglvl) print(client.map_fog_get()) -- set borders do local xlen, ylen, zlen xlen, ylen, zlen = common.map_get_dims() local r,g,b r,g,b = client.map_fog_get() if MODE_BORDER_SHOW then borders = { new_border(-1, 0, 0, 1, 0, 0, r,g,b), new_border(xlen+1, ylen, zlen, 1, 0, 0, r,g,b), new_border(0, 0, -1, 0, 0, 1, r,g,b), new_border(xlen, ylen, zlen+1, 0, 0, 1, r,g,b), new_border(-1, 0, 0, 1, 0, 0, r,g,b), new_border(xlen+1, ylen, zlen, 1, 0, 0, r,g,b), new_border(0, 0, -1, 0, 0, 1, r,g,b), new_border(xlen, ylen, zlen+1, 0, 0, 1, r,g,b), } end end -- create map overview do local xlen, ylen, zlen xlen, ylen, zlen = common.map_get_dims() img_overview = common.img_new(xlen, zlen) img_overview_hmap = common.img_new(xlen, zlen) img_overview_grid = common.img_new(xlen, zlen) --img_overview_icons = common.img_new(xlen, zlen) local x,z if shader_world then texa_overview_hmap[1] = img_overview_hmap end for z=0,zlen-1 do for x=0,xlen-1 do local l = common.map_pillar_get(x,z) local c = argb_split_to_merged(l[7],l[6],l[5]) common.img_pixel_set(img_overview, x, z, c) common.img_pixel_set(img_overview_hmap, x, z, l[2]) end end for z=63,zlen-1,64 do for x=0,xlen-1 do common.img_pixel_set(img_overview_grid, x, z, 0xFFFFFFFF) end end for z=0,zlen-1 do for x=63,xlen-1,64 do common.img_pixel_set(img_overview_grid, x, z, 0xFFFFFFFF) end end for x=0,xlen-1 do common.img_pixel_set(img_overview_grid, x, zlen-1, 0xFFFF0000) end for z=0,zlen-1 do common.img_pixel_set(img_overview_grid, xlen-1, z, 0xFFFF0000) end end -- create colour palette image img_cpal = common.img_new(64,64) img_cpal_rect = common.img_new(8,8) do local cx,cy,x,y for cy=0,7 do for cx=0,7 do local r,g,b r = cpalette[cy*8+cx+1][1] g = cpalette[cy*8+cx+1][2] b = cpalette[cy*8+cx+1][3] local c = argb_split_to_merged(r,g,b) for y=cy*8+1,cy*8+6 do for x=cx*8+1,cx*8+6 do common.img_pixel_set(img_cpal, x, y, c) end end end end local i for i=0,6 do common.img_pixel_set(img_cpal_rect, i, 0, 0xFFFFFFFF) common.img_pixel_set(img_cpal_rect, 7, i, 0xFFFFFFFF) common.img_pixel_set(img_cpal_rect, 7-i, 7, 0xFFFFFFFF) common.img_pixel_set(img_cpal_rect, 0, 7-i, 0xFFFFFFFF) end end -- hooks in place! if VA_TEST then --[[ va_test = common.va_make({ {0, 0, 0, 1, 0.5, 0.5}, {1, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 0, 0}, {0, 0, 0, 0.5, 1, 0.5}, {0, 0, 1, 0, 1, 0}, {1, 0, 0, 0, 1, 0}, {0, 0, 0, 0.5, 0.5, 1}, {0, 1, 0, 0, 0, 1}, {0, 0, 1, 0, 0, 1}, {1, 0, 0, 0.7, 0, 0.7}, {0, 0, 1, 0.7, 0, 0.7}, {0, 1, 0, 0.7, 0, 0.7}, }) ]] --va_test = loadkv6("pkg/base/kv6/playerheadalt.kv6", 1.0/16.0) va_test = common.va_make({ {0, 0, 0, 0, 0}, {1, 0, 0, 0, 1}, {0, 1, 0, 1, 0}, {0, 0, 0, 0, 0}, {0, 0, 1, 0, 1}, {1, 0, 0, 1, 0}, {0, 0, 0, 0, 0}, {0, 1, 0, 0, 1}, {0, 0, 1, 1, 0}, {1, 0, 0, 0, 0}, {0, 0, 1, 0, 1}, {0, 1, 0, 1, 0}, }, nil, "3v,2t") --[[ va_test = common.va_make({ {0, 0, 0, 1, 0.5, 0.5, 0, 0}, {1, 0, 0, 1, 0, 0, 0, 1}, {0, 1, 0, 1, 0, 0, 1, 0}, {0, 0, 0, 0.5, 1, 0.5, 0, 0}, {0, 0, 1, 0, 1, 0, 0, 1}, {1, 0, 0, 0, 1, 0, 1, 0}, {0, 0, 0, 0.5, 0.5, 1, 0, 0}, {0, 1, 0, 0, 0, 1, 0, 1}, {0, 0, 1, 0, 0, 1, 1, 0}, {1, 0, 0, 0.7, 0, 0.7, 0, 0}, {0, 0, 1, 0.7, 0, 0.7, 0, 1}, {0, 1, 0, 0.7, 0, 0.7, 1, 0}, }, nil, "3v,3c,2t") ]] end if USE_GLSL_20 then shader_misc, result = loadfile("pkg/base/shader/misc_diff.lua")() shader_world, result = loadfile("pkg/base/shader/world_diff.lua")() shader_white, result = loadfile("pkg/base/shader/white.lua")() shader_simple, result = loadfile("pkg/base/shader/simple.lua")() shader_img, result = loadfile("pkg/base/shader/img.lua")() postproc_map = { toon = "pkg/base/shader/post_toon.lua", simple = "pkg/base/shader/post_simple.lua", stereo = "pkg/base/shader/post_stereo.lua", } if user_config.postproc == false then shader_postproc = nil else local postproc = (user_config.postproc and postproc_map[user_config.postproc]) or "pkg/base/shader/post_toon.lua" shader_postproc, result = loadfile(postproc)() end end if shader_world then shader_world.push() end if client.map_render then client.map_enable_autorender(false) if USE_GLSL and shader_world then client.map_enable_side_shading(false) end end function client.hook_render() local sec_current = render_sec_current if fbo_world then client.fbo_use(fbo_world) client.gfx_clear_color() client.gfx_clear_depth() client.gfx_clear_stencil() end if client.map_render and map_loaded then if shader_world then client.map_render(map_loaded, 0, 0, 0, {img_overview_hmap}) else client.map_render(map_loaded, 0, 0, 0) end end if shader_world then shader_world.pop() end if shader_misc then shader_misc.set_uniform_f("sun", 1.0/math.sqrt(4.0), math.sqrt(2.0)/math.sqrt(4.0), 1.0/math.sqrt(4.0), 0) shader_misc.set_uniform_f("time", sec_current or 0.0) shader_misc.set_uniform_i("tex0", 0) shader_misc.push() end local s_img_blit = client.img_blit if shader_img then function client.img_blit(...) shader_img.push() s_img_blit(...) shader_img.pop() end end local i for i=tracers.head,tracers.tail do local tc = tracers[i] local x,y,z x,y,z = tc.x, tc.y, tc.z local sya = math.sin(tc.ya) local cya = math.cos(tc.ya) local sxa = math.sin(tc.xa) local cxa = math.cos(tc.xa) local d = tracers.time - tc.time d = d + 0.005 d = d * 600.0 x = x + sya*cxa*d y = y + sxa*d z = z + cya*cxa*d client.wav_chn_update(tracers.chn, x, y, z) mdl_tracer_inst.render_global( x,y,z, 0.0, -tc.xa, tc.ya, 1) end for i=nades.head,nades.tail do if nades[i] then nades[i].render() end end for i=particles.head,particles.tail do if particles[i] then particles[i].render() end end for i=1,#borders do borders[i].render() end local s_gfx_clear_depth = client.gfx_clear_depth if fbo_world then --[[ client.fbo_use(nil) client.gfx_clear_color() client.fbo_use(fbo_world) ]] function client.gfx_clear_depth(...) client.fbo_use(nil) local shader = shader_postproc or shader_img or shader_misc if shader then shader.set_uniform_i("tex0", 0) shader.set_uniform_i("tex1", 1) shader.set_uniform_f("soffs", 1.0/screen_width, 1.0/screen_height) shader.set_uniform_f("time", sec_current or 0) local _r, _g, _b, f = client.map_fog_get() local zoom = (players and players.current and players[players.current] and players[players.current].zoom) or 1.0 --f = f / zoom local n = 0.05 -- / zoom shader.set_uniform_f("fog", f) shader.set_uniform_f("depth_A", (f+n)/(f-n)) shader.set_uniform_f("depth_B", -(2.0*f*n)/(f-n)) shader.push() end s_img_blit(fbo_world, 0, 0) client.img_blit = s_img_blit if shader then shader.pop() end client.gfx_clear_depth = s_gfx_clear_depth --client.fbo_use(fbo_world) --client.gfx_clear_color() s_gfx_clear_depth(...) --client.fbo_use(fbo_world) end end if players and players[players.current] then players[players.current].show_hud() end if VA_TEST and sec_current then client.va_render_local(va_test, -0.8, 0.35, 1, sec_current, sec_current*0.8, sec_current*0.623, 0.1, img_overview) end if client.gfx_clear_depth ~= s_gfx_clear_depth then client.gfx_clear_depth() end client.gfx_clear_depth = s_gfx_clear_depth if shader_misc then shader_misc.pop() end client.img_blit = s_img_blit if shader_world then shader_world.set_uniform_f("sun", 1.0/math.sqrt(4.0), math.sqrt(2.0)/math.sqrt(4.0), 1.0/math.sqrt(4.0), 0) shader_world.set_uniform_f("time", sec_current or 0.0) local xlen, ylen, zlen = common.map_get_dims() shader_world.set_uniform_f("map_idims", 1.0/xlen, 1.0/zlen) shader_world.push() end if do_screenshot then local loc = client.img_dump() chat_add(chat_text, sec_current / 2, "Screenshot saved as: " .. loc, 0xFFFFFFAA) do_screenshot = false end end client.hook_tick = h_tick_init client.hook_key = h_key client.hook_text = h_text client.hook_mouse_button = h_mouse_button client.hook_mouse_motion = h_mouse_motion client.hook_window_activate = h_window_activate function client.hook_kick(reason) print("Kicked - "..reason) function client.hook_tick() client.mouse_lock_set(false) client.mouse_visible_set(true) return 0.01 end function client.hook_key(sym, state, modif, uni) if state and sym == BTSK_QUIT then client.hook_tick = nil end end local old_render = client.hook_render local new_render = nil function new_render_fn(...) client.hook_render = old_render local ret = client.hook_render(...) old_render = client.hook_render client.hook_render = new_render font_large.print(30, 30, 0xFFAA0000, "KICKED") font_mini.print(30, 65, 0xFFAA0000, reason) end new_render = new_render_fn client.hook_render = new_render end print("pkg/base/client_start.lua: Loading mods...") load_mod_list(getfenv(), nil, {"load", "load_client"}, client_config) print("pkg/base/client_start.lua loaded.") if FAST_LOCAL_INIT and sandbox then sandbox.gfx_select(sandbox.this()) end