├── .gitignore ├── README.md ├── lua ├── autorun │ ├── client │ │ ├── g64_cl_init.lua │ │ ├── g64_emotemenu.lua │ │ ├── g64_hud.lua │ │ ├── g64_lang.lua │ │ └── g64_spawnmenu.lua │ ├── g64_convars.lua │ ├── g64_init.lua │ ├── server │ │ ├── g64_networkstrings.lua │ │ └── g64_sv_init.lua │ └── sh_systimetimers_loader.lua ├── entities │ ├── g64_1up.lua │ ├── g64_bluecoin.lua │ ├── g64_coin.lua │ ├── g64_mario.lua │ ├── g64_metalcap.lua │ ├── g64_physbox.lua │ ├── g64_redcoin.lua │ ├── g64_tptrigger.lua │ ├── g64_vanishcap.lua │ ├── g64_wingcap.lua │ └── g64_yellowcoin.lua ├── includes │ ├── g64_config.lua │ ├── g64_luabsp.lua │ ├── g64_sprites.lua │ ├── g64_types.lua │ ├── g64_utils.lua │ └── modules │ │ └── systimetimers.lua └── weapons │ └── gmod_tool │ └── stools │ └── g64surfacechanger.lua ├── materials └── vgui │ ├── entities │ ├── g64_blankicon.png │ ├── g64_blankicon.vmt │ ├── g64_blankicon.vtf │ ├── g64_mario.png │ ├── g64_mario.psd │ ├── g64_mario.vmt │ ├── g64_mario.vtf │ ├── g64_metalcap.png │ ├── g64_metalcap.psd │ ├── g64_metalcap.vmt │ ├── g64_metalcap.vtf │ ├── g64_vanishcap.png │ ├── g64_vanishcap.psd │ ├── g64_vanishcap.vmt │ ├── g64_vanishcap.vtf │ ├── g64_wingcap.png │ ├── g64_wingcap.psd │ ├── g64_wingcap.vmt │ └── g64_wingcap.vtf │ ├── radial.png │ ├── radial.vmt │ └── radial.vtf └── particles └── sm64.pcf /.gitignore: -------------------------------------------------------------------------------- 1 | materials/workshop.* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # G64 2 | A Garry's Mod addon that uses [libsm64](https://github.com/libsm64/libsm64/) to put a playable Mario in the game. \ 3 | Note: This requires Windows and 64-bit Garry's Mod. 4 | 5 | ## Installation 6 | - Download G64 [from the workshop](https://steamcommunity.com/sharedfiles/filedetails/?id=2814638140). Alternatively, clone this repo in your `GarrysMod\garrysmod\addons` folder. 7 | - Download and run the [G64 Installer](https://github.com/ckosmic/G64Installer/releases/latest) to install the files needed for the addon to interact with libsm64. 8 | - Obtain a copy of the US version of the Super Mario 64 ROM (MD5: `20b854b239203baf6c961b850a4a51a2`, SHA1: `9bef1128717f958171a4afac3ed78ee2bb4e86ce`). No, I will not tell you how or where to get this, nor will I send it to you. 9 | - Make sure you're on the 64-bit version of the game **OR THIS WILL NOT WORK AT ALL.** To do this, right click on Garry's Mod in your Steam library and click `Properties...`. Then click `BETAS` and select `x86-64 - Chromium + 64-bit binaries` from the dropdown. 10 | - Now that Gmod is in 64-bit mode, open it and load a map. Open the spawn menu and under Utilities > G64 > Settings, set the path to the ROM you obtained. 11 | 12 | You're now all set! Spawn Mario from the G64 tab and if you did everything right, Mario will spawn. Enjoy! 13 | 14 | ## See More 15 | Source to my gmod fork of libsm64 can be found here: https://github.com/ckosmic/libsm64/tree/gmod \ 16 | Source to the G64 binary module can be found here: https://github.com/ckosmic/libsm64-gmod \ 17 | Source to the G64 installer can be found here: https://github.com/ckosmic/G64Installer \ 18 | Source to the G64 auto updater module can be found here: https://github.com/ckosmic/g64_autoupdater 19 | 20 | ## Credits 21 | Many features of this addon (like sound and multiplayer) would not be possible without @dylanpdx's [Retro64Mod fork of libsm64](https://github.com/Retro64Mod/libsm64-retro64/). \ 22 | [SysTimeTimers](https://github.com/SnisnotAl/SysTimeTimers) by @SnisnotAI \ 23 | [gmod-luabsp](https://github.com/h3xcat/gmod-luabsp/blob/master/luabsp.lua) by @h3xcat -------------------------------------------------------------------------------- /lua/autorun/client/g64_cl_init.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | include("includes/g64_config.lua") 4 | 5 | -- Make level transitions work 6 | local spawnMarioOnceInited = false 7 | local inited = false 8 | hook.Add("InitPostEntity", "G64_CL_INIT_POST_ENTITY", function() 9 | 10 | hook.Add("Think", "G64_STEAMID_WAIT_NOTNIL", function() 11 | local marios = ents.FindByClass("g64_mario") 12 | for k,v in ipairs(marios) do 13 | if v.Owner.SteamID ~= nil and LocalPlayer().SteamID ~= nil then 14 | hook.Remove("Think", "G64_STEAMID_WAIT_NOTNIL") 15 | if v.Owner:SteamID() == LocalPlayer():SteamID() then 16 | net.Start("G64_RESETINVALIDPLAYER") 17 | net.WriteEntity(v) 18 | net.SendToServer() 19 | v.Owner.IsMario = false 20 | v.Owner.SM64LoadedMap = false 21 | if inited == false then 22 | spawnMarioOnceInited = true 23 | else 24 | inited = true 25 | net.Start("G64_SPAWNMARIOATPLAYER") 26 | net.SendToServer() 27 | end 28 | end 29 | end 30 | end 31 | end) 32 | 33 | LocalPlayer().CoinCount = 0 34 | LocalPlayer().RedCoinCount = 0 35 | LocalPlayer().LivesCount = 4 36 | end) 37 | 38 | hook.Add("G64Initialized", "G64_SPAWN_CHANGELEVEL_MARIO", function() 39 | inited = true 40 | if spawnMarioOnceInited == false then return end 41 | timer.Create("blah", 1, 1, function() 42 | net.Start("G64_SPAWNMARIOATPLAYER") 43 | net.SendToServer() 44 | end) 45 | end) 46 | 47 | -- Timer for the the libsm64 game loop 48 | G64_TICKRATE = 1/33 49 | systimetimers.Create("G64_GAME_TICK", G64_TICKRATE, 0, function() 50 | hook.Call("G64GameTick") 51 | end) 52 | 53 | hook.Add("G64AdjustedTimeScale", "G64_ADJUST_TIMESCALE", function(timeScale) 54 | if timeScale == nil then timeScale = 1 end 55 | G64_TICKRATE = 1/33 / timeScale 56 | systimetimers.Adjust("G64_GAME_TICK", G64_TICKRATE) 57 | end) 58 | 59 | -- Entity collision system from GWater-V3 60 | local propQueue = propQueue or {} 61 | local surfaceIds = surfaceIds or {} 62 | local objects = objects or {} 63 | local objectIds = objectIds or {} 64 | 65 | local allEnts = allEnts or {} 66 | 67 | function SeqArgs(priority, seqId) 68 | return bit.bor(bit.lshift(priority, 8), seqId) 69 | end 70 | 71 | function StopAllTracks() 72 | for i = 0, 0x22 do 73 | libsm64.StopMusic(i) 74 | end 75 | end 76 | 77 | function PlayTrack(seqId) 78 | if libsm64 ~= nil and libsm64.ModuleLoaded == true and libsm64.IsGlobalInit() then 79 | StopAllTracks() 80 | libsm64.PlayMusic(0, SeqArgs(4, seqId), 0) 81 | end 82 | end 83 | 84 | function GetSoundArg(soundTable) 85 | if type(soundTable) == "table" then 86 | return libsm64.GetSoundArg(soundTable[1], soundTable[2], soundTable[3], soundTable[4], soundTable[5]) 87 | elseif type(soundTable) == "number" then 88 | return soundTable 89 | end 90 | return nil 91 | end 92 | 93 | local meta = FindMetaTable("Player") 94 | 95 | function meta:HasGodMode() 96 | return self:GetNWBool("HasGodMode") 97 | end 98 | 99 | local function AddPropMesh(prop) 100 | if not prop or prop:IsValid() == false then return end 101 | 102 | local surf = prop.G64SurfaceType 103 | local terr = prop.G64TerrainType 104 | 105 | if surf == nil then surf = 0 end 106 | if terr == nil then terr = 0 end 107 | 108 | local phys = prop:GetPhysicsObject() 109 | 110 | if prop:IsScripted() and phys:IsValid() and phys:IsCollisionEnabled() then 111 | surfaceIds[#libsm64.EntMeshes+1] = {} 112 | for k,convex in pairs(phys:GetMeshConvexes()) do 113 | local finalMesh = {} 114 | for k,vertex in pairs(convex) do 115 | finalMesh[#finalMesh + 1] = vertex.pos 116 | end 117 | table.insert(surfaceIds[#libsm64.EntMeshes+1], libsm64.SurfaceObjectCreate(finalMesh, phys:GetPos(), phys:GetAngles(), surf, terr)) 118 | finalMesh = nil 119 | end 120 | table.insert(libsm64.EntMeshes, prop) 121 | return 122 | end 123 | 124 | if libsm64.AllowedBrushEnts[prop:GetClass()] and prop:GetBrushSurfaces() ~= nil and #prop:GetBrushSurfaces() > 0 then 125 | local finalMesh = {} 126 | local surfaces = prop:GetBrushSurfaces() 127 | if surfaces == nil or #surfaces == 0 then return end 128 | for k,surfInfo in pairs(surfaces) do 129 | local vertices = surfInfo:GetVertices() 130 | for i = 1, #vertices - 2 do 131 | local len = #finalMesh 132 | finalMesh[len + 1] = vertices[1] 133 | finalMesh[len + 2] = vertices[i + 1] 134 | finalMesh[len + 3] = vertices[i + 2] 135 | end 136 | end 137 | 138 | if #finalMesh == 0 then return end 139 | surfaceIds[#libsm64.EntMeshes+1] = {} 140 | table.insert(surfaceIds[#libsm64.EntMeshes+1], libsm64.SurfaceObjectCreate(finalMesh, prop:GetPos(), prop:GetAngles(), surf, terr)) 141 | table.insert(libsm64.EntMeshes, prop) 142 | finalMesh = nil 143 | return 144 | end 145 | 146 | prop:PhysicsInit(6) 147 | phys = prop:GetPhysicsObject() 148 | if phys:IsValid() == false then 149 | prop:PhysicsDestroy() 150 | return 151 | end 152 | 153 | if phys:IsValid() and phys:IsCollisionEnabled() then 154 | surfaceIds[#libsm64.EntMeshes+1] = {} 155 | for k,convex in pairs(phys:GetMeshConvexes()) do 156 | local finalMesh = {} 157 | for k,vertex in pairs(convex) do 158 | finalMesh[#finalMesh + 1] = vertex.pos 159 | end 160 | table.insert(surfaceIds[#libsm64.EntMeshes+1], libsm64.SurfaceObjectCreate(finalMesh, phys:GetPos(), phys:GetAngles(), surf, terr)) 161 | finalMesh = nil 162 | end 163 | table.insert(libsm64.EntMeshes, prop) 164 | else 165 | local model = prop:GetModel() 166 | if not model or not util.GetModelMeshes(model) then return end 167 | local finalMesh = {} 168 | for k,mesh in pairs(util.GetModelMeshes(model)) do 169 | for k,vertex in pairs(mesh.triangles) do 170 | table.insert(finalMesh, vertex.pos) 171 | end 172 | end 173 | surfaceIds[#libsm64.EntMeshes+1] = {} 174 | table.insert(surfaceIds[#libsm64.EntMeshes+1], libsm64.SurfaceObjectCreate(finalMesh, prop:GetPos(), prop:GetAngles(), surf, terr)) 175 | table.insert(libsm64.EntMeshes, prop) 176 | finalMesh = nil 177 | end 178 | 179 | prop:PhysicsDestroy() 180 | end 181 | 182 | local function RotMatToAng(mat) 183 | local sy = math.sqrt(mat:GetField(1, 1) * mat:GetField(1, 1) + mat:GetField(2, 1) * mat:GetField(2, 1)) 184 | local x, y, z 185 | if not (sy < 0.000001) then 186 | x = math.atan2(mat:GetField(3, 2), mat:GetField(3, 3)) 187 | y = math.atan2(-mat:GetField(3, 1), sy) 188 | z = math.atan2(mat:GetField(2, 1), mat:GetField(1, 1)) 189 | else 190 | x = math.atan2(-mat:GetField(2, 3), mat:GetField(2, 2)) 191 | y = math.atan2(-mat:GetField(3, 1), sy) 192 | z = 0 193 | end 194 | x = math.fmod(math.deg(x) + 180, 360) 195 | y = math.fmod(math.deg(y) + 180, 360) 196 | z = math.fmod(math.deg(z) + 180, 360) 197 | return Angle(x, z, y) 198 | end 199 | 200 | hook.Add("G64Initialized", "G64_ENTITY_GEO", function() 201 | 202 | function libsm64.AddColliderToQueue(ent) 203 | if ent:IsValid() and not ent.SM64_UPLOADED and (libsm64.AllowedEnts[ent:GetClass()] or libsm64.AllowedBrushEnts[ent:GetClass()]) then 204 | propQueue[#propQueue+1] = ent 205 | ent.SM64_UPLOADED = true 206 | end 207 | end 208 | 209 | function libsm64.RemoveCollider(ent) 210 | ent.SM64_UPLOADED = false 211 | local entIndex = table.KeyFromValue(libsm64.EntMeshes, ent) 212 | local allEntIndex = table.KeyFromValue(allEnts, ent) 213 | table.remove(allEnts, allEntIndex) 214 | if surfaceIds[entIndex] ~= nil then 215 | for j,surfaceId in pairs(surfaceIds[entIndex]) do 216 | libsm64.SurfaceObjectDelete(surfaceId) 217 | end 218 | table.remove(surfaceIds, entIndex) 219 | table.remove(libsm64.EntMeshes, entIndex) 220 | end 221 | end 222 | 223 | local function ProcessNewEntity(ent) 224 | if table.HasValue(allEnts, ent) then return end 225 | libsm64.AddColliderToQueue(ent) 226 | allEnts[#allEnts + 1] = ent 227 | if (ent:IsNPC() or ent:IsPlayer()) and ent ~= LocalPlayer() and ent:GetClass() ~= "g64_mario" then 228 | local min, max = ent:WorldSpaceAABB() 229 | local hbHeight = max.z - min.z 230 | local hbRad = max.x - min.x 231 | ent.G64ObjectId = libsm64.ObjectCreate(ent:GetPos(), hbHeight, hbRad) 232 | objectIds[#objectIds + 1] = ent.G64ObjectId 233 | objects[#objects + 1] = ent 234 | end 235 | end 236 | 237 | local props = ents.GetAll() 238 | for k,v in ipairs(props) do 239 | ProcessNewEntity(v) 240 | end 241 | 242 | hook.Add("OnEntityCreated", "G64_ENTITY_CREATED", function(ent) 243 | ProcessNewEntity(ent) 244 | end) 245 | 246 | --hook.Add("HUDPaint", "ugh", function(ent) 247 | -- local e = libsm64.EntMeshes[1] 248 | -- if IsValid(e) then 249 | -- surface.SetFont( "DermaLarge" ) 250 | -- surface.SetTextPos( 400, 128 ) 251 | -- surface.SetTextColor( 0, 0, 0 ) 252 | -- local a = e:GetAngles() 253 | -- debugoverlay.Line(e:GetPos(), e:GetPos() + a:Up() * 400, 0.1, Color(0,0,255)) 254 | -- debugoverlay.Line(e:GetPos(), e:GetPos() + a:Forward() * 400, 0.1, Color(0,255,0)) 255 | -- debugoverlay.Line(e:GetPos(), e:GetPos() + a:Right() * 400, 0.1, Color(255,0,0)) 256 | -- surface.DrawText( "" .. math.Round(a.z) .. ", " .. math.Round(-a.y) .. ", " .. math.Round(-a.x) ) 257 | -- end 258 | --end) 259 | 260 | local prevTimeScale = -1.0 261 | local prevScaleFactor = -1.0 262 | local noCollidePos = Vector(0, 0, -32768) 263 | local function UpdatePropCollisions() 264 | for k,v in ipairs(libsm64.EntMeshes) do 265 | local trashCan = {} 266 | if IsValid(v) == false or not (libsm64.AllowedEnts[v:GetClass()] or libsm64.AllowedBrushEnts[v:GetClass()]) then 267 | table.insert(trashCan, k) 268 | for j,surfaceId in pairs(surfaceIds[k]) do 269 | libsm64.SurfaceObjectDelete(surfaceId) 270 | end 271 | else 272 | local vPhys = v:GetPhysicsObject() 273 | if vPhys:IsValid() then 274 | if v.CollisionState ~= nil then 275 | local vColState = v:GetPhysicsObject():IsCollisionEnabled() 276 | if v.CollisionState ~= vColState then 277 | v.CollisionState = vColState 278 | libsm64.RemoveCollider(v) 279 | end 280 | else 281 | v.CollisionState = v:GetPhysicsObject():IsCollisionEnabled() 282 | end 283 | end 284 | 285 | local mario = LocalPlayer().MarioEnt 286 | for j,surfaceId in pairs(surfaceIds[k]) do 287 | --if v:GetSolidFlags() ~= 256 then print(v, v:GetSolidFlags()) end 288 | if v:GetCollisionGroup() == COLLISION_GROUP_WORLD or 289 | v.DontCollideWithMario == true or 290 | v == LocalPlayer():GetVehicle() or 291 | (IsValid(mario) and mario.hasVanishCap == true) or 292 | v:IsSolid() == false or 293 | v:GetNWInt("Solidity") == 0 or 294 | (IsValid(mario) and mario.heldObj == v) then 295 | 296 | libsm64.SurfaceObjectMove(surfaceId, noCollidePos, v:GetAngles()) 297 | else 298 | libsm64.SurfaceObjectMove(surfaceId, v:GetPos(), v:GetAngles()) 299 | --local mat = v:GetWorldTransformMatrix() 300 | --local w = math.sqrt(1.0 + mat:GetField(1,1) + mat:GetField(2,2) + mat:GetField(3,3)) / 2.0 301 | --local w4 = 4.0 * w 302 | --local x = (mat:GetField(3,2) - mat:GetField(2,3)) / w4 303 | --local y = (mat:GetField(1,3) - mat:GetField(3,1)) / w4 304 | --local z = (mat:GetField(2,1) - mat:GetField(1,2)) / w4 305 | --print(x,y,z,w) 306 | 307 | --local a = RotMatToAng(v:GetWorldTransformMatrix()) 308 | 309 | --libsm64.SurfaceObjectMoveQ(surfaceId, v:GetPos(), x,y,z,w) 310 | end 311 | end 312 | end 313 | for i=1,#trashCan do 314 | table.remove(surfaceIds, trashCan[i]) 315 | table.remove(libsm64.EntMeshes, trashCan[i]) 316 | end 317 | end 318 | end 319 | 320 | hook.Add("G64GameTick", "G64_UPDATE_COLLISION", function() 321 | UpdatePropCollisions() 322 | 323 | for i = 1, 8 do 324 | if propQueue[1] == nil then break end 325 | AddPropMesh(propQueue[1]) 326 | table.remove(propQueue, 1) 327 | end 328 | 329 | -- Update NPC/Player collision 330 | for i=#objects,1,-1 do 331 | v = objects[i] 332 | if not IsValid(v) or v == LocalPlayer() or (v:IsNPC() and v:GetNoDraw()) then 333 | if objectIds[i] ~= nil and objectIds[i] >= 0 then 334 | libsm64.ObjectDelete(objectIds[i]) 335 | table.remove(objectIds, i) 336 | table.remove(objects, i) 337 | end 338 | elseif (v:IsPlayer() and v:Health() <= 0) then 339 | libsm64.ObjectMove(v.G64ObjectId, noCollidePos) 340 | else 341 | libsm64.ObjectMove(v.G64ObjectId, v:GetPos()) 342 | end 343 | end 344 | 345 | if prevTimeScale ~= GetConVar("host_timescale"):GetFloat() then 346 | libsm64.TimeScale = GetConVar("host_timescale"):GetFloat() 347 | prevTimeScale = libsm64.TimeScale 348 | hook.Call("G64AdjustedTimeScale", nil, libsm64.TimeScale) 349 | end 350 | 351 | if prevScaleFactor ~= GetConVar("g64_scale_factor"):GetFloat() then 352 | libsm64.ScaleFactor = GetConVar("g64_scale_factor"):GetFloat() 353 | prevScaleFactor = libsm64.ScaleFactor 354 | libsm64.SetScaleFactor(libsm64.ScaleFactor) 355 | local newBounds = 160 / libsm64.ScaleFactor 356 | local marioEnt = LocalPlayer().MarioEnt 357 | if IsValid(marioEnt) then 358 | marioEnt.Maxs.x = newBounds 359 | marioEnt.Maxs.y = newBounds 360 | marioEnt.Maxs.z = newBounds 361 | marioEnt.Mins.x = -newBounds 362 | marioEnt.Mins.y = -newBounds 363 | marioEnt.Mins.z = -newBounds 364 | 365 | net.Start("G64_REMOVEINVALIDMARIO") 366 | net.WriteEntity(marioEnt) 367 | net.SendToServer() 368 | end 369 | 370 | -- Recreate prop collisions since their vertices depend on scale factor 371 | for i=#libsm64.EntMeshes,1,-1 do 372 | v = libsm64.EntMeshes[i] 373 | libsm64.RemoveCollider(v) 374 | end 375 | table.Empty(libsm64.EntMeshes) 376 | table.Empty(surfaceIds) 377 | 378 | local props = ents.GetAll() 379 | for k,v in ipairs(props) do 380 | ProcessNewEntity(v) 381 | end 382 | end 383 | end) 384 | 385 | hook.Add("Think", "G64_CL_THINK", function() 386 | libsm64.GeneralUpdate() 387 | 388 | -- Update entity attack timers 389 | local frameTime = FrameTime() 390 | for i=#allEnts,1,-1 do 391 | v = allEnts[i] 392 | if IsValid(v) then 393 | if v.HitStunTimer == nil then 394 | v.HitStunTimer = 0 395 | end 396 | v.HitStunTimer = v.HitStunTimer - frameTime 397 | else 398 | table.remove(allEnts, i) 399 | end 400 | end 401 | end) 402 | 403 | hook.Add("G64UpdatePropCollisions", "G64_INSTANT_PROP_UPDATE", function() 404 | UpdatePropCollisions() 405 | end) 406 | 407 | hook.Add("PreCleanupMap", "G64_CLEANUP_ENTITIES", function() 408 | for k,v in ipairs(libsm64.EntMeshes) do 409 | for j,surfaceId in pairs(surfaceIds[k]) do 410 | libsm64.SurfaceObjectDelete(surfaceId) 411 | end 412 | end 413 | table.Empty(libsm64.EntMeshes) 414 | end) 415 | end) 416 | 417 | hook.Add("ShutDown", "G64_SHUTTING_DOWN", function() 418 | if libsm64.ModuleLoaded == true then 419 | libsm64.GlobalTerminate() 420 | end 421 | end) 422 | 423 | net.Receive("G64_CHANGESURFACEINFO", function(len) 424 | local ent = net.ReadEntity() 425 | ent.G64SurfaceType = net.ReadInt(16) 426 | ent.G64TerrainType = net.ReadUInt(16) 427 | libsm64.RemoveCollider( ent ) 428 | libsm64.AddColliderToQueue( ent ) 429 | end) 430 | 431 | net.Receive("G64_TELEPORTMARIO", function(len) 432 | local mario = net.ReadEntity() 433 | local pos = net.ReadVector() 434 | local ang = net.ReadAngle() 435 | 436 | if IsValid(mario) then 437 | libsm64.SetMarioPosition(mario.MarioId, pos) 438 | libsm64.SetMarioAngle(mario.MarioId, math.rad(ang[2]-90)/(math.pi*math.pi)) 439 | end 440 | end) 441 | 442 | concommand.Add("g64_load_module", function(ply, cmd, args) 443 | LoadSM64Module() 444 | end) 445 | concommand.Add("g64_init", function(ply, cmd, args) 446 | libsm64.GlobalInit() 447 | end) 448 | concommand.Add("g64_terminate", function(ply, cmd, args) 449 | if ply.IsMario == false then 450 | print(libsm64.GlobalTerminate()) 451 | else 452 | print("Please leave Mario mode before running g64_terminate.") 453 | end 454 | end) 455 | concommand.Add("g64_isinit", function(ply, cmd, args) 456 | print(libsm64.IsGlobalInit()) 457 | end) 458 | concommand.Add("g64_purge_map_cache", function(ply, cmd, args) 459 | file.Delete("g64/cache/" .. game.GetMap() .. "_cache.dat") 460 | end) 461 | concommand.Add("g64_config_set", function(ply, cmd, args) 462 | if g64config.Config[args[1]] == nil then MsgC(Color(255,100,100), "[G64] Config contains no key: ", args[1], "\n") return end 463 | 464 | local parsed = tonumber(args[2]) 465 | if parsed ~= nil then 466 | g64config.Config[args[1]] = parsed 467 | else 468 | g64config.Config[args[1]] = args[2] 469 | end 470 | 471 | g64config.Save() 472 | end) 473 | concommand.Add("g64_set_lives", function(ply, cmd, args) 474 | local marioEnt = ply.MarioEnt 475 | if IsValid(marioEnt) then 476 | libsm64.MarioSetLives(marioEnt.MarioId, tonumber(args[1])) 477 | end 478 | end) 479 | 480 | --hook.Remove("HUDPaint", "G64_CL_THINK_DEBUG") 481 | --hook.Add("OnContextMenuOpen", "G64_CTX_OPEN", function() 482 | -- hook.Add("HUDPaint", "G64_CL_THINK_DEBUG", function() 483 | -- local trTab = util.GetPlayerTrace(LocalPlayer()) 484 | -- local tr = util.TraceLine(trTab) 485 | -- local tx, ty = input.GetCursorPos() 486 | -- surface.SetFont( "Default" ) 487 | -- surface.SetTextColor( 255, 255, 255 ) 488 | -- surface.SetTextPos( tx + 30, ty + 30 ) 489 | -- surface.DrawText( tr.Entity:GetClass() ) 490 | -- surface.SetTextPos( tx + 30, ty + 40 ) 491 | -- surface.DrawText( tr.Entity:GetCollisionGroup() ) 492 | -- surface.SetTextPos( tx + 30, ty + 50 ) 493 | -- surface.DrawText( tostring(bit.band(FSOLID_NOT_SOLID, v:GetSolidFlags()) == FSOLID_NOT_SOLID) ) 494 | -- end) 495 | --end) 496 | -- 497 | --hook.Add("OnContextMenuClose", "G64_CTX_CLOSE", function() 498 | -- hook.Remove("HUDPaint", "G64_CL_THINK_DEBUG") 499 | --end) 500 | 501 | --local prevThing = 0 502 | --hook.Remove("Think", "G64_CL_THINK_DEBUG") 503 | --hook.Add("Think", "G64_CL_THINK_DEBUG", function() 504 | -- local automatic = GetConVar("dsp_automatic"):GetInt() 505 | -- if automatic != prevThing then 506 | -- print("dsp_automatic", GetConVar("dsp_automatic"):GetInt()) 507 | -- print("dsp_db_mixdrop", GetConVar("dsp_db_mixdrop"):GetFloat()) 508 | -- print("dsp_mix_max", GetConVar("dsp_mix_max"):GetFloat()) 509 | -- print("dsp_mix_min", GetConVar("dsp_mix_min"):GetFloat()) 510 | -- print("-------------------") 511 | -- prevThing = automatic 512 | -- end 513 | --end) -------------------------------------------------------------------------------- /lua/autorun/client/g64_emotemenu.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | g64emote = g64emote or {} 4 | 5 | local wH = ScrW()/2 6 | local hH = ScrH()/2 7 | 8 | local radialMaterial = Material("vgui/radial") 9 | local mousePos = Vector() 10 | 11 | g64emote.Segments = 8 12 | g64emote.SegAng = math.pi/g64emote.Segments*2 13 | 14 | g64emote.SelRad = 2048 15 | g64emote.OrigPoints = { 16 | { x = wH, y = hH+g64emote.SelRad }, 17 | { x = wH - (hH+g64emote.SelRad - hH) * math.sin(g64emote.SegAng), y = hH + (hH+g64emote.SelRad - hH) * math.cos(g64emote.SegAng) } 18 | } 19 | g64emote.Triangle = { 20 | { x = wH, y = hH }, 21 | { x = 0, y = 0 }, 22 | { x = 0, y = 0 } 23 | } 24 | g64emote.Emotes = { 25 | { 26 | action = "ACT_START_SLEEPING", 27 | name = "Sleep" 28 | }, 29 | { 30 | action = "ACT_COUGHING", 31 | name = "Cough" 32 | }, 33 | { 34 | action = "ACT_SHOCKWAVE_BOUNCE", 35 | name = "Bounce" 36 | }, 37 | { 38 | action = "ACT_GROUND_BONK", 39 | name = "Bonk" 40 | }, 41 | { 42 | action = "ACT_DEATH_EXIT_LAND", 43 | name = "Hard Bonk" 44 | }, 45 | { 46 | action = "ACT_BACKFLIP_LAND", 47 | name = "Haha" 48 | }, 49 | { 50 | action = "ACT_THROWING", 51 | name = "Throw" 52 | }, 53 | { 54 | action = "ACT_HEAVY_THROW", 55 | name = "Heavy Throw" 56 | }, 57 | { 58 | action = "ACT_SHOCKED", 59 | name = "Shock" 60 | }, 61 | { 62 | action = "ACT_PUTTING_ON_CAP", 63 | name = "Adjust Cap" 64 | }, 65 | { 66 | action = "ACT_UNKNOWN_0002020E", 67 | name = "Wave" 68 | }, 69 | { 70 | action = "ACT_BUTT_STUCK_IN_GROUND", 71 | name = "Butt Stuck" 72 | }, 73 | } 74 | 75 | g64emote.CalculateSegments = function(segs) 76 | g64emote.Segments = segs 77 | g64emote.SegAng = math.pi/segs*2 78 | g64emote.SelRad = 2048 79 | g64emote.OrigPoints[2].x = wH - (hH+g64emote.SelRad - hH) * math.sin(g64emote.SegAng) 80 | g64emote.OrigPoints[2].y = hH + (hH+g64emote.SelRad - hH) * math.cos(g64emote.SegAng) 81 | end 82 | 83 | g64emote.ActiveEmotes = {} 84 | 85 | g64emote.LoadActiveEmotes = function() 86 | g64emote.ActiveEmotes = string.Split(GetConVar("g64_active_emotes"):GetString(), ",") 87 | for i=1, #g64emote.ActiveEmotes do 88 | g64emote.ActiveEmotes[i] = tonumber(g64emote.ActiveEmotes[i]) 89 | if g64emote.ActiveEmotes[i] == nil then 90 | table.remove(g64emote.ActiveEmotes, i) 91 | end 92 | end 93 | g64emote.CalculateSegments(#g64emote.ActiveEmotes) 94 | end 95 | 96 | g64emote.Selected = 0 97 | 98 | local function AddHooks() 99 | hook.Add("HUDPaint", "G64_EMOTE_THINK", function() 100 | local marioEnt = LocalPlayer().MarioEnt 101 | if input.IsKeyDown(GetConVar("g64_emotemenu"):GetInt()) and IsValid(marioEnt) and #g64emote.ActiveEmotes > 0 then 102 | if g64emote.MenuOpen == false then 103 | g64emote.PanelContainer:Show() 104 | g64emote.PanelContainer:MakePopup() 105 | end 106 | g64emote.MenuOpen = true 107 | else 108 | if g64emote.MenuOpen == true then 109 | g64emote.PanelContainer:Hide() 110 | g64emote.PanelContainer:MouseCapture(false) 111 | g64emote.PanelContainer:SetMouseInputEnabled(false) 112 | end 113 | g64emote.MenuOpen = false 114 | end 115 | 116 | 117 | if g64emote.MenuOpen == true then 118 | render.SetStencilWriteMask( 0xFF ) 119 | render.SetStencilTestMask( 0xFF ) 120 | render.SetStencilReferenceValue( 0 ) 121 | render.SetStencilCompareFunction( STENCIL_ALWAYS ) 122 | render.SetStencilPassOperation( STENCIL_KEEP ) 123 | render.SetStencilFailOperation( STENCIL_KEEP ) 124 | render.SetStencilZFailOperation( STENCIL_KEEP ) 125 | render.ClearStencil() 126 | 127 | render.SetStencilEnable( true ) 128 | render.SetStencilReferenceValue( 1 ) 129 | render.SetStencilCompareFunction( STENCIL_ALWAYS ) 130 | render.SetStencilPassOperation( STENCIL_REPLACE ) 131 | render.SetStencilTestMask(255) 132 | render.SetStencilWriteMask(255) 133 | 134 | surface.SetDrawColor(255,255,255,255) 135 | surface.SetMaterial(radialMaterial) 136 | surface.DrawTexturedRect(ScrW()/2-256, ScrH()/2-256, 512, 512) 137 | 138 | render.SetStencilReferenceValue( 1 ) 139 | render.SetStencilCompareFunction( STENCIL_EQUAL ) 140 | render.SetStencilPassOperation( STENCIL_NEVER ) 141 | render.SetStencilTestMask(255) 142 | render.SetStencilWriteMask(255) 143 | 144 | surface.SetFont("Default") 145 | surface.SetTextColor(255,255,255) 146 | for i=1, #g64emote.ActiveEmotes do 147 | local angle = math.pi/2 + g64emote.SegAng * (i-1) 148 | local x2 = wH + (256*math.cos(angle)) 149 | local y2 = hH + (256*math.sin(angle)) 150 | surface.SetDrawColor(0,0,0,230) 151 | surface.DrawLine(wH, hH, x2, y2) 152 | local x3 = wH + (180*math.cos(angle+g64emote.SegAng/2)) 153 | local y3 = hH + (180*math.sin(angle+g64emote.SegAng/2)) 154 | local segText = g64emote.Emotes[g64emote.ActiveEmotes[i]].name 155 | local w, h = surface.GetTextSize(segText) 156 | surface.SetTextPos(x3 - w/2, y3 - h/2) 157 | surface.DrawText(segText) 158 | end 159 | 160 | mousePos.x, mousePos.y = input.GetCursorPos() 161 | local mouseDist = math.sqrt(((wH - mousePos.x) * (wH - mousePos.x)) + ((hH - mousePos.y) * (hH - mousePos.y))) 162 | mousePos.x = mousePos.x - wH 163 | mousePos.y = mousePos.y - hH 164 | mousePos:Normalize() 165 | 166 | if mouseDist > 110 then 167 | local angle = math.atan2(mousePos.y, mousePos.x) + math.pi + math.pi/2 168 | 169 | g64emote.Selected = math.floor(angle/(math.pi*2)*g64emote.Segments) + 1 170 | g64emote.Selected = math.fmod(g64emote.Selected, g64emote.Segments) 171 | if g64emote.Selected == 0 then g64emote.Selected = g64emote.Segments end 172 | 173 | angle = math.floor(angle/g64emote.SegAng)*g64emote.SegAng 174 | local cosAng = math.cos(angle) 175 | local sinAng = math.sin(angle) 176 | 177 | g64emote.Triangle[2].x = wH + (g64emote.OrigPoints[1].x - wH) * cosAng - (g64emote.OrigPoints[1].y - hH) * sinAng 178 | g64emote.Triangle[2].y = hH + (g64emote.OrigPoints[1].y - hH) * cosAng + (g64emote.OrigPoints[1].x - wH) * sinAng 179 | g64emote.Triangle[3].x = wH + (g64emote.OrigPoints[2].x - wH) * cosAng - (g64emote.OrigPoints[2].y - hH) * sinAng 180 | g64emote.Triangle[3].y = hH + (g64emote.OrigPoints[2].y - hH) * cosAng + (g64emote.OrigPoints[2].x - wH) * sinAng 181 | 182 | surface.SetDrawColor(163,163,163,100) 183 | if g64emote.Segments > 2 then 184 | draw.NoTexture() 185 | surface.DrawPoly(g64emote.Triangle) 186 | elseif g64emote.Segments == 2 then 187 | mousePos.x, mousePos.y = input.GetCursorPos() 188 | if mousePos.x > wH then 189 | surface.DrawRect(wH, hH-256, 256, 512) 190 | g64emote.Selected = 2 191 | else 192 | surface.DrawRect(wH-256, hH-256, 256, 512) 193 | g64emote.Selected = 1 194 | end 195 | elseif g64emote.Segments == 1 then 196 | surface.DrawRect(wH-256, hH-256, 512, 512) 197 | g64emote.Selected = 1 198 | end 199 | else 200 | g64emote.Selected = 0 201 | end 202 | 203 | render.SetStencilEnable( false ) 204 | else 205 | if g64emote.Selected > 0 then 206 | local action = g64types.SM64MarioAction[g64emote.Emotes[g64emote.ActiveEmotes[g64emote.Selected]].action] 207 | marioEnt:SetMarioAction(action) 208 | g64emote.Selected = 0 209 | end 210 | end 211 | end) 212 | end 213 | 214 | local function CreatePanels() 215 | if g64emote.PanelContainer then g64emote.PanelContainer:Remove() end 216 | 217 | g64emote.PanelContainer = vgui.Create("DPanel") 218 | g64emote.PanelContainer:SetPos(ScrW()/2-256, ScrH()/2-256) 219 | g64emote.PanelContainer:SetSize(512, 512) 220 | g64emote.PanelContainer:SetDrawBackground(false) 221 | g64emote.PanelContainer:Hide() 222 | 223 | hook.Remove("HUDPaint", "G64_EMOTE_THINK") 224 | AddHooks() 225 | end 226 | 227 | g64emote.LoadActiveEmotes() 228 | timer.Remove("WaitToCreatePanels") 229 | timer.Create("WaitToCreatePanels", 0.1, 1, CreatePanels) -------------------------------------------------------------------------------- /lua/autorun/client/g64_hud.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | include("includes/g64_sprites.lua") 3 | include("includes/g64_types.lua") 4 | 5 | UI_SCALE = 6 6 | ICON_SIZE = 16 * UI_SCALE 7 | HUD_TOP_Y = 15 8 | SCREEN_WIDTH = ScrW() 9 | SCREEN_HEIGHT = ScrH() 10 | ASPECT_RATIO = SCREEN_WIDTH / SCREEN_HEIGHT 11 | 12 | local aw, ah = 0 13 | 14 | local isSwimming = false 15 | local emphasizingFlag = false 16 | local sPowerMeterVisibleTimer = 0 17 | local sPowerMeterStoredHealth = 8 18 | local sPowerMeterHUD = { 19 | animation = 0, 20 | x = ScrW()/2-32*UI_SCALE, 21 | y = 240+35 22 | } 23 | 24 | local function GFX_DIMENSIONS_FROM_LEFT_EDGE(v) 25 | return (SCREEN_WIDTH * 0.5 - SCREEN_HEIGHT * 0.5 * ASPECT_RATIO + v * UI_SCALE) 26 | end 27 | local function GFX_DIMENSIONS_FROM_RIGHT_EDGE(v) 28 | return (SCREEN_WIDTH * 0.5 + SCREEN_HEIGHT * 0.5 * ASPECT_RATIO - v * UI_SCALE) 29 | end 30 | local function GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(v) 31 | return (math.floor(GFX_DIMENSIONS_FROM_LEFT_EDGE(v))) 32 | end 33 | local function GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(v) 34 | return (math.ceil(GFX_DIMENSIONS_FROM_RIGHT_EDGE(v))) 35 | end 36 | 37 | local function animate_power_meter_emphasized() 38 | if emphasizingFlag == false then 39 | if sPowerMeterVisibleTimer == 45 then 40 | sPowerMeterHUD.animation = g64types.SM64PowerMeterAnimation.POWER_METER_DEEMPHASIZING 41 | end 42 | else 43 | sPowerMeterVisibleTimer = 0 44 | end 45 | end 46 | 47 | local function animate_power_meter_deemphasizing() 48 | local speed = 5 49 | if sPowerMeterHUD.y >= 181 then 50 | speed = 3 51 | end 52 | if sPowerMeterHUD.y >= 191 then 53 | speed = 2 54 | end 55 | if sPowerMeterHUD.y >= 196 then 56 | speed = 1 57 | end 58 | 59 | sPowerMeterHUD.y = sPowerMeterHUD.y + speed 60 | 61 | if sPowerMeterHUD.y >= 201 then 62 | sPowerMeterHUD.y = 200 63 | sPowerMeterHUD.animation = g64types.SM64PowerMeterAnimation.POWER_METER_VISIBLE 64 | end 65 | end 66 | 67 | local function animate_power_meter_hiding() 68 | sPowerMeterHUD.y = sPowerMeterHUD.y + 20 69 | if sPowerMeterHUD.y >= 301 then 70 | sPowerMeterHUD.animation = g64types.SM64PowerMeterAnimation.POWER_METER_HIDDEN 71 | sPowerMeterVisibleTimer = 0 72 | end 73 | end 74 | 75 | local function handle_power_meter_actions(numHealthWedges) 76 | if numHealthWedges < 8 and sPowerMeterStoredHealth == 8 and sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_HIDDEN then 77 | sPowerMeterHUD.animation = g64types.SM64PowerMeterAnimation.POWER_METER_EMPHASIZED 78 | sPowerMeterHUD.y = 166 79 | end 80 | 81 | if numHealthWedges == 8 and sPowerMeterStoredHealth == 7 then 82 | sPowerMeterVisibleTimer = 0 83 | end 84 | 85 | if numHealthWedges == 8 and sPowerMeterVisibleTimer > 45 then 86 | sPowerMeterHUD.animation = g64types.SM64PowerMeterAnimation.POWER_METER_HIDING 87 | end 88 | 89 | sPowerMeterStoredHealth = numHealthWedges 90 | 91 | if isSwimming == true then 92 | if sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_HIDDEN or sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_EMPHASIZED then 93 | sPowerMeterHUD.animation = g64types.SM64PowerMeterAnimation.POWER_METER_DEEMPHASIZING 94 | sPowerMeterHUD.y = 166 95 | end 96 | sPowerMeterVisibleTimer = 0 97 | end 98 | end 99 | 100 | local function SetCurrentAtlasDimensions(w, h) 101 | aw, ah = w, h 102 | end 103 | 104 | local function DrawSprite(sprite, x, y, rw, rh) 105 | local w, h = sprite.w, sprite.h 106 | local u0, v0 = sprite.u, sprite.v 107 | local u1, v1 = u0 + w / aw, v0 + h / ah 108 | local du = 0.5 / aw -- half pixel anticorrection 109 | local dv = 0.5 / ah -- half pixel anticorrection 110 | u0, v0 = (u0 - du) / (1 - 2 * du), (v0 - dv) / (1 - 2 * dv) 111 | u1, v1 = (u1 - du) / (1 - 2 * du), (v1 - dv) / (1 - 2 * dv) 112 | if false then u1 = u1-0.5/aw end 113 | surface.DrawTexturedRectUV(x, y, rw, rh, u0, v0, u1, v1) 114 | end 115 | 116 | local function DrawNumber(num, x, y) 117 | local num_str = tostring(num) 118 | for i = 1, #num_str do 119 | local c = num_str:sub(i,i) 120 | DrawSprite(g64sprites.Characters[c], x + (i-1) * 12*UI_SCALE, y, ICON_SIZE, ICON_SIZE) 121 | end 122 | end 123 | 124 | hook.Remove("HUDPaint", "G64_DRAW_HUD") 125 | hook.Add("HUDPaint", "G64_DRAW_HUD", function() 126 | if GetConVar("g64_hud_enable"):GetBool() == false then return end 127 | local lPlayer = LocalPlayer() 128 | local marioEnt = lPlayer.MarioEnt 129 | if not IsValid(marioEnt) or not lPlayer.IsMario then return end 130 | 131 | local topUp = HUD_TOP_Y*UI_SCALE 132 | local showX = 1 133 | 134 | local starCount = 0 135 | local coinCount = lPlayer.CoinCount 136 | local marioNumLives = lPlayer.LivesCount 137 | local marioHealth = marioEnt.marioHealth 138 | if marioHealth < 0 then marioHealth = 0 end 139 | if marioHealth > 8 then marioHealth = 8 end 140 | 141 | if marioNumLives == nil then return end 142 | 143 | if starCount >= 100 then 144 | showX = 0 145 | end 146 | 147 | surface.SetDrawColor(color_white) 148 | surface.SetMaterial(g64utils.UIMat) 149 | SetCurrentAtlasDimensions(g64sprites.UI.tex_width, g64sprites.UI.tex_height) 150 | if marioNumLives >= 0 then 151 | DrawSprite(g64sprites.UI.mario_head, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(22), topUp, ICON_SIZE, ICON_SIZE) 152 | DrawSprite(g64sprites.UI.times, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(38), topUp, ICON_SIZE, ICON_SIZE) 153 | DrawNumber(marioNumLives, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(54), topUp) 154 | end 155 | 156 | DrawSprite(g64sprites.UI.coin, GFX_DIMENSIONS_FROM_RIGHT_EDGE(320-168), topUp, ICON_SIZE, ICON_SIZE) 157 | DrawSprite(g64sprites.UI.times, GFX_DIMENSIONS_FROM_RIGHT_EDGE(320-184), topUp, ICON_SIZE, ICON_SIZE) 158 | DrawNumber(coinCount, GFX_DIMENSIONS_FROM_RIGHT_EDGE(320-198), topUp) 159 | 160 | DrawSprite(g64sprites.UI.star, GFX_DIMENSIONS_FROM_RIGHT_EDGE(78), topUp, ICON_SIZE, ICON_SIZE) 161 | if showX == 1 then 162 | DrawSprite(g64sprites.UI.times, GFX_DIMENSIONS_FROM_RIGHT_EDGE(78)+ICON_SIZE, topUp, ICON_SIZE, ICON_SIZE) 163 | end 164 | DrawNumber(starCount, (showX * 14 * UI_SCALE) + GFX_DIMENSIONS_FROM_RIGHT_EDGE(78 - 16), topUp) 165 | 166 | local healthX = ScrW()/2-32*UI_SCALE 167 | local healthY = (240-sPowerMeterHUD.y-35)*UI_SCALE 168 | local wedgeSprite = g64sprites.Health["wedge_" .. marioEnt.marioHealth] 169 | 170 | surface.SetMaterial(g64utils.HealthMat) 171 | SetCurrentAtlasDimensions(g64sprites.Health.tex_width, g64sprites.Health.tex_height) 172 | DrawSprite(g64sprites.Health.bg_0, healthX, healthY, 32*UI_SCALE, 64*UI_SCALE) 173 | DrawSprite(g64sprites.Health.bg_1, healthX+31*UI_SCALE, healthY, 32*UI_SCALE, 64*UI_SCALE) 174 | if marioHealth > 0 and wedgeSprite then 175 | DrawSprite(wedgeSprite, healthX+15*UI_SCALE, healthY+16*UI_SCALE, 32*UI_SCALE, 64*UI_SCALE) 176 | end 177 | end) 178 | 179 | hook.Add("G64GameTick", "G64_HUD_TICK", function() 180 | local marioEnt = LocalPlayer().MarioEnt 181 | if not IsValid(marioEnt) or not LocalPlayer().IsMario then return end 182 | 183 | UI_SCALE = GetConVar("g64_hud_scale"):GetInt() 184 | ICON_SIZE = 16 * UI_SCALE 185 | 186 | if marioEnt.marioHurtCounter > 0 then 187 | emphasizingFlag = true 188 | else 189 | emphasizingFlag = false 190 | end 191 | 192 | if sPowerMeterHUD.animation ~= g64types.SM64PowerMeterAnimation.POWER_METER_HIDING then 193 | handle_power_meter_actions(marioEnt.marioHealth) 194 | end 195 | 196 | if sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_HIDDEN then 197 | return 198 | end 199 | 200 | if sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_EMPHASIZED then 201 | animate_power_meter_emphasized() 202 | elseif sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_DEEMPHASIZING then 203 | animate_power_meter_deemphasizing() 204 | elseif sPowerMeterHUD.animation == g64types.SM64PowerMeterAnimation.POWER_METER_HIDING then 205 | animate_power_meter_hiding() 206 | end 207 | 208 | sPowerMeterVisibleTimer = sPowerMeterVisibleTimer + 1 209 | end) 210 | 211 | hook.Add("OnScreenSizeChanged", "G64_SCREEN_SIZE_CHANGED_HUD", function(ow, oh) 212 | SCREEN_WIDTH = ScrW() 213 | SCREEN_HEIGHT = ScrH() 214 | ASPECT_RATIO = SCREEN_WIDTH / SCREEN_HEIGHT 215 | sPowerMeterHUD.x = ScrW()/2-32*UI_SCALE 216 | end) -------------------------------------------------------------------------------- /lua/autorun/client/g64_lang.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | language.Add( "g64_mario", "Mario" ) 4 | 5 | language.Add( "tool.g64surfacechanger.name", "Surface Changer" ) 6 | language.Add( "tool.g64surfacechanger.desc", "Change the G64 surface of an object" ) 7 | language.Add( "tool.g64surfacechanger.surf", "Surface type" ) 8 | language.Add( "tool.g64surfacechanger.terr", "Terrain type" ) 9 | language.Add( "tool.g64surfacechanger.left", "Apply selected Surface / Terrain Type to an object" ) 10 | 11 | language.Add( "tool.g64surfacechanger.stone", "Stone" ) 12 | language.Add( "tool.g64surfacechanger.grass", "Grass" ) 13 | language.Add( "tool.g64surfacechanger.snow", "Snow" ) 14 | language.Add( "tool.g64surfacechanger.sand", "Sand" ) 15 | language.Add( "tool.g64surfacechanger.spooky", "Spooky" ) 16 | language.Add( "tool.g64surfacechanger.water", "Water" ) 17 | language.Add( "tool.g64surfacechanger.slide", "Slide" ) 18 | 19 | language.Add( "tool.g64surfacechanger.default", "Default" ) 20 | language.Add( "tool.g64surfacechanger.burning", "Burning" ) 21 | language.Add( "tool.g64surfacechanger.hangable", "Hangable" ) 22 | language.Add( "tool.g64surfacechanger.slow", "Slow" ) 23 | language.Add( "tool.g64surfacechanger.very_slippery", "Very Slippery" ) 24 | language.Add( "tool.g64surfacechanger.slippery", "Slippery" ) 25 | language.Add( "tool.g64surfacechanger.not_slippery", "Not Slippery" ) 26 | language.Add( "tool.g64surfacechanger.shallow_quicksand", "Shallow Quicksand" ) 27 | language.Add( "tool.g64surfacechanger.deep_quicksand", "Deep Quicksand" ) 28 | language.Add( "tool.g64surfacechanger.instant_quicksand", "Instant Quicksand" ) 29 | language.Add( "tool.g64surfacechanger.ice", "Ice" ) 30 | language.Add( "tool.g64surfacechanger.hard", "Hard" ) 31 | language.Add( "tool.g64surfacechanger.hard_slippery", "Hard Slippery" ) 32 | language.Add( "tool.g64surfacechanger.hard_very_slippery", "Hard Very Slippery" ) 33 | language.Add( "tool.g64surfacechanger.hard_not_slippery", "Hard Not Slippery" ) 34 | language.Add( "tool.g64surfacechanger.vertical_wind", "Vertical Wind" ) 35 | language.Add( "tool.g64surfacechanger.horizontal_wind", "Horizontal Wind" ) 36 | language.Add( "tool.g64surfacechanger.quicksand", "Quicksand" ) 37 | language.Add( "tool.g64surfacechanger.noise_default", "Noise Default" ) 38 | language.Add( "tool.g64surfacechanger.vanish_cap_walls", "Vanish Cap Wall" ) -------------------------------------------------------------------------------- /lua/autorun/client/g64_spawnmenu.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | include("includes/g64_types.lua") 4 | include("includes/g64_config.lua") 5 | 6 | hook.Add("AddToolMenuCategories", "G64_CREATE_SPAWN_MENU", function() 7 | spawnmenu.AddToolCategory("Utilities", "G64", "#G64") 8 | end) 9 | 10 | hook.Add("PopulateToolMenu", "G64_CREATE_MENU_SETTINGS", function() 11 | g64config.Load() 12 | 13 | spawnmenu.AddToolMenuOption("Utilities", "G64", "G64_Settings", "#Settings", "", "", function(panel) 14 | panel:ClearControls() 15 | 16 | local genHeader = vgui.Create("DLabel") 17 | genHeader:SetText("General") 18 | genHeader:SetTextColor(Color(0,0,0)) 19 | genHeader:SetFont("DermaDefaultBold") 20 | 21 | local filePathEntry = vgui.Create("DTextEntry") 22 | filePathEntry:SetPlaceholderText("No file specified") 23 | filePathEntry:SetValue(GetConVar("g64_rompath"):GetString()) 24 | filePathEntry.OnEnter = function(self) 25 | GetConVar("g64_rompath"):SetString(self:GetValue()) 26 | end 27 | 28 | local browseButton = vgui.Create("DButton") 29 | browseButton:SetText("Browse...") 30 | browseButton.DoClick = function() 31 | local filePath = libsm64.OpenFileDialog() 32 | if not isnumber(filePath) then 33 | GetConVar("g64_rompath"):SetString(filePath) 34 | filePathEntry:SetValue(filePath) 35 | else 36 | if filePath == 0 then 37 | chat.AddText(Color(255, 100, 100), "[G64] Failed to open file.") 38 | elseif filePath == 1 then 39 | chat.AddText(Color(255, 100, 100), "[G64] File browser unsupported on non-windows computers.") 40 | end 41 | end 42 | end 43 | 44 | local toggleUpdates = vgui.Create("DCheckBoxLabel") 45 | toggleUpdates:SetText("Auto-update") 46 | toggleUpdates:SetTextColor(Color(0,0,0)) 47 | toggleUpdates:SetTooltip([[Allows the addon to update libsm64 48 | and the G64 module upon disconnect.]]) 49 | if GetConVar("g64_auto_update"):GetBool() then toggleUpdates:SetValue(true) 50 | else toggleUpdates:SetValue(false) end 51 | toggleUpdates:SetConVar("g64_auto_update") 52 | 53 | local toggleInterp = vgui.Create("DCheckBoxLabel") 54 | toggleInterp:SetText("Enable mesh interpolation") 55 | toggleInterp:SetTextColor(Color(0,0,0)) 56 | toggleInterp:SetTooltip([[Makes Mario's mesh move smoother but will 57 | cause artifacts and may cause a slight performance drop.]]) 58 | if GetConVar("g64_interpolation"):GetBool() then toggleInterp:SetValue(true) 59 | else toggleInterp:SetValue(false) end 60 | toggleInterp:SetConVar("g64_interpolation") 61 | 62 | local toggleCapMusic = vgui.Create("DCheckBoxLabel") 63 | toggleCapMusic:SetText("Play cap music") 64 | toggleCapMusic:SetTextColor(Color(0,0,0)) 65 | toggleCapMusic:SetTooltip([[Plays the wing cap or metal cap theme 66 | when picking up a cap.]]) 67 | if GetConVar("g64_cap_music"):GetBool() then toggleCapMusic:SetValue(true) 68 | else toggleCapMusic:SetValue(false) end 69 | toggleCapMusic:SetConVar("g64_cap_music") 70 | 71 | local rspnOnDeath = vgui.Create("DCheckBoxLabel") 72 | rspnOnDeath:SetText("Respawn Mario on Game Over") 73 | rspnOnDeath:SetTextColor(Color(0,0,0)) 74 | rspnOnDeath:SetTooltip([[Puts you back in Mario mode after 75 | you run out of lives and die.]]) 76 | if GetConVar("g64_respawn_mario_on_death"):GetBool() then rspnOnDeath:SetValue(true) 77 | else rspnOnDeath:SetValue(false) end 78 | rspnOnDeath:SetConVar("g64_respawn_mario_on_death") 79 | 80 | local volumeSlider = vgui.Create("DNumSlider") 81 | volumeSlider:SetText("Volume") 82 | volumeSlider:SetMin(0) 83 | volumeSlider:SetMax(1) 84 | volumeSlider:SetDecimals(2) 85 | volumeSlider:SetConVar("g64_global_volume") 86 | volumeSlider:SetDark(true) 87 | volumeSlider.OnValueChanged = function(panel, value) 88 | if libsm64 ~= nil then libsm64.SetGlobalVolume(value) end 89 | end 90 | 91 | local hudToggle = vgui.Create("DCheckBoxLabel") 92 | hudToggle:SetText("Enable HUD") 93 | hudToggle:SetTextColor(Color(0,0,0)) 94 | hudToggle:SetTooltip([[Enables the HUD.]]) 95 | if GetConVar("g64_hud_enable"):GetBool() then hudToggle:SetValue(true) 96 | else hudToggle:SetValue(false) end 97 | hudToggle:SetConVar("g64_hud_enable") 98 | 99 | local hudScaleSlider = vgui.Create("DNumSlider") 100 | hudScaleSlider:SetText("HUD scale") 101 | hudScaleSlider:SetMin(0) 102 | hudScaleSlider:SetMax(6) 103 | hudScaleSlider:SetDecimals(0) 104 | hudScaleSlider:SetConVar("g64_hud_scale") 105 | hudScaleSlider:SetDark(true) 106 | 107 | local colHeader = vgui.Create("DLabel") 108 | colHeader:SetText("Colors") 109 | colHeader:SetTextColor(Color(0,0,0)) 110 | colHeader:SetFont("DermaDefaultBold") 111 | 112 | local colorListView = vgui.Create("DListView") 113 | colorListView:SetMultiSelect(false) 114 | colorListView:AddColumn("Body Part") 115 | colorListView:AddLine("Overalls") 116 | colorListView:AddLine("Shirt / Hat") 117 | colorListView:AddLine("Skin") 118 | colorListView:AddLine("Hair") 119 | colorListView:AddLine("Gloves") 120 | colorListView:AddLine("Shoes") 121 | colorListView:SetHeight(150) 122 | 123 | local colorMixer = vgui.Create("DColorMixer") 124 | colorMixer.ValueChanged = function(panel, color) 125 | local rowIndex, pan = colorListView:GetSelectedLine() 126 | g64config.Config.MarioColors[rowIndex] = { color.r, color.g, color.b } 127 | g64config.Save() 128 | GetConVar("g64_upd_col_flag"):SetBool(true) 129 | end 130 | 131 | colorListView.OnRowSelected = function(panel, rowIndex, row) 132 | local colTab = g64config.Config.MarioColors[rowIndex] 133 | colorMixer:SetColor(Color(colTab[1], colTab[2], colTab[3], 255)) 134 | end 135 | colorListView:SelectFirstItem() 136 | 137 | local resetColorsButton = vgui.Create("DButton") 138 | resetColorsButton:SetText("Reset colors") 139 | resetColorsButton.DoClick = function() 140 | g64config.Config.MarioColors = table.Copy(g64types.DefaultMarioColors) 141 | local rowIndex, pan = colorListView:GetSelectedLine() 142 | local colTab = g64config.Config.MarioColors[rowIndex] 143 | colorMixer:SetColor(Color(colTab[1], colTab[2], colTab[3], 255)) 144 | g64config.Save() 145 | end 146 | 147 | panel:AddItem(genHeader) 148 | panel:AddItem(filePathEntry) 149 | panel:AddItem(browseButton) 150 | panel:AddItem(toggleUpdates) 151 | panel:AddItem(toggleInterp) 152 | panel:AddItem(toggleCapMusic) 153 | panel:AddItem(rspnOnDeath) 154 | panel:AddItem(volumeSlider) 155 | panel:AddItem(hudToggle) 156 | panel:AddItem(hudScaleSlider) 157 | panel:AddItem(colHeader) 158 | panel:AddItem(colorListView) 159 | panel:AddItem(colorMixer) 160 | panel:AddItem(resetColorsButton) 161 | end) 162 | 163 | spawnmenu.AddToolMenuOption("Utilities", "G64", "G64_MusicPlayer", "#Music Player", "", "", function(panel) 164 | panel:ClearControls() 165 | g64utils.GlobalInit() 166 | 167 | local musicListView = vgui.Create("DListView") 168 | musicListView:SetMultiSelect(false) 169 | musicListView:AddColumn("Song") 170 | musicListView:AddLine("Star Catch Fanfare") 171 | musicListView:AddLine("Title Theme") 172 | musicListView:AddLine("Bob-Omb Battlefield") 173 | musicListView:AddLine("Inside the Castle Walls") 174 | musicListView:AddLine("Dire, Dire Docks") 175 | musicListView:AddLine("Lethal Lava Land") 176 | musicListView:AddLine("Koopa's Theme") 177 | musicListView:AddLine("Snow Mountain") 178 | musicListView:AddLine("Slider") 179 | musicListView:AddLine("Haunted House") 180 | musicListView:AddLine("Piranha Plant's Lullaby") 181 | musicListView:AddLine("Cave Dungeon") 182 | musicListView:AddLine("Star Select") 183 | musicListView:AddLine("Powerful Mario") 184 | musicListView:AddLine("Metallic Mario") 185 | musicListView:AddLine("Koopa's Message") 186 | musicListView:AddLine("Koopa's Road") 187 | musicListView:AddLine("High Score") 188 | musicListView:AddLine("Merry Go-Round") 189 | musicListView:AddLine("Race Fanfare") 190 | musicListView:AddLine("Star Spawn") 191 | musicListView:AddLine("Stage Boss") 192 | musicListView:AddLine("Koopa Clear") 193 | musicListView:AddLine("Looping Steps") 194 | musicListView:AddLine("Ultimate Koopa") 195 | musicListView:AddLine("Staff Roll") 196 | musicListView:AddLine("Correct Solution") 197 | musicListView:AddLine("Toad's Message") 198 | musicListView:AddLine("Peach's Message") 199 | musicListView:AddLine("Game Start") 200 | musicListView:AddLine("Ultimate Koopa Clear") 201 | musicListView:AddLine("Ending Demo") 202 | musicListView:AddLine("File Select") 203 | musicListView:AddLine("Lakitu") 204 | musicListView:SetHeight(400) 205 | function musicListView:DoDoubleClick(lineId, line) 206 | PlayTrack(lineId) 207 | end 208 | 209 | local playButton = vgui.Create("DButton") 210 | playButton:SetText("Play") 211 | playButton.DoClick = function() 212 | local rowIndex, pan = musicListView:GetSelectedLine() 213 | PlayTrack(rowIndex) 214 | end 215 | 216 | local stopButton = vgui.Create("DButton") 217 | stopButton:SetText("Stop") 218 | stopButton.DoClick = function() 219 | local rowIndex, pan = musicListView:GetSelectedLine() 220 | StopAllTracks() 221 | end 222 | 223 | panel:AddItem(musicListView) 224 | panel:AddItem(playButton) 225 | panel:AddItem(stopButton) 226 | end) 227 | 228 | spawnmenu.AddToolMenuOption("Utilities", "G64", "G64_KeyBinds", "#Key Binds", "", "", function(panel) 229 | panel:ClearControls() 230 | 231 | local header_forward = vgui.Create("DLabel") 232 | header_forward:SetText("Move forward") 233 | header_forward:SetTextColor(Color(0,0,0)) 234 | local binder_forward = vgui.Create("DBinder") 235 | binder_forward:SetConVar("g64_forward") 236 | 237 | local header_back = vgui.Create("DLabel") 238 | header_back:SetText("Move back") 239 | header_back:SetTextColor(Color(0,0,0)) 240 | local binder_back = vgui.Create("DBinder") 241 | binder_back:SetConVar("g64_back") 242 | 243 | local header_moveleft = vgui.Create("DLabel") 244 | header_moveleft:SetText("Move left") 245 | header_moveleft:SetTextColor(Color(0,0,0)) 246 | local binder_moveleft = vgui.Create("DBinder") 247 | binder_moveleft:SetConVar("g64_moveleft") 248 | 249 | local header_moveright = vgui.Create("DLabel") 250 | header_moveright:SetText("Move right") 251 | header_moveright:SetTextColor(Color(0,0,0)) 252 | local binder_moveright = vgui.Create("DBinder") 253 | binder_moveright:SetConVar("g64_moveright") 254 | 255 | local header_jump = vgui.Create("DLabel") 256 | header_jump:SetText("Jump") 257 | header_jump:SetTextColor(Color(0,0,0)) 258 | local binder_jump = vgui.Create("DBinder") 259 | binder_jump:SetConVar("g64_jump") 260 | 261 | local header_duck = vgui.Create("DLabel") 262 | header_duck:SetText("Crouch") 263 | header_duck:SetTextColor(Color(0,0,0)) 264 | local binder_duck = vgui.Create("DBinder") 265 | binder_duck:SetConVar("g64_duck") 266 | 267 | local header_attack = vgui.Create("DLabel") 268 | header_attack:SetText("Attack") 269 | header_attack:SetTextColor(Color(0,0,0)) 270 | local binder_attack = vgui.Create("DBinder") 271 | binder_attack:SetConVar("g64_attack") 272 | 273 | local header_pickup = vgui.Create("DLabel") 274 | header_pickup:SetText("Pick Up") 275 | header_pickup:SetTextColor(Color(0,0,0)) 276 | local binder_pickup = vgui.Create("DBinder") 277 | binder_pickup:SetConVar("g64_pickup") 278 | 279 | local header_remove = vgui.Create("DLabel") 280 | header_remove:SetText("Remove Mario") 281 | header_remove:SetTextColor(Color(0,0,0)) 282 | local binder_remove = vgui.Create("DBinder") 283 | binder_remove:SetConVar("g64_remove") 284 | 285 | local header_emotemenu = vgui.Create("DLabel") 286 | header_emotemenu:SetText("Emote menu") 287 | header_emotemenu:SetTextColor(Color(0,0,0)) 288 | local binder_emotemenu = vgui.Create("DBinder") 289 | binder_emotemenu:SetConVar("g64_emotemenu") 290 | 291 | local header_freemove = vgui.Create("DLabel") 292 | header_freemove:SetText("Free move") 293 | header_freemove:SetTextColor(Color(0,0,0)) 294 | local binder_freemove = vgui.Create("DBinder") 295 | binder_freemove:SetConVar("g64_freemove") 296 | 297 | 298 | panel:AddItem(header_forward) 299 | panel:AddItem(binder_forward) 300 | panel:AddItem(header_back) 301 | panel:AddItem(binder_back) 302 | panel:AddItem(header_moveleft) 303 | panel:AddItem(binder_moveleft) 304 | panel:AddItem(header_moveright) 305 | panel:AddItem(binder_moveright) 306 | panel:AddItem(header_jump) 307 | panel:AddItem(binder_jump) 308 | panel:AddItem(header_duck) 309 | panel:AddItem(binder_duck) 310 | panel:AddItem(header_attack) 311 | panel:AddItem(binder_attack) 312 | panel:AddItem(header_pickup) 313 | panel:AddItem(binder_pickup) 314 | panel:AddItem(header_remove) 315 | panel:AddItem(binder_remove) 316 | panel:AddItem(header_emotemenu) 317 | panel:AddItem(binder_emotemenu) 318 | panel:AddItem(header_freemove) 319 | panel:AddItem(binder_freemove) 320 | end) 321 | 322 | spawnmenu.AddToolMenuOption("Utilities", "G64", "G64_Gamepad", "#Gamepad", "", "", function(panel) 323 | panel:ClearControls() 324 | 325 | local cur_connected = vgui.Create("RichText") 326 | cur_connected:SetVerticalScrollbarEnabled(false) 327 | function cur_connected:PerformLayout() 328 | self:SetContentAlignment(5) 329 | self:SetFontInternal("DermaDefaultBold") 330 | end 331 | 332 | local sens_slider = vgui.Create("DNumSlider") 333 | sens_slider:SetText("Camera sensitivity") 334 | sens_slider:SetMin(0) 335 | sens_slider:SetMax(200) 336 | sens_slider:SetDecimals(0) 337 | sens_slider:SetConVar("g64_gp_sensitivity") 338 | sens_slider:SetDark(true) 339 | 340 | 341 | panel:AddItem(cur_connected) 342 | panel:AddItem(sens_slider) 343 | 344 | hook.Remove("Think", "G64_UPDATE_GAMEPAD_STATUS") 345 | hook.Add("Think", "G64_UPDATE_GAMEPAD_STATUS", function() 346 | if IsValid(cur_connected) then 347 | local gp_name = libsm64.GetGamepadName() 348 | cur_connected:SetText("") 349 | if gp_name == "No gamepad connected." then 350 | cur_connected:InsertColorChange(200,0,0,255) 351 | cur_connected:AppendText(libsm64.GetGamepadName()) 352 | else 353 | cur_connected:InsertColorChange(0,0,0,255) 354 | cur_connected:AppendText("Connected gamepad: ") 355 | cur_connected:InsertColorChange(0,200,0,255) 356 | cur_connected:AppendText(libsm64.GetGamepadName()) 357 | end 358 | end 359 | end) 360 | end) 361 | 362 | spawnmenu.AddToolMenuOption("Utilities", "G64", "G64_Emotes", "#Emotes", "", "", function(panel) 363 | panel:ClearControls() 364 | g64emote.LoadActiveEmotes() 365 | 366 | local emoteStates = {} 367 | for i=1, #g64emote.Emotes do 368 | emoteStates[i] = false 369 | end 370 | for i=1, #g64emote.ActiveEmotes do 371 | emoteStates[g64emote.ActiveEmotes[i]] = true 372 | end 373 | 374 | local emotesHeader = vgui.Create("DLabel") 375 | emotesHeader:SetText("Emote List") 376 | emotesHeader:SetTextColor(Color(0,0,0)) 377 | emotesHeader:SetFont("DermaDefaultBold") 378 | emotesHeader:SetWrap(true) 379 | emotesHeader:SetAutoStretchVertical(true) 380 | 381 | local activeHeader = vgui.Create("DLabel") 382 | activeHeader:SetText("Active Emotes") 383 | activeHeader:SetTextColor(Color(0,0,0)) 384 | activeHeader:SetFont("DermaDefaultBold") 385 | activeHeader:SetWrap(true) 386 | activeHeader:SetAutoStretchVertical(true) 387 | 388 | local activeListView = vgui.Create("DListView") 389 | activeListView:SetMultiSelect(false) 390 | activeListView:AddColumn("Active Emote") 391 | activeListView:SetHeight(200) 392 | for i=1, #emoteStates do 393 | if emoteStates[i] == true then 394 | activeListView:AddLine(g64emote.Emotes[i].name) 395 | end 396 | end 397 | activeListView.RefreshList = function() 398 | activeListView:Clear() 399 | table.Empty(g64emote.ActiveEmotes) 400 | for i=1, #emoteStates do 401 | if emoteStates[i] == true then 402 | table.insert(g64emote.ActiveEmotes, i) 403 | activeListView:AddLine(g64emote.Emotes[i].name) 404 | end 405 | end 406 | GetConVar("g64_active_emotes"):SetString(table.concat(g64emote.ActiveEmotes, ",")) 407 | g64emote.CalculateSegments(#g64emote.ActiveEmotes) 408 | end 409 | activeListView.OnRowSelected = function(panel, rowIndex, row) 410 | activeListView:ClearSelection() 411 | end 412 | 413 | local function AddActiveEmote(index) 414 | emoteStates[index] = not emoteStates[index] 415 | activeListView.RefreshList() 416 | end 417 | 418 | local emotesListView = vgui.Create("DListView") 419 | emotesListView:SetMultiSelect(false) 420 | emotesListView:AddColumn("Emote") 421 | for i=1, #g64emote.Emotes do 422 | emotesListView:AddLine(g64emote.Emotes[i].name) 423 | end 424 | emotesListView:SetHeight(400) 425 | function emotesListView:DoDoubleClick(lineId, line) 426 | AddActiveEmote(lineId) 427 | end 428 | 429 | local addButton = vgui.Create("DButton") 430 | addButton:SetText("Add / Remove") 431 | addButton.DoClick = function() 432 | local rowIndex, pan = emotesListView:GetSelectedLine() 433 | AddActiveEmote(rowIndex) 434 | end 435 | 436 | panel:AddItem(emotesHeader) 437 | panel:AddItem(emotesListView) 438 | panel:AddItem(addButton) 439 | panel:AddItem(activeHeader) 440 | panel:AddItem(activeListView) 441 | end) 442 | end) 443 | 444 | G64EntityCategories = { 445 | "Main", 446 | "Items", 447 | "Caps" 448 | } 449 | 450 | hook.Add("G64SpawnMenuPopulate", "G64_SPAWN_MENU_POPULATE", function(panel, tree, node) 451 | local cats = {} 452 | local ents = list.Get("g64_entities") 453 | 454 | if ents then 455 | for k,v in pairs(ents) do 456 | v.Category = v.Category or "Other Stuff" 457 | cats[v.Category] = cats[v.Category] or {} 458 | v.ClassName = k 459 | v.PrintName = v.Name 460 | table.insert(cats[v.Category], v) 461 | end 462 | end 463 | 464 | local entnode = tree:AddNode("Entities", "icon16/bricks.png") 465 | local ListPanel = vgui.Create("ContentContainer", panel) 466 | ListPanel:SetVisible(false) 467 | ListPanel:SetTriggerSpawnlistChange(false) 468 | 469 | entnode.DoPopulate = function(self) 470 | ListPanel:Clear() 471 | 472 | for k1,v1 in next, G64EntityCategories do 473 | local k,v = v1, cats[v1] 474 | local Header = vgui.Create("ContentHeader", ListPanel) 475 | Header:SetText(k) 476 | ListPanel:Add(Header) 477 | 478 | for k,ent in SortedPairsByMemberValue(v, "PrintName") do 479 | spawnmenu.CreateContentIcon("g64_entity", ListPanel, { 480 | nicename = ent.PrintName or ent.ClassName, 481 | spawnname = ent.ClassName, 482 | material = ent.Material, 483 | admin = false, 484 | icongenerator = ent.IconGenerator 485 | }) 486 | end 487 | end 488 | end 489 | 490 | entnode.DoClick = function(self) 491 | self:DoPopulate() 492 | panel:SwitchPanel(ListPanel) 493 | end 494 | 495 | local FirstNode = tree:Root():GetChildNode(0) 496 | if IsValid(FirstNode) then 497 | FirstNode:InternalDoClick() 498 | end 499 | end) 500 | 501 | spawnmenu.AddCreationTab("G64", function() 502 | local contentPanel = vgui.Create("SpawnmenuContentPanel") 503 | contentPanel:CallPopulateHook("G64SpawnMenuPopulate") 504 | return contentPanel 505 | end, "icon16/controller.png", 50, "Mario in Garry's Mod!") 506 | 507 | local blankIconMat = Material("vgui/entities/g64_blankicon") 508 | spawnmenu.AddContentType("g64_entity", function(container, data) 509 | if not data.nicename then return end 510 | if not data.spawnname then return end 511 | 512 | local icon = vgui.Create("ContentIcon", container) 513 | icon:SetContentType("g64_entity") 514 | icon:SetSpawnName(data.spawnname) 515 | icon:SetName(data.nicename) 516 | if data.material then icon:SetMaterial(data.material) end 517 | if data.icongenerator then 518 | icon.Padding = 0 519 | icon.Image:SetVisible(true) 520 | icon.Image:SetPos(0, 0) 521 | icon.Image:NoClipping(false) 522 | function icon.Image:Paint(w,h) 523 | g64utils.GlobalInit() 524 | local w2 = w - icon.Padding * 2 525 | local h2 = h - icon.Padding * 2 526 | local u0, v0 = data.icongenerator.u[1], data.icongenerator.v[1] 527 | local u1, v1 = data.icongenerator.u[2], data.icongenerator.v[2] 528 | 529 | render.PushFilterMag(TEXFILTER.ANISOTROPIC) 530 | render.PushFilterMin(TEXFILTER.ANISOTROPIC) 531 | 532 | surface.SetMaterial(blankIconMat) 533 | surface.DrawTexturedRect(3 + icon.Border, 3 + icon.Border, 128 - 8 - icon.Border * 2, 128 - 8 - icon.Border * 2) 534 | 535 | render.PopFilterMin() 536 | render.PopFilterMag() 537 | 538 | render.PushFilterMag(TEXFILTER.LINEAR) 539 | 540 | if data.icongenerator.tint then surface.SetDrawColor(data.icongenerator.tint:Unpack()) 541 | else surface.SetDrawColor(color_white) end 542 | surface.SetMaterial(data.icongenerator.material) 543 | surface.DrawTexturedRectUV(w2*0.175+icon.Padding+3, h2*0.175+icon.Padding+3, w2*0.65, h2*0.65, u0, v0, u1, v1) 544 | 545 | render.PopFilterMag() 546 | 547 | icon:Paint(icon:GetSize()) 548 | end 549 | function icon:PerformLayout() 550 | if ( self:IsDown() && !self.Dragging ) then 551 | self.Padding = 6 552 | else 553 | self.Padding = 0 554 | end 555 | end 556 | end 557 | icon:SetAdminOnly(data.admin and true or false) 558 | icon:SetColor(Color(0, 0, 0, 255)) 559 | 560 | icon.DoClick = function() 561 | RunConsoleCommand("g64_spawnsent", data.spawnname) 562 | surface.PlaySound("ui/buttonclickrelease.wav") 563 | end 564 | 565 | icon.OpenMenu = function(icon) 566 | local menu = DermaMenu() 567 | menu:AddOption("Copy to clipboard", function() 568 | SetClipboardText(data.spawnname) 569 | end):SetIcon("icon16/page_copy.png") 570 | menu:AddOption("Spawn using toolgun", function() 571 | RunConsoleCommand("gmod_tool", "creator") 572 | RunConsoleCommand("creator_type", "0") 573 | RunConsoleCommand("creator_name", data.spawnname) 574 | end):SetIcon("icon16/brick_add.png") 575 | menu:Open() 576 | end 577 | 578 | if IsValid(container) then 579 | container:Add(icon) 580 | end 581 | 582 | return icon 583 | end) -------------------------------------------------------------------------------- /lua/autorun/g64_convars.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | CreateConVar("g64_vanishcap_timer", "600", FCVAR_CHEAT, "Timer for the vanish cap (default: 600)", 0, 65535) 4 | CreateConVar("g64_metalcap_timer", "600", FCVAR_CHEAT, "Timer for the metal cap (default: 600)", 0, 65535) 5 | CreateConVar("g64_wingcap_timer", "1800", FCVAR_CHEAT, "Timer for the wing cap (default: 1800)", 0, 65535) 6 | CreateConVar("g64_process_displacements", "1", FCVAR_CHEAT) 7 | CreateConVar("g64_process_static_props", "1", FCVAR_CHEAT) 8 | CreateConVar("g64_scale_factor", "2.5", bit.bor(FCVAR_CHEAT, FCVAR_REPLICATED), "The scale factor of Mario (default: 2.5)", 0.1, 8) 9 | CreateConVar("g64_respawn_mario_on_death", "1", bit.bor(FCVAR_ARCHIVE, FCVAR_USERINFO)) 10 | 11 | if CLIENT then 12 | CreateClientConVar("g64_debug_collision", "0", true, false) 13 | CreateClientConVar("g64_debug_rays", "0", true, false) 14 | CreateClientConVar("g64_interpolation", "1", true, false) 15 | CreateClientConVar("g64_rompath", "", true, false) 16 | CreateClientConVar("g64_lib_version", "", true, false) 17 | CreateClientConVar("g64_upd_col_flag", "0", true, false) 18 | CreateClientConVar("g64_cap_music", "1", true, false) 19 | CreateClientConVar("g64_global_volume", "1.0", true, false, "", 0.0, 1.0) 20 | CreateClientConVar("g64_auto_update", "1", true, false) 21 | CreateClientConVar("g64_active_emotes", "", true, false) 22 | CreateClientConVar("g64_disable_cache", "0", true, false) 23 | CreateClientConVar("g64_hud_scale", "4", true, false) 24 | CreateClientConVar("g64_hud_enable", "1", true, false) 25 | CreateClientConVar("g64_cam_distance", "500", true, false) 26 | 27 | CreateClientConVar("g64_forward", KEY_W, true) 28 | CreateClientConVar("g64_back", KEY_S, true) 29 | CreateClientConVar("g64_moveleft", KEY_A, true) 30 | CreateClientConVar("g64_moveright", KEY_D, true) 31 | CreateClientConVar("g64_jump", KEY_SPACE, true) 32 | CreateClientConVar("g64_duck", KEY_LCONTROL, true) 33 | CreateClientConVar("g64_attack", MOUSE_LEFT, true) 34 | CreateClientConVar("g64_pickup", MOUSE_RIGHT, true) 35 | CreateClientConVar("g64_remove", KEY_R, true) 36 | CreateClientConVar("g64_emotemenu", KEY_LALT, true) 37 | CreateClientConVar("g64_freemove", KEY_V, true) 38 | 39 | CreateClientConVar("g64_gp_sensitivity", "75", true, false) 40 | else 41 | local function fixupProp( ply, ent, hitpos, mins, maxs ) 42 | local entPos = ent:GetPos() 43 | local endposD = ent:LocalToWorld( mins ) 44 | local tr_down = util.TraceLine( { 45 | start = entPos, 46 | endpos = endposD, 47 | filter = { ent, ply } 48 | } ) 49 | 50 | local endposU = ent:LocalToWorld( maxs ) 51 | local tr_up = util.TraceLine( { 52 | start = entPos, 53 | endpos = endposU, 54 | filter = { ent, ply } 55 | } ) 56 | 57 | -- Both traces hit meaning we are probably inside a wall on both sides, do nothing 58 | if ( tr_up.Hit && tr_down.Hit ) then return end 59 | 60 | if ( tr_down.Hit ) then ent:SetPos( entPos + ( tr_down.HitPos - endposD ) ) end 61 | if ( tr_up.Hit ) then ent:SetPos( entPos + ( tr_up.HitPos - endposU ) ) end 62 | end 63 | 64 | local function TryFixPropPosition( ply, ent, hitpos ) 65 | fixupProp( ply, ent, hitpos, Vector( ent:OBBMins().x, 0, 0 ), Vector( ent:OBBMaxs().x, 0, 0 ) ) 66 | fixupProp( ply, ent, hitpos, Vector( 0, ent:OBBMins().y, 0 ), Vector( 0, ent:OBBMaxs().y, 0 ) ) 67 | fixupProp( ply, ent, hitpos, Vector( 0, 0, ent:OBBMins().z ), Vector( 0, 0, ent:OBBMaxs().z ) ) 68 | end 69 | 70 | local function CanPlayerSpawnSENT( ply, EntityName ) 71 | 72 | --local isAdmin = ( IsValid( ply ) && ply:IsAdmin() ) || game.SinglePlayer() 73 | 74 | -- Make sure this is a SWEP 75 | local sent = scripted_ents.GetStored( EntityName ) 76 | if ( sent == nil ) then 77 | 78 | -- Is this in the SpawnableEntities list? 79 | local SpawnableEntities = list.Get( "SpawnableG64Entities" ) 80 | if ( !SpawnableEntities ) then return false end 81 | local EntTable = SpawnableEntities[ EntityName ] 82 | if ( !EntTable ) then return false end 83 | --if ( EntTable.AdminOnly && !isAdmin ) then return false end 84 | return true 85 | 86 | end 87 | 88 | -- We need a spawn function. The SENT can then spawn itself properly 89 | local SpawnFunction = scripted_ents.GetMember( EntityName, "SpawnFunction" ) 90 | if ( !isfunction( SpawnFunction ) ) then return false end 91 | 92 | -- You're not allowed to spawn this unless you're an admin! 93 | --if ( !scripted_ents.GetMember( EntityName, "G64Spawnable" ) && !isAdmin ) then return false end 94 | --if ( scripted_ents.GetMember( EntityName, "AdminOnly" ) && !isAdmin ) then return false end 95 | 96 | return true 97 | 98 | end 99 | 100 | --[[--------------------------------------------------------- 101 | Name: Spawn_SENT 102 | Desc: Console Command for a player to spawn different items 103 | -----------------------------------------------------------]] 104 | local function G64_Spawn_SENT( ply, EntityName, tr ) 105 | print(ply, EntityName) 106 | 107 | -- We don't support this command from dedicated server console 108 | if ( !IsValid( ply ) ) then return end 109 | 110 | if ( EntityName == nil ) then return end 111 | 112 | if ( !CanPlayerSpawnSENT( ply, EntityName ) ) then return end 113 | 114 | -- Ask the gamemode if it's ok to spawn this 115 | if ( !gamemode.Call( "PlayerSpawnSENT", ply, EntityName ) ) then return end 116 | 117 | if ( !tr ) then 118 | 119 | local vStart = ply:EyePos() 120 | local vForward = ply:GetAimVector() 121 | 122 | tr = util.TraceLine( { 123 | start = vStart, 124 | endpos = vStart + ( vForward * 4096 ), 125 | filter = ply 126 | } ) 127 | 128 | end 129 | 130 | local entity = nil 131 | local PrintName = nil 132 | local sent = scripted_ents.GetStored( EntityName ) 133 | 134 | if ( sent ) then 135 | 136 | local sent = sent.t 137 | 138 | ClassName = EntityName 139 | 140 | local SpawnFunction = scripted_ents.GetMember( EntityName, "SpawnFunction" ) 141 | if ( !SpawnFunction ) then return end -- Fallback to default behavior below? 142 | 143 | entity = SpawnFunction( sent, ply, tr, EntityName ) 144 | 145 | if ( IsValid( entity ) ) then 146 | entity:SetCreator( ply ) 147 | end 148 | 149 | ClassName = nil 150 | 151 | PrintName = sent.PrintName 152 | 153 | else 154 | 155 | -- Spawn from list table 156 | local SpawnableEntities = list.Get( "SpawnableG64Entities" ) 157 | if ( !SpawnableEntities ) then return end 158 | 159 | local EntTable = SpawnableEntities[ EntityName ] 160 | if ( !EntTable ) then return end 161 | 162 | PrintName = EntTable.PrintName 163 | 164 | local SpawnPos = tr.HitPos + tr.HitNormal * 16 165 | if ( EntTable.NormalOffset ) then SpawnPos = SpawnPos + tr.HitNormal * EntTable.NormalOffset end 166 | 167 | -- Make sure the spawn position is not out of bounds 168 | local oobTr = util.TraceLine( { 169 | start = tr.HitPos, 170 | endpos = SpawnPos, 171 | mask = MASK_SOLID_BRUSHONLY 172 | } ) 173 | 174 | if ( oobTr.Hit ) then 175 | SpawnPos = oobTr.HitPos + oobTr.HitNormal * ( tr.HitPos:Distance( oobTr.HitPos ) / 2 ) 176 | end 177 | 178 | entity = ents.Create( EntTable.ClassName ) 179 | entity:SetPos( SpawnPos ) 180 | 181 | if ( EntTable.KeyValues ) then 182 | for k, v in pairs( EntTable.KeyValues ) do 183 | entity:SetKeyValue( k, v ) 184 | end 185 | end 186 | 187 | if ( EntTable.Material ) then 188 | entity:SetMaterial( EntTable.Material ) 189 | end 190 | 191 | entity:Spawn() 192 | entity:Activate() 193 | 194 | DoPropSpawnedEffect( entity ) 195 | 196 | if ( EntTable.DropToFloor ) then 197 | entity:DropToFloor() 198 | end 199 | 200 | end 201 | 202 | if ( !IsValid( entity ) ) then return end 203 | 204 | TryFixPropPosition( ply, entity, tr.HitPos ) 205 | 206 | if ( IsValid( ply ) ) then 207 | gamemode.Call( "PlayerSpawnedSENT", ply, entity ) 208 | end 209 | 210 | undo.Create( "SENT" ) 211 | undo.SetPlayer( ply ) 212 | undo.AddEntity( entity ) 213 | if ( PrintName ) then 214 | undo.SetCustomUndoText( "Undone " .. PrintName ) 215 | end 216 | undo.Finish( "Scripted Entity (" .. tostring( EntityName ) .. ")" ) 217 | 218 | ply:AddCleanup( "sents", entity ) 219 | entity:SetVar( "Player", ply ) 220 | 221 | end 222 | concommand.Add( "g64_spawnsent", function( ply, cmd, args ) G64_Spawn_SENT( ply, args[ 1 ] ) end) 223 | end 224 | 225 | function RegisterG64Entity(t, name) 226 | list.Set("SpawnableG64Entities", name, { 227 | PrintName = t.PrintName, 228 | ClassName = name, 229 | Category = t.Category, 230 | G64Spawnable = t.G64Spawnable, 231 | 232 | NormalOffset = t.NormalOffset, 233 | DropToFloor = t.DropToFloor, 234 | Author = t.Author, 235 | AdminOnly = t.AdminOnly, 236 | Information = t.Information, 237 | ScriptedEntityType = t.ScriptedEntityType, 238 | IconOverride = t.IconOverride 239 | }) 240 | end -------------------------------------------------------------------------------- /lua/autorun/g64_init.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile("includes/g64_luabsp.lua") 2 | AddCSLuaFile("includes/g64_config.lua") 3 | AddCSLuaFile("includes/g64_types.lua") 4 | AddCSLuaFile("includes/g64_utils.lua") 5 | AddCSLuaFile() 6 | 7 | game.AddParticles("particles/sm64.pcf") 8 | PrecacheParticleSystem("ground_pound") 9 | PrecacheParticleSystem("mario_dust") 10 | PrecacheParticleSystem("mario_horiz_star") 11 | PrecacheParticleSystem("mario_vert_star") 12 | PrecacheParticleSystem("mario_fire") 13 | PrecacheParticleSystem("coin_pickup") 14 | 15 | REQUIRED_LIBSM64 = 3 16 | REQUIRED_MODULE = 2 17 | 18 | if CLIENT then 19 | 20 | local moduleName = "gmcl_g64_win64.dll" 21 | local updaterName = "gmcl_g64_updater_win64.dll" 22 | --if(jit.arch == "x86") then 23 | -- moduleName = "gmcl_g64_win32.dll" 24 | --end 25 | 26 | include("includes/g64_config.lua") 27 | 28 | local initWorldCalled = false 29 | 30 | local function LoadFailure() 31 | libsm64.ModuleExists = false 32 | libsm64.ModuleLoaded = false 33 | libsm64.MapLoaded = false 34 | libsm64.ScaleFactor = 2 35 | end 36 | 37 | local function LoadAndCacheMapGeometry(timeout) 38 | local mapStatus = "[G64] Getting map geometry..." 39 | if not LocalPlayer().SM64LoadedMap then 40 | net.Start("G64_UPLOADCOLORS") 41 | for i=1, 6 do 42 | net.WriteUInt(g64config.Config.MarioColors[i][1], 8) 43 | net.WriteUInt(g64config.Config.MarioColors[i][2], 8) 44 | net.WriteUInt(g64config.Config.MarioColors[i][3], 8) 45 | end 46 | net.SendToServer() 47 | 48 | timer.Simple(timeout, function() 49 | net.Start("G64_LOADMAPGEO") 50 | print("[G64] Getting map geometry...") 51 | net.SendToServer() 52 | 53 | hook.Add("HUDPaint", "G64_DRAW_MAP_STATUS", function() 54 | surface.SetFont("Default") 55 | w, h = surface.GetTextSize(mapStatus) 56 | 57 | surface.SetDrawColor( 0, 0, 0, 200 ) 58 | surface.DrawRect( ScrW()-(w+40), ScrH()-50, w+20, 38 ) 59 | surface.SetTextColor(255, 255, 255) 60 | surface.SetTextPos(ScrW()-(w+30), ScrH()-40) 61 | surface.DrawText(mapStatus) 62 | end) 63 | end) 64 | 65 | local vertices = {} 66 | local dispVertices = {} 67 | local startTime = CurTime() 68 | local worldMin = Vector() 69 | local worldMax = Vector() 70 | local xDelta, yDelta 71 | local xChunks, yChunks 72 | local xDispChunks, yDispChunks 73 | local tileSize = 1000 74 | local dispTileSize = 500 75 | local xOffset, yOffset 76 | local chunkMin, chunkMax 77 | local dispChunkMin, dispChunkMax 78 | 79 | local function InitMapDownload() 80 | worldMin = Vector(net.ReadInt(16), net.ReadInt(16), net.ReadInt(16)) 81 | worldMax = Vector(net.ReadInt(16), net.ReadInt(16), net.ReadInt(16)) 82 | xDelta = worldMax.x - worldMin.x 83 | yDelta = worldMax.y - worldMin.y 84 | xOffset = worldMin.x + 16384 85 | yOffset = worldMin.y + 16384 86 | xChunks = math.ceil(xDelta / tileSize) 87 | yChunks = math.ceil(yDelta / tileSize) 88 | xDispChunks = math.ceil(xDelta / dispTileSize) 89 | yDispChunks = math.ceil(yDelta / dispTileSize) 90 | if GetConVar("g64_debug_collision"):GetBool() then 91 | print("[G64] Chunks: ", xChunks, yChunks) 92 | print("[G64] World bounds: ", worldMin.x, worldMin.y, worldMax.x, worldMax.y) 93 | end 94 | for i = 1, xChunks do 95 | vertices[i] = {} 96 | for j = 1, yChunks do 97 | vertices[i][j] = {} 98 | end 99 | end 100 | for i = 1, xDispChunks do 101 | dispVertices[i] = {} 102 | for j = 1, yDispChunks do 103 | dispVertices[i][j] = {} 104 | end 105 | end 106 | libsm64.XDelta = xDelta 107 | libsm64.YDelta = yDelta 108 | libsm64.WorldMin = worldMin 109 | libsm64.WorldMax = worldMax 110 | libsm64.XChunks = xChunks 111 | libsm64.YChunks = yChunks 112 | libsm64.XDispChunks = xDispChunks 113 | libsm64.YDispChunks = yDispChunks 114 | end 115 | 116 | function PlaceTriangleInChunks(vecs, vertTable, nChunksX, nChunksY, vertOffset) 117 | local triVerts = {} 118 | local chunksToPlaceIn = {} 119 | local triMin = Vector(16384, 16384) 120 | local triMax = Vector(-16384, -16384) 121 | 122 | if vertOffset == nil then vertOffset = Vector() end 123 | 124 | for i = 1, 3 do 125 | local x = math.Clamp(vecs[i].x + vertOffset.x, worldMin.x, worldMax.x) 126 | local y = math.Clamp(vecs[i].y + vertOffset.y, worldMin.y, worldMax.y) 127 | local z = vecs[i].z + vertOffset.z 128 | local xChunk, yChunk 129 | xChunk = math.floor((x + 16384 - xOffset - 100) / xDelta * nChunksX) -- Subtract then add 100 units for vertices that may be on chunk borders 130 | yChunk = math.floor((y + 16384 - yOffset - 100) / yDelta * nChunksY) 131 | if xChunk < triMin.x then triMin.x = xChunk end 132 | if yChunk < triMin.y then triMin.y = yChunk end 133 | xChunk = math.floor((x + 16384 - xOffset + 100) / xDelta * nChunksX) 134 | yChunk = math.floor((y + 16384 - yOffset + 100) / yDelta * nChunksY) 135 | if xChunk > triMax.x then triMax.x = xChunk + 1 end 136 | if yChunk > triMax.y then triMax.y = yChunk + 1 end 137 | table.insert(triVerts, Vector(x, y, z)) 138 | end 139 | triMin.x = math.Clamp(triMin.x, 0, nChunksX-1) 140 | triMin.y = math.Clamp(triMin.y, 0, nChunksY-1) 141 | triMax.x = math.Clamp(triMax.x, 0, nChunksX-1) 142 | triMax.y = math.Clamp(triMax.y, 0, nChunksY-1) 143 | 144 | for u = triMin.x, triMax.x do 145 | for v = triMin.y, triMax.y do 146 | chunksToPlaceIn[tostring(u) .. " " .. tostring(v)] = { u, v } 147 | end 148 | end 149 | 150 | for k,m in pairs(chunksToPlaceIn) do 151 | local x = m[1] + 1 152 | local y = m[2] + 1 153 | for l,n in ipairs(triVerts) do 154 | if vertTable[x] == nil or vertTable[x][y] == nil then print("Vertex array out of bounds at: ", x, y) end 155 | table.insert(vertTable[x][y], n) 156 | end 157 | end 158 | end 159 | 160 | function ParseBSP(finished_cb) 161 | include("includes/g64_luabsp.lua") 162 | local bsp = luabsp.LoadMap(game:GetMap()) 163 | print("[G64] Parsing .bsp file (version " .. bsp.version .. ")...") 164 | 165 | -- Displacements aren't included in map phys geometry, 166 | -- so we have to do the next cursed thing: bsp parsing 167 | local function ParseDisplacements(callback) 168 | if GetConVar("g64_process_displacements"):GetBool() then 169 | mapStatus = "[G64] Processing displacements..." 170 | print(mapStatus) 171 | bsp:LoadDisplacementVertices(function() 172 | for i = 1, #bsp.displacement_vertices, 3 do 173 | local vecs = { 174 | bsp.displacement_vertices[i], 175 | bsp.displacement_vertices[i+1], 176 | bsp.displacement_vertices[i+2] 177 | } 178 | 179 | PlaceTriangleInChunks(vecs, dispVertices, xDispChunks, yDispChunks) 180 | end 181 | return callback() 182 | end) 183 | else 184 | return callback() 185 | end 186 | end 187 | 188 | -- Neither are prop_statics 189 | local function ParseStaticProps(callback) 190 | if GetConVar("g64_process_static_props"):GetBool() then 191 | mapStatus = "[G64] Processing static props..." 192 | print(mapStatus) 193 | 194 | local function RotateVertices(verts, ang) 195 | local cosa = math.cos(ang.y * 0.017453) 196 | local sina = math.sin(ang.y * 0.017453) 197 | 198 | local cosb = math.cos(ang.x * 0.017453) 199 | local sinb = math.sin(ang.x * 0.017453) 200 | 201 | local cosc = math.cos(ang.z * 0.017453) 202 | local sinc = math.sin(ang.z * 0.017453) 203 | 204 | local Axx = cosa*cosb 205 | local Axy = cosa*sinb*sinc - sina*cosc 206 | local Axz = cosa*sinb*cosc + sina*sinc 207 | 208 | local Ayx = sina*cosb 209 | local Ayy = sina*sinb*sinc + cosa*cosc 210 | local Ayz = sina*sinb*cosc - cosa*sinc 211 | 212 | local Azx = -sinb 213 | local Azy = cosb*sinc 214 | local Azz = cosb*cosc 215 | 216 | local returnVerts = {} 217 | for i = 1, #verts do 218 | local px = verts[i].x 219 | local py = verts[i].y 220 | local pz = verts[i].z 221 | 222 | local nx = Axx*px + Axy*py + Axz*pz 223 | local ny = Ayx*px + Ayy*py + Ayz*pz 224 | local nz = Azx*px + Azy*py + Azz*pz 225 | 226 | returnVerts[i] = Vector(nx, ny, nz) 227 | end 228 | 229 | return returnVerts 230 | end 231 | 232 | 233 | bsp:LoadStaticProps(function() 234 | for i = 1, #bsp.static_props do 235 | local props = {} 236 | for k,v in ipairs(bsp.static_props[i].names) do 237 | local csEnt = ents.CreateClientProp(v) 238 | props[v] = {} 239 | if csEnt:GetPhysicsObject():IsValid() then 240 | for k,convex in pairs(csEnt:GetPhysicsObject():GetMeshConvexes()) do 241 | for k,vertex in pairs(convex) do 242 | table.insert(props[v], vertex.pos) 243 | end 244 | end 245 | end 246 | csEnt:Remove() 247 | end 248 | for k,v in ipairs(bsp.static_props[i].entries) do 249 | local propVerts = props[v.PropType] 250 | if propVerts ~= nil and v.Solid == 6 then 251 | local rotatedVerts = RotateVertices(propVerts, v.Angles) 252 | for j = 1, #rotatedVerts, 3 do 253 | local vecs = { 254 | rotatedVerts[j], 255 | rotatedVerts[j+1], 256 | rotatedVerts[j+2] 257 | } 258 | 259 | PlaceTriangleInChunks(vecs, vertices, xChunks, yChunks, v.Origin) 260 | end 261 | end 262 | end 263 | end 264 | return callback() 265 | end) 266 | else 267 | return callback() 268 | end 269 | end 270 | 271 | 272 | ParseDisplacements(function() 273 | ParseStaticProps(function() 274 | return finished_cb() 275 | end) 276 | end) 277 | end 278 | 279 | net.Receive("G64_LOADMAPGEO", function(len, ply) 280 | local msg = net.ReadUInt(8) 281 | if msg == 0 then 282 | -- Setup variables n stuff 283 | InitMapDownload() 284 | elseif msg == 1 then 285 | -- Process map phys geometry 286 | local vertCount = net.ReadUInt(32) 287 | local tileArea = tileSize * tileSize 288 | for i = 1, vertCount, 3 do 289 | local v1 = Vector(net.ReadInt(16), net.ReadInt(16), net.ReadInt(16)) 290 | local v2 = Vector(net.ReadInt(16), net.ReadInt(16), net.ReadInt(16)) 291 | local v3 = Vector(net.ReadInt(16), net.ReadInt(16), net.ReadInt(16)) 292 | local vecs = { v1, v2, v3 } 293 | 294 | PlaceTriangleInChunks(vecs, vertices, xChunks, yChunks) 295 | end 296 | elseif msg == 2 then 297 | ParseBSP(function() 298 | 299 | local endTime = CurTime() 300 | local deltaTime = endTime - startTime 301 | print("[G64] Received map geometry!") 302 | 303 | libsm64.MapVertices = vertices 304 | libsm64.DispVertices = dispVertices 305 | if GetConVar("g64_disable_cache"):GetBool() == false then 306 | mapStatus = "[G64] Caching map geometry..." 307 | g64utils.WriteMapCache(filename, vertices, dispVertices) 308 | end 309 | libsm64.MapLoaded = true 310 | 311 | hook.Remove("HUDPaint", "G64_DRAW_MAP_STATUS") 312 | hook.Run("G64Initialized") 313 | 314 | end) 315 | end 316 | end) 317 | end 318 | end 319 | 320 | function InitializeWorld(timeout) 321 | if initWorldCalled == true then return end 322 | initWorldCalled = true 323 | 324 | if jit.arch == "x86" then 325 | libsm64 = {} 326 | LoadFailure() 327 | chat.AddText(Color(255, 100, 100), "[G64] You are on 32-bit Garry's Mod. G64 only works in 64-bit mode. Follow the instructions here to switch to 64-bit: ", Color(86, 173, 255), "https://github.com/ckosmic/g64#installation\n") 328 | return 329 | end 330 | 331 | if GetConVar("g64_auto_update"):GetBool() == true then 332 | local updaterResult = -1 333 | if file.Exists("lua/bin/" .. updaterName, "MOD") then 334 | require("g64_updater") 335 | local currentVersion = GetConVar("g64_lib_version"):GetString() 336 | if currentVersion == "" or file.Exists("lua/bin/" .. moduleName, "MOD") == false then 337 | // Force download if there is no module available 338 | currentVersion = "0.0.0" 339 | end 340 | 341 | // 0 = Up to date 342 | // 1 = Successfully updated 343 | // > 1 = Error updating 344 | updaterResult = g64updater.UpdateG64From(currentVersion) 345 | else 346 | print("[G64] Failed to check for updates: Updater module is missing.") 347 | end 348 | 349 | if updaterResult > 1 then 350 | libsm64 = {} 351 | LoadFailure() 352 | chat.AddText(Color(255, 100, 100), "[G64] Failed to update G64's library package. Check the console for more info.") 353 | return 354 | end 355 | end 356 | 357 | if file.Exists("lua/bin/" .. moduleName, "MOD") then 358 | require("g64") 359 | 360 | GetConVar("g64_lib_version"):SetString(libsm64.GetPackageVersion()) 361 | 362 | if libsm64.GetPackageVersion == nil then 363 | -- Pre-auto-updater check 364 | chat.AddText(Color(255, 100, 100), "[G64] Your G64 binary module and libsm64 versions are outdated! Please download the latest versions of both from ", Color(86, 173, 255), "https://github.com/ckosmic/g64/releases/latest", Color(255, 100, 100), ". (This next version comes with an optional auto-updater so that's this process will be way easier after you update.)\n") 365 | libsm64.ModuleOutdated = true 366 | libsm64.LibSM64Outdated = true 367 | if not game.SinglePlayer() then -- Don't load outdated libsm64 in multi just in case of incompatibilities 368 | LoadFailure() 369 | return 370 | end 371 | else 372 | -- Post auto-updater check 373 | libsm64.PackageVersion = libsm64.GetPackageVersion() 374 | libsm64.LibSM64Version = libsm64.GetLibVersion() 375 | libsm64.PackageOutdated = false 376 | 377 | print("[G64] Loaded G64 binary module! (Package version "..libsm64.PackageVersion..")") 378 | end 379 | 380 | libsm64.ModuleExists = true 381 | libsm64.ModuleLoaded = true 382 | libsm64.MapLoaded = false 383 | libsm64.ScaleFactor = GetConVar("g64_scale_factor"):GetFloat() 384 | 385 | libsm64.SetScaleFactor(libsm64.ScaleFactor) 386 | 387 | libsm64.AllowedEnts = { 388 | prop_physics = true, 389 | prop_dynamic = true, 390 | prop_vehicle = true, 391 | prop_vehicle_airboat = true, 392 | prop_vehicle_apc = true, 393 | prop_vehicle_driveable = true, 394 | prop_vehicle_jeep = true, 395 | prop_vehicle_prisoner_pod = true, 396 | prop_door_rotating = true, 397 | gmod_sent_vehicle_fphysics_base = true, 398 | } 399 | libsm64.AllowedBrushEnts = { 400 | func_door = true, 401 | func_door_rotating = true, 402 | func_movelinear = true, 403 | func_tracktrain = true, 404 | func_wall = true, 405 | func_breakable = true, 406 | func_brush = true, 407 | func_detail = true, 408 | func_lod = true, 409 | func_rotating = true, 410 | func_physbox = true, 411 | func_useableladder = true, 412 | func_platrot = true, 413 | func_pushable = true, 414 | } 415 | libsm64.EntMeshes = {} 416 | libsm64.TimeScale = 1.0 417 | libsm64.SetGlobalVolume(GetConVar("g64_global_volume"):GetFloat()) 418 | 419 | local filename = "g64/cache/" .. game:GetMap() .. "_cache.dat" 420 | if file.Exists(filename, "DATA") and GetConVar("g64_disable_cache"):GetBool() == false then 421 | local mapStatus = "[G64] Loading map geometry from cache..." 422 | print(mapStatus) 423 | 424 | hook.Add("HUDPaint", "G64_DRAW_MAP_STATUS", function() 425 | surface.SetFont("Default") 426 | w, h = surface.GetTextSize(mapStatus) 427 | 428 | surface.SetDrawColor( 0, 0, 0, 200 ) 429 | surface.DrawRect( ScrW()-(w+40), ScrH()-50, w+20, 38 ) 430 | surface.SetTextColor(255, 255, 255) 431 | surface.SetTextPos(ScrW()-(w+30), ScrH()-40) 432 | surface.DrawText(mapStatus) 433 | end) 434 | 435 | if g64utils.LoadMapCache(filename) == true then 436 | hook.Run("G64Initialized") 437 | hook.Remove("HUDPaint", "G64_DRAW_MAP_STATUS") 438 | print("[G64] Loaded cached map geometry!") 439 | else 440 | hook.Remove("HUDPaint", "G64_DRAW_MAP_STATUS") 441 | LoadAndCacheMapGeometry(timeout) 442 | end 443 | 444 | else 445 | LoadAndCacheMapGeometry(timeout) 446 | end 447 | else 448 | libsm64 = {} 449 | LoadFailure() 450 | MsgC(Color(255, 100, 100), "[G64] Couldn't locate the G64 binary module! Please download it from https://github.com/ckosmic/g64#installation\n") 451 | end 452 | end 453 | 454 | hook.Add("InitPostEntity", "G64_INIT_POST_ENTITY", function() 455 | hook.Remove("InitPostEntity", "G64_INIT_POST_ENTITY") 456 | g64config.Load() 457 | InitializeWorld(2) 458 | end) 459 | else 460 | net.Receive("G64_LOADMAPGEO", function(len, ply) 461 | if not ply.SM64LoadedMap then 462 | LoadMapGeometry(ply) 463 | end 464 | ply.SM64LoadedMap = true 465 | end) 466 | 467 | function LoadMapGeometry(ply) 468 | local convexes = Entity(0):GetPhysicsObject():GetMeshConvexes() 469 | local triCount = 0 470 | local worldMin, worldMax = Entity(0):GetModelBounds() 471 | net.Start("G64_LOADMAPGEO", false) 472 | net.WriteUInt(0, 8) 473 | 474 | net.WriteInt(worldMin.x, 16) 475 | net.WriteInt(worldMin.y, 16) 476 | net.WriteInt(worldMin.z, 16) 477 | net.WriteInt(worldMax.x, 16) 478 | net.WriteInt(worldMax.y, 16) 479 | net.WriteInt(worldMax.z, 16) 480 | 481 | net.Send(ply) 482 | hook.Add("Tick", "G64_MAP_LOADER" .. ply:EntIndex(), function() 483 | local counter = 0 484 | while counter < 32 and #convexes ~= 0 do 485 | local convex = table.remove(convexes) 486 | net.Start("G64_LOADMAPGEO", false) 487 | net.WriteUInt(1, 8) 488 | net.WriteUInt(#convex, 32) 489 | counter = counter + 1 490 | for i = 1, #convex do 491 | local vertex = convex[i].pos 492 | net.WriteInt(vertex.x, 16) 493 | net.WriteInt(vertex.y, 16) 494 | net.WriteInt(vertex.z, 16) 495 | triCount = triCount + 1 496 | end 497 | net.Send(ply) 498 | end 499 | if #convexes == 0 then 500 | hook.Remove("Tick", "G64_MAP_LOADER" .. ply:EntIndex()) 501 | net.Start("G64_LOADMAPGEO", false) 502 | net.WriteUInt(2, 8) 503 | net.Send(ply) 504 | end 505 | end) 506 | end 507 | end 508 | 509 | drive.Register("G64_DRIVE", 510 | { 511 | }, "drive_base") -------------------------------------------------------------------------------- /lua/autorun/server/g64_networkstrings.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | util.AddNetworkString("G64_LOADMAPGEO") 4 | util.AddNetworkString("G64_PLAYERREADY") 5 | util.AddNetworkString("G64_HURTNPC") 6 | util.AddNetworkString("G64_USEENTITY") 7 | util.AddNetworkString("G64_DAMAGEENTITY") 8 | util.AddNetworkString("G64_TRANSMITMOVE") 9 | util.AddNetworkString("G64_TRANSMITCAP") 10 | util.AddNetworkString("G64_DAMAGEMARIO") 11 | util.AddNetworkString("G64_INITLOCALCLIENT") 12 | util.AddNetworkString("G64_TICKREMOTEMARIO") 13 | util.AddNetworkString("G64_TRANSMITCOLORS") 14 | util.AddNetworkString("G64_UPDATEREMOTECOLORS") 15 | util.AddNetworkString("G64_UPDATEREMOTECAP") 16 | util.AddNetworkString("G64_REQUESTCOLORS") 17 | util.AddNetworkString("G64_UPLOADCOLORS") 18 | util.AddNetworkString("G64_REMOVEINVALIDMARIO") 19 | util.AddNetworkString("G64_CHANGESURFACEINFO") 20 | util.AddNetworkString("G64_RESETINVALIDPLAYER") 21 | util.AddNetworkString("G64_SPAWNMARIOATPLAYER") 22 | util.AddNetworkString("G64_REMOVEFROMCLIENT") 23 | util.AddNetworkString("G64_RESPAWNMARIO") 24 | util.AddNetworkString("G64_COLLECTED1UP") 25 | util.AddNetworkString("G64_COLLECTEDCOIN") 26 | util.AddNetworkString("G64_SPAWNNEWPLAYER") 27 | util.AddNetworkString("G64_UPDATEHELDOBJECT") 28 | util.AddNetworkString("G64_TELEPORTMARIO") -------------------------------------------------------------------------------- /lua/autorun/server/g64_sv_init.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | include("includes/g64_utils.lua") 3 | 4 | g64sv = {} 5 | g64sv.PlayerColors = {} 6 | g64sv.PlayerTick = {} 7 | 8 | local directionAngCos = math.cos(math.pi / 2) 9 | local function DegreesFromEyes(ply, pos) 10 | if not pos then return 360 end 11 | local dPos = (pos + ply:EyeAngles():Forward()*300) - ply:GetShootPos() 12 | dPos:Normalize() 13 | local flDot = ply:EyeAngles():Forward():Dot(dPos) 14 | local flDegreesFromCrosshair = math.deg(math.acos(flDot)) 15 | return math.abs(flDegreesFromCrosshair) 16 | end 17 | 18 | local function GetSeatPoint(veh, role) 19 | if IsValid(veh) and veh:IsVehicle() then 20 | local seatAttachment = veh:LookupAttachment("vehicle_feet_passenger" .. role) 21 | local vPos, vAng = nil 22 | if seatAttachment > 0 then 23 | local seat = veh:GetAttachment(seatAttachment) 24 | return seat.Pos, seat.Ang 25 | else 26 | return veh:GetPassengerSeatPoint(role) 27 | end 28 | end 29 | return nil, nil 30 | end 31 | 32 | local animInfo = {} 33 | local networkedPos = Vector() 34 | local upOffset = Vector(0,0,5) 35 | local traceTable = {} 36 | local lastSafePos = Vector() 37 | animInfo.rotation = {} 38 | net.Receive("G64_TRANSMITMOVE", function(len, ply) 39 | if IsValid(ply.MarioEnt) then 40 | 41 | local mario = ply.MarioEnt 42 | 43 | networkedPos.x = net.ReadInt(16) 44 | networkedPos.y = net.ReadInt(16) 45 | networkedPos.z = net.ReadInt(16) 46 | networkedPos = networkedPos + upOffset 47 | local dist = mario:GetNWFloat("PlyMarioDist") 48 | ply:SetGroundEntity(nil) 49 | 50 | if not IsValid(ply.UsingCamera) then 51 | ply:SetNWEntity("UsingCamera", ply) 52 | else 53 | ply.UsingCamera:SetNWBool("locked", ply.UsingCamera.locked) 54 | ply:SetNWEntity("UsingCamera", ply.UsingCamera) 55 | end 56 | 57 | 58 | animInfo.animID = net.ReadInt(16) 59 | animInfo.animAccel = net.ReadInt(32) 60 | animInfo.rotation[1] = net.ReadInt(16) 61 | animInfo.rotation[2] = net.ReadInt(16) 62 | animInfo.rotation[3] = net.ReadInt(16) 63 | 64 | local health = net.ReadUInt(4) 65 | ply:SetHealth(health) 66 | 67 | if ply:InVehicle() then 68 | if health <= 0 then 69 | ply:ExitVehicle() 70 | end 71 | else 72 | ply:SetPos(networkedPos) 73 | mario:SetPos(networkedPos) 74 | mario.NetworkedPos = networkedPos 75 | end 76 | 77 | local flags = net.ReadUInt(32) 78 | if g64utils.MarioHasFlag(flags, 0x00000002) then 79 | ply:SetNotSolid(true) 80 | else 81 | ply:SetNotSolid(false) 82 | end 83 | 84 | local filter = RecipientFilter() 85 | filter:AddAllPlayers() 86 | filter:RemovePlayer(ply) 87 | local plys = filter:GetPlayers() 88 | for i = 1, #plys do 89 | if DegreesFromEyes(plys[i], networkedPos) > plys[i]:GetFOV() then 90 | filter:RemovePlayer(plys[i]) 91 | end 92 | end 93 | 94 | net.Start("G64_TICKREMOTEMARIO", false) 95 | net.WriteEntity(ply.MarioEnt) 96 | net.WriteInt(animInfo.animID, 16) 97 | net.WriteInt(animInfo.animAccel, 32) 98 | net.WriteInt(animInfo.rotation[1], 16) 99 | net.WriteInt(animInfo.rotation[2], 16) 100 | net.WriteInt(animInfo.rotation[3], 16) 101 | net.WriteUInt(flags, 32) 102 | net.Send(filter) 103 | end 104 | end) 105 | 106 | net.Receive("G64_TRANSMITCOLORS", function(len, ply) 107 | if IsValid(ply.MarioEnt) then 108 | if g64sv.PlayerColors[ply] == nil then g64sv.PlayerColors[ply] = {} end 109 | 110 | local colTab = g64sv.PlayerColors[ply] 111 | for i=1, 6 do 112 | colTab[i] = { net.ReadUInt(8), net.ReadUInt(8), net.ReadUInt(8) } 113 | end 114 | 115 | net.Start("G64_UPDATEREMOTECOLORS", false) 116 | net.WriteEntity(ply.MarioEnt) 117 | for i=1, 6 do 118 | net.WriteUInt(colTab[i][1], 8) 119 | net.WriteUInt(colTab[i][2], 8) 120 | net.WriteUInt(colTab[i][3], 8) 121 | end 122 | net.SendOmit(ply) 123 | end 124 | end) 125 | 126 | net.Receive("G64_REQUESTCOLORS", function(len, ply) 127 | local owner = net.ReadEntity() 128 | if IsValid(owner.MarioEnt) then 129 | if g64sv.PlayerColors[owner] ~= nil then 130 | local colTab = g64sv.PlayerColors[owner] 131 | 132 | net.Start("G64_UPDATEREMOTECOLORS", false) 133 | net.WriteEntity(owner.MarioEnt) 134 | for i=1, 6 do 135 | net.WriteUInt(colTab[i][1], 8) 136 | net.WriteUInt(colTab[i][2], 8) 137 | net.WriteUInt(colTab[i][3], 8) 138 | end 139 | net.Send(ply) 140 | end 141 | end 142 | end) 143 | 144 | hook.Add("InitPostEntity", "G64_SV_INIT_POST_ENTITY", function() 145 | local triggers = ents.FindByClass("trigger_teleport") 146 | for k,v in ipairs(triggers) do 147 | local amins, amaxs = v:GetRotatedAABB(v:OBBMins(), v:OBBMaxs()) 148 | local keyValues = v:GetKeyValues() 149 | local tpTarget = ents.FindByName(keyValues.target)[1] 150 | 151 | local tg = ents.Create("g64_tptrigger") 152 | tg.PhysMesh = {} 153 | local surfaces = v:GetBrushSurfaces() 154 | for k,surfInfo in pairs(surfaces) do 155 | local vertices = surfInfo:GetVertices() 156 | for i = 1, #vertices - 2 do 157 | local len = #tg.PhysMesh 158 | tg.PhysMesh[len + 1] = { pos = vertices[1] } 159 | tg.PhysMesh[len + 2] = { pos = vertices[i + 1] } 160 | tg.PhysMesh[len + 3] = { pos = vertices[i + 2] } 161 | end 162 | end 163 | 164 | tg:Spawn() 165 | tg:SetPos(v:GetPos()) 166 | tg:SetAngles(v:GetAngles()) 167 | 168 | v.G64TPTrigger = tg 169 | tg.OrigTrigger = v 170 | tg.Enabled = true 171 | if keyValues.StartDisabled == 1 then tg.Enabled = false end 172 | if IsValid(tpTarget) then 173 | tg.TargetPos = tpTarget:GetPos() 174 | tg.TargetAng = tpTarget:GetAngles() 175 | else 176 | tg.TargetPos = nil 177 | tg.TargetAng = nil 178 | end 179 | end 180 | end) 181 | 182 | hook.Add("EntityTakeDamage", "G64_PLAYER_DAMAGED", function(target, dmg) 183 | if target:IsPlayer() and target.IsMario == true and target:HasGodMode() == false then 184 | local damage = math.ceil(dmg:GetDamage()/10) 185 | local src = dmg:GetDamagePosition() 186 | 187 | net.Start("G64_DAMAGEMARIO", true) 188 | net.WriteUInt(damage, 8) 189 | net.WriteInt(src.x, 16) 190 | net.WriteInt(src.y, 16) 191 | net.WriteInt(src.z, 16) 192 | net.Send(target) 193 | 194 | return true 195 | end 196 | end) 197 | 198 | hook.Add("EntityRemoved", "G64_ENTITY_REMOVED", function(ent) 199 | local ply = ent.Owner 200 | if ply ~= nil and ply:IsValid() and ply:IsPlayer() and ply.IsMario == true then 201 | g64sv.PlayerColors[ply] = nil 202 | g64sv.PlayerTick[ply] = nil 203 | end 204 | end) 205 | 206 | local useBlacklist = { 207 | g64_physbox = true 208 | } 209 | hook.Add("PlayerUse", "G64_PLAYER_USE", function(ply, ent) 210 | if IsValid(ply.MarioEnt) and ply.IsMario == true and useBlacklist[ent:GetClass()] and ply:Health() > 0 then return false end 211 | end) 212 | 213 | hook.Add("PlayerDisconnected", "G64_PLY_DISCONNECT", function(ply) 214 | if IsValid(ply.MarioEnt) and ply.IsMario == true then ply.MarioEnt:Remove() end 215 | end) 216 | 217 | hook.Add("PlayerDeath", "G64_PLAYER_DEATH", function(victim, inflictor, attacker) 218 | if IsValid(victim.MarioEnt) then 219 | victim.MarioEnt:Remove() 220 | end 221 | end) 222 | 223 | hook.Add("PlayerEnteredVehicle", "G64_PLAYER_ENTERED_VEHICLE", function(ply, veh, role) 224 | if IsValid(ply.MarioEnt) and ply.IsMario == true then 225 | local vPos, vAng = GetSeatPoint(veh, role) 226 | local mario = ply.MarioEnt 227 | 228 | local driveable = veh:GetClass() ~= "prop_vehicle_prisoner_pod" 229 | -- Check for simfphys cars 230 | for k,v in ipairs(ents.FindInSphere(veh:GetPos(), 10)) do 231 | if v:GetClass() == "gmod_sent_vehicle_fphysics_base" then 232 | driveable = true 233 | end 234 | end 235 | 236 | if driveable then 237 | mario:SetParent(ply) 238 | mario:SetLocalAngles(Angle(0,-90,0)) 239 | local offset = ply:GetPos() 240 | offset:Add(ply:GetForward()*10) 241 | offset:Add(ply:GetUp()*6) 242 | mario:SetPos(offset) 243 | else 244 | mario:SetParent(veh) 245 | mario:SetPos(vPos) 246 | mario:SetAngles(veh:GetAngles()) 247 | end 248 | 249 | veh:SetThirdPersonMode(true) 250 | ply:SetActiveWeapon(NULL) 251 | ply:CrosshairDisable() 252 | drive.PlayerStopDriving(ply) 253 | end 254 | end) 255 | 256 | hook.Add("PlayerLeaveVehicle", "G64_PLAYER_LEFT_VEHICLE", function(ply, veh) 257 | if IsValid(ply.MarioEnt) and ply.IsMario == true then 258 | local mario = ply.MarioEnt 259 | mario:SetParent(nil) 260 | mario:SetAngles(Angle()) 261 | 262 | local mins, maxs = veh:WorldSpaceAABB() 263 | local exitPt = veh:CheckExitPoint(120, maxs.z-mins.z+75) 264 | if exitPt ~= nil then 265 | ply:SetPos(exitPt) 266 | mario:SetPos(exitPt) 267 | end 268 | 269 | ply:CrosshairDisable() 270 | ply.MarioEnt:SetPos(ply:GetPos()) 271 | drive.PlayerStartDriving(ply, ply.MarioEnt, "G64_DRIVE") 272 | ply.MarioEnt:SetAngles(Angle()) 273 | ply:SetObserverMode(OBS_MODE_CHASE) 274 | end 275 | end) 276 | 277 | hook.Add("SetupMove", "G64_SETUP_MOVE", function(ply, mv, cmd) 278 | if not (IsValid(ply.MarioEnt) and ply.IsMario == true) then return end 279 | 280 | if mv:KeyPressed(IN_USE) and ply:InVehicle() then 281 | ply:ExitVehicle() 282 | end 283 | end) 284 | 285 | hook.Add("AcceptInput", "G64_ACCEPT_INPUT", function(ent, inp, activator, caller, value) 286 | if ent:GetClass() == "trigger_teleport" and IsValid(ent.G64TPTrigger) then 287 | if inp == "Enable" then 288 | ent.G64TPTrigger.Enabled = true 289 | elseif inp == "Disable" then 290 | ent.G64TPTrigger.Enabled = false 291 | end 292 | --print(ent, inp, activator, caller, value) 293 | end 294 | end) 295 | 296 | local allEnts = ents.GetAll() 297 | hook.Add("OnEntityCreated", "G64_SV_ON_ENT_CREATED", function(ent) 298 | if IsValid(ent) == false then return end 299 | table.insert(allEnts, ent) 300 | end) 301 | 302 | local markedForDeletion = {} 303 | timer.Remove("G64_SOLIDITY_CHECK") 304 | timer.Create("G64_SOLIDITY_CHECK", 1, 0, function() 305 | table.Empty(markedForDeletion) 306 | for k,v in ipairs(allEnts) do 307 | if IsValid(v) == false then 308 | table.insert(markedForDeletion, k) 309 | continue 310 | end 311 | local kv = v:GetKeyValues() 312 | if kv.Solidity ~= nil then 313 | v:SetNWInt("Solidity", kv.Solidity) 314 | else 315 | v:SetNWInt("Solidity", -1) 316 | end 317 | end 318 | 319 | for k,v in ipairs(markedForDeletion) do 320 | table.remove(allEnts, v) 321 | end 322 | end) 323 | 324 | local physgunBlacklist = { 325 | g64_physbox = true, 326 | g64_mario = true 327 | } 328 | hook.Add("PhysgunPickup", "G64_PHYSGUN_PICKUP", function(ply, ent) 329 | if physgunBlacklist[ent:GetClass()] then 330 | return false 331 | end 332 | end) 333 | 334 | local function SpawnMarioAtPlayer(ply) 335 | ply.MarioEnt = nil 336 | local mario = ents.Create("g64_mario") 337 | mario.Owner = ply 338 | mario:SetPos(ply:GetPos()) 339 | mario:SetOwner(ply) 340 | mario:Spawn() 341 | mario:Activate() 342 | undo.Create("Mario") 343 | undo.AddEntity(mario) 344 | undo.SetPlayer(ply) 345 | undo.Finish() 346 | end 347 | 348 | net.Receive("G64_UPLOADCOLORS", function(len, ply) 349 | if g64sv.PlayerColors[ply] == nil then g64sv.PlayerColors[ply] = {} end 350 | for i=1, 6 do 351 | g64sv.PlayerColors[ply][i] = { net.ReadUInt(8), net.ReadUInt(8), net.ReadUInt(8) } 352 | end 353 | end) 354 | 355 | net.Receive("G64_DAMAGEENTITY", function(len, ply) 356 | local mario = net.ReadEntity() 357 | local victim = net.ReadEntity() 358 | local forceVec = net.ReadVector() 359 | local hitPos = net.ReadVector() 360 | local minDmg = net.ReadUInt(8) 361 | 362 | if not IsValid(victim) or !IsValid(mario) then return end 363 | local victimHealth = victim:Health() 364 | if victim:IsNPC() or victim:IsPlayer() or victimHealth > 0 then 365 | local d = DamageInfo() 366 | local damage = math.random(minDmg, minDmg+10) 367 | d:SetDamage(damage) 368 | d:SetAttacker(mario) 369 | d:SetInflictor(mario) 370 | d:SetDamageType(DMG_GENERIC) 371 | d:SetDamageForce(forceVec * 15000) 372 | d:SetDamagePosition(hitPos) 373 | 374 | local damageDiff = victimHealth - damage 375 | if victim.IsMario then damageDiff = victimHealth - math.ceil(damage / 10) end 376 | 377 | if (victim:IsNPC() or victim:IsPlayer()) and damageDiff <= 0 and victimHealth > 0 then 378 | local coin = nil 379 | if victim:IsPlayer() then coin = ents.Create("g64_bluecoin") 380 | else coin = ents.Create("g64_yellowcoin") end 381 | local entPos = victim:GetPos() 382 | entPos:Add(Vector(0, 0, 30)) 383 | coin:SetPos(entPos) 384 | coin:Spawn() 385 | coin:SetNWEntity("IgnoreEnt", victim) 386 | local coinPhys = coin:GetPhysicsObject() 387 | if IsValid(coinPhys) then 388 | coinPhys:SetVelocity(Vector(math.random(-100, 100), math.random(-100, 100), math.random(200, 400))) 389 | end 390 | end 391 | 392 | victim:TakeDamageInfo(d) 393 | elseif victim:GetPhysicsObject():IsValid() then 394 | local phys = victim:GetPhysicsObject() 395 | 396 | phys:ApplyForceOffset(forceVec * 7800, hitPos) 397 | end 398 | 399 | if ply:GetUseEntity() ~= NULL then 400 | ply:GetUseEntity():Use(mario, mario, USE_ON) 401 | end 402 | end) 403 | 404 | net.Receive("G64_REMOVEINVALIDMARIO", function(len, ply) 405 | local ent = net.ReadEntity() 406 | ply:ExitVehicle() 407 | if IsValid(ent) then ent:Remove() end 408 | end) 409 | 410 | net.Receive("G64_RESETINVALIDPLAYER", function(len, ply) 411 | local mario = net.ReadEntity() 412 | if mario ~= nil then mario:Remove() end 413 | ply.SM64LoadedMap = false 414 | end) 415 | 416 | net.Receive("G64_REMOVEFROMCLIENT", function(len, ply) 417 | local ent = net.ReadEntity() 418 | if IsValid(ent) then ent:Remove() end 419 | end) 420 | 421 | net.Receive("G64_SPAWNMARIOATPLAYER", function(len, ply) 422 | SpawnMarioAtPlayer(ply) 423 | end) 424 | 425 | net.Receive("G64_RESPAWNMARIO", function(len, ply) 426 | local ent = net.ReadEntity() 427 | if IsValid(ent) then ent:Remove() end 428 | if GetConVar("g64_respawn_mario_on_death"):GetBool() == false then return end 429 | timer.Create("G64_DELAY_PLAYER_RESPAWN", 0.1, 1, function() 430 | local spawns = ents.FindByClass("info_player_start") 431 | local random_entry = math.random(#spawns) 432 | local spawnpoint = spawns[random_entry] 433 | ply:SetPos(spawnpoint:GetPos()) 434 | timer.Create("G64_DELAY_MARIO_RESPAWN", 0.1, 1, function() 435 | SpawnMarioAtPlayer(ply) 436 | end) 437 | end) 438 | end) 439 | 440 | net.Receive("G64_COLLECTED1UP", function(len, ply) 441 | if ply.IsMario == nil or ply.IsMario == false then 442 | ply:SetArmor(ply:Armor() + 25) 443 | end 444 | end) 445 | 446 | net.Receive("G64_COLLECTEDCOIN", function(len, ply) 447 | if ply.IsMario == nil or ply.IsMario == false then 448 | ply:SetHealth(ply:Health() + 25) 449 | end 450 | end) 451 | 452 | net.Receive("G64_UPDATEHELDOBJECT", function(len, ply) 453 | local ent = net.ReadEntity() 454 | local pos = net.ReadVector() 455 | local ang = net.ReadAngle() 456 | local arg = net.ReadUInt(8) 457 | if IsValid(ent) then 458 | if arg < 2 then 459 | ent:SetNotSolid(false) 460 | local phys = ent:GetPhysicsObject() 461 | if IsValid(phys) then 462 | phys:EnableMotion(true) 463 | phys:Wake() 464 | if arg == 1 then 465 | phys:SetVelocity(ang:Forward()*200 + Vector(0,0,200)) 466 | end 467 | end 468 | else 469 | ent:SetPos(pos) 470 | ent:SetAngles(ang) 471 | ent:SetNotSolid(true) 472 | local phys = ent:GetPhysicsObject() 473 | if IsValid(phys) then 474 | phys:EnableMotion(false) 475 | end 476 | end 477 | end 478 | end) 479 | 480 | local meta = FindMetaTable("Player") 481 | 482 | meta.DefaultGodEnable = meta.DefaultGodEnable or meta.GodEnable 483 | meta.DefaultGodDisable = meta.DefaultGodDisable or meta.GodDisable 484 | 485 | function meta:GodEnable() 486 | self:SetNWBool("HasGodMode", true) 487 | self:DefaultGodEnable() 488 | end 489 | 490 | function meta:GodDisable() 491 | self:SetNWBool("HasGodMode", false) 492 | self:DefaultGodDisable() 493 | end -------------------------------------------------------------------------------- /lua/autorun/sh_systimetimers_loader.lua: -------------------------------------------------------------------------------- 1 | if SERVER then 2 | require("systimetimers") 3 | AddCSLuaFile("includes/modules/systimetimers.lua") 4 | elseif CLIENT then 5 | require("systimetimers") 6 | end 7 | -------------------------------------------------------------------------------- /lua/entities/g64_1up.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | include("includes/g64_sprites.lua") 3 | 4 | ENT.Type = "anim" 5 | ENT.Base = "base_entity" 6 | 7 | ENT.Category = "G64" 8 | ENT.PrintName = "1-Up" 9 | ENT.Author = "ckosmic" 10 | ENT.Spawnable = false 11 | ENT.AdminSpawnable = true 12 | ENT.AdminOnly = false 13 | ENT.RenderGroup = RENDERGROUP_TRANSLUCENT 14 | 15 | RegisterG64Entity(ENT, "g64_1up") 16 | 17 | function ENT:SpawnFunction(ply, tr, ClassName) 18 | if not tr.Hit then return end 19 | 20 | local SpawnPos = tr.HitPos + tr.HitNormal * 16 21 | 22 | local ent = ents.Create(ClassName) 23 | ent:SetOwner(ply) 24 | ent:SetPos(SpawnPos) 25 | ent:Spawn() 26 | ent:Activate() 27 | 28 | return ent 29 | end 30 | 31 | function ENT:Initialize() 32 | self.Owner = self:GetOwner() 33 | 34 | self:SetModel( "models/props_phx/misc/soccerball.mdl" ) 35 | self:SetColor( Color( 255, 255, 255 ) ) 36 | 37 | self:SetMoveType( MOVETYPE_VPHYSICS ) 38 | self:SetSolid( SOLID_VPHYSICS ) 39 | self:SetCollisionGroup(COLLISION_GROUP_WEAPON) 40 | 41 | if SERVER then 42 | self:PhysicsInit( SOLID_VPHYSICS ) 43 | else 44 | g64utils.GlobalInit() 45 | end 46 | 47 | self:PhysWake() 48 | 49 | self.Collected = false 50 | end 51 | 52 | function ENT:DrawTranslucent() 53 | local angle = EyeAngles() 54 | angle = Angle(angle.x, angle.y, 0) 55 | angle:RotateAroundAxis(angle:Up(), -90) 56 | angle:RotateAroundAxis(angle:Forward(), 90) 57 | 58 | local w = 20 59 | local h = 20 60 | 61 | render.OverrideDepthEnable(true, true) 62 | cam.Start3D2D(self:GetPos(), angle, 1) 63 | surface.SetDrawColor(color_white) 64 | surface.SetMaterial(g64utils.HealthMat) 65 | local he = g64sprites.Health 66 | local u0, v0 = he.one_up.u, 0 67 | local u1, v1 = he.one_up.u + he.one_up.w / he.tex_width, 1 68 | u0 = u0 + he.one_up.w / he.tex_width / he.tex_width -- Source engine is just so funny right haha 69 | u1 = u1 + he.one_up.w / he.tex_width / he.tex_width -- Source engine is just so silly right haha 70 | surface.DrawTexturedRectUV(-w/2, -h/2, w, h, u0, v0, u1, v1) 71 | cam.End3D2D() 72 | render.OverrideDepthEnable(false) 73 | end 74 | 75 | local plyOffset = Vector(0, 0, 30) 76 | function ENT:Think() 77 | if self:GetOwner() ~= nil and self:GetOwner():EntIndex() > 0 then 78 | self.Owner = ents.GetByIndex(self:GetOwner():EntIndex()) 79 | self:SetOwner(nil) 80 | end 81 | if CLIENT then 82 | local ply = LocalPlayer() 83 | local marioEnt = ply.MarioEnt 84 | if g64utils.WithinBounds(self:GetPos(), ply:GetNetworkOrigin(), 40) and self.Collected == false and self:GetNWEntity("IgnoreEnt") ~= ply then 85 | if IsValid(marioEnt) then 86 | libsm64.MarioSetLives(marioEnt.MarioId, marioEnt.marioNumLives + 1) 87 | end 88 | 89 | local soundArg = GetSoundArg(g64types.SM64SoundTable.SOUND_GENERAL_COLLECT_1UP) 90 | libsm64.PlaySoundGlobal(soundArg) 91 | 92 | ParticleEffect("coin_pickup", self:GetPos(), Angle()) 93 | 94 | g64utils.RemoveFromClient(self) 95 | net.Start("G64_COLLECTED1UP") 96 | net.SendToServer() 97 | self.Collected = true 98 | end 99 | 100 | self:SetNextClientThink(CurTime()) 101 | return true 102 | end 103 | end 104 | 105 | function ENT:PhysicsCollide(data, physobj) 106 | local LastSpeed = math.max( data.OurOldVelocity:Length(), data.Speed ) 107 | local NewVelocity = physobj:GetVelocity() 108 | NewVelocity:Normalize() 109 | 110 | LastSpeed = math.max( NewVelocity:Length(), LastSpeed ) 111 | 112 | local TargetVelocity = NewVelocity * LastSpeed * 0.2 113 | 114 | physobj:SetVelocity( TargetVelocity ) 115 | end 116 | 117 | include("includes/g64_utils.lua") 118 | list.Set("g64_entities", "g64_1up", { 119 | Category = "Items", 120 | Name = "1-Up", 121 | Material = "", 122 | IconGenerator = { 123 | material = g64utils.HealthMat, 124 | u = { g64sprites.Health.one_up.u, g64sprites.Health.one_up.u + g64sprites.Health.one_up.w / g64sprites.Health.tex_width }, 125 | v = { 0, 1 } 126 | } 127 | }) 128 | -------------------------------------------------------------------------------- /lua/entities/g64_bluecoin.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.Category = "G64" 7 | ENT.PrintName = "Blue Coin" 8 | ENT.Author = "ckosmic" 9 | ENT.Spawnable = false 10 | ENT.AdminSpawnable = true 11 | ENT.AdminOnly = false 12 | 13 | ENT.CoinColor = Color(120, 120, 255) 14 | ENT.CoinValue = 5 15 | 16 | RegisterG64Entity(ENT, "g64_bluecoin") 17 | 18 | include("entities/g64_coin.lua") 19 | include("includes/g64_utils.lua") 20 | 21 | list.Set("g64_entities", "g64_bluecoin", { 22 | Category = "Items", 23 | Name = "Blue Coin", 24 | Material = "", 25 | IconGenerator = { 26 | material = g64utils.CoinMat, 27 | u = { 1*0.25, 1*0.25+0.25 }, 28 | v = { 0, 1 }, 29 | tint = Color(120, 120, 255) 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /lua/entities/g64_coin.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.CoinFrame = 0 4 | ENT.IgnoreEnt = nil 5 | 6 | function ENT:SpawnFunction(ply, tr, ClassName) 7 | if not tr.Hit then return end 8 | 9 | local SpawnPos = tr.HitPos + tr.HitNormal * 16 10 | 11 | local ent = ents.Create(ClassName) 12 | ent:SetOwner(ply) 13 | ent:SetPos(SpawnPos) 14 | ent:Spawn() 15 | ent:Activate() 16 | 17 | return ent 18 | end 19 | 20 | function ENT:Initialize() 21 | self.Owner = self:GetOwner() 22 | 23 | self:SetModel( "models/props_phx/misc/soccerball.mdl" ) 24 | self:SetColor( Color( 255, 255, 255 ) ) 25 | 26 | self:SetMoveType( MOVETYPE_VPHYSICS ) 27 | self:SetSolid( SOLID_VPHYSICS ) 28 | self:SetCollisionGroup(COLLISION_GROUP_WEAPON) 29 | 30 | if SERVER then 31 | self:PhysicsInit( SOLID_VPHYSICS ) 32 | else 33 | g64utils.GlobalInit() 34 | end 35 | 36 | self:PhysWake() 37 | 38 | self.Collected = false 39 | 40 | timer.Create("G64_COIN_FRAME_TIMER" .. self:EntIndex(), 0.1, 0, function() 41 | self.CoinFrame = self.CoinFrame + 1 42 | self.CoinFrame = math.fmod(self.CoinFrame, 4) 43 | end) 44 | 45 | self:StartThinkTimer() 46 | end 47 | 48 | function ENT:OnRemove() 49 | timer.Remove("G64_COIN_FRAME_TIMER" .. self:EntIndex()) 50 | end 51 | 52 | function ENT:Draw() 53 | local angle = EyeAngles() 54 | angle = Angle(angle.x, angle.y, 0) 55 | angle:RotateAroundAxis(angle:Up(), -90) 56 | angle:RotateAroundAxis(angle:Forward(), 90) 57 | 58 | local w = 20 59 | local h = 20 60 | 61 | render.OverrideDepthEnable(true, true) 62 | cam.Start3D2D(self:GetPos(), angle, 1) 63 | surface.SetDrawColor(self.CoinColor:Unpack()) 64 | surface.SetMaterial(g64utils.CoinMat) 65 | local u0, v0 = self.CoinFrame*0.25, 0 66 | local u1, v1 = self.CoinFrame*0.25+0.25, 1 67 | u0 = u0 + 0.25 / 32 -- Source engine is just so funny right haha 68 | u1 = u1 + 0.25 / 32 -- Source engine is just so silly right haha 69 | surface.DrawTexturedRectUV(-w/2, -h/2, w, h, u0, v0, u1, v1) 70 | cam.End3D2D() 71 | render.OverrideDepthEnable(false) 72 | end 73 | 74 | local plyOffset = Vector(0, 0, 30) 75 | function ENT:StartThinkTimer() 76 | timer.Create("G64_COIN_THINK_DELAY" .. self:EntIndex(), 0.5, 1, function() 77 | function self:Think() 78 | if self:GetOwner() ~= nil and self:GetOwner():EntIndex() > 0 then 79 | self.Owner = ents.GetByIndex(self:GetOwner():EntIndex()) 80 | self:SetOwner(nil) 81 | end 82 | if CLIENT then 83 | local ply = LocalPlayer() 84 | if g64utils.WithinBounds(self:GetPos(), ply:GetNetworkOrigin(), 40) and self.Collected == false and self:GetNWEntity("IgnoreEnt") ~= ply then 85 | ply.CoinCount = ply.CoinCount + self.CoinValue 86 | 87 | if self.CoinValue == 1 then 88 | local soundArg = GetSoundArg(g64types.SM64SoundTable.SOUND_GENERAL_COIN) 89 | libsm64.PlaySoundGlobal(soundArg) 90 | elseif self.CoinValue == 2 then 91 | local soundArg = GetSoundArg(g64types.SM64SoundTable.SOUND_MENU_COLLECT_RED_COIN) + bit.lshift(ply.RedCoinCount, 16) 92 | libsm64.PlaySoundGlobal(soundArg) 93 | ply.RedCoinCount = ply.RedCoinCount + 1 94 | ply.RedCoinCount = math.fmod(ply.RedCoinCount, 8) 95 | elseif self.CoinValue == 5 then 96 | local soundArg = GetSoundArg(g64types.SM64SoundTable.SOUND_GENERAL_COIN) 97 | timer.Create("G64_BLUE_COIN_SOUND", 0.07, 5, function() 98 | libsm64.PlaySoundGlobal(soundArg) 99 | end) 100 | end 101 | 102 | if IsValid(ply.MarioEnt) then 103 | libsm64.MarioHeal(ply.MarioEnt.MarioId, self.CoinValue) 104 | end 105 | 106 | ParticleEffect("coin_pickup", self:GetPos(), Angle()) 107 | 108 | g64utils.RemoveFromClient(self) 109 | net.Start("G64_COLLECTEDCOIN") 110 | net.SendToServer() 111 | self.Collected = true 112 | end 113 | 114 | self:SetNextClientThink(CurTime()) 115 | return true 116 | end 117 | end 118 | end) 119 | end 120 | 121 | function ENT:PhysicsCollide(data, physobj) 122 | local LastSpeed = math.max( data.OurOldVelocity:Length(), data.Speed ) 123 | local NewVelocity = physobj:GetVelocity() 124 | NewVelocity:Normalize() 125 | 126 | LastSpeed = math.max( NewVelocity:Length(), LastSpeed ) 127 | 128 | local TargetVelocity = NewVelocity * LastSpeed * 0.7 129 | 130 | physobj:SetVelocity( TargetVelocity ) 131 | end -------------------------------------------------------------------------------- /lua/entities/g64_metalcap.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.Category = "G64" 7 | ENT.PrintName = "Metal Cap" 8 | ENT.Author = "ckosmic" 9 | ENT.Spawnable = false 10 | ENT.AdminSpawnable = true 11 | ENT.AdminOnly = false 12 | 13 | RegisterG64Entity(ENT, "g64_metalcap") 14 | 15 | function ENT:SpawnFunction(ply, tr, ClassName) 16 | if not tr.Hit then return end 17 | 18 | local SpawnPos = tr.HitPos + tr.HitNormal * 16 19 | 20 | local ent = ents.Create(ClassName) 21 | ent:SetPos(SpawnPos) 22 | ent:Spawn() 23 | ent:Activate() 24 | 25 | return ent 26 | end 27 | 28 | function ENT:Initialize() 29 | self:SetModel( "models/player/items/humans/top_hat.mdl" ) 30 | self:SetColor( Color( 200, 200, 200 ) ) 31 | self:SetModelScale(2, 0) 32 | 33 | self:SetMoveType( MOVETYPE_VPHYSICS ) 34 | self:SetSolid( SOLID_VPHYSICS ) 35 | 36 | self.Collected = false 37 | 38 | if SERVER then self:PhysicsInit( SOLID_VPHYSICS ) end 39 | 40 | self:PhysWake() 41 | end 42 | 43 | local metalMat = Material("debug/env_cubemap_model") 44 | function ENT:Draw() 45 | render.MaterialOverride(metalMat) 46 | self:DrawModel() 47 | render.MaterialOverride(nil) 48 | end 49 | 50 | function ENT:Think() 51 | if CLIENT then 52 | local ply = LocalPlayer() 53 | local marioEnt = ply.MarioEnt 54 | if g64utils.WithinBounds(self:GetPos(), ply:GetNetworkOrigin(), 40) and self.Collected == false then 55 | if IsValid(ply.MarioEnt) and ply.IsMario == true and ply.MarioEnt.hasMetalCap == false then 56 | ply.MarioEnt.EnableMetalCap = true 57 | end 58 | 59 | g64utils.RemoveFromClient(self) 60 | self.Collected = true 61 | end 62 | end 63 | end 64 | 65 | list.Set("g64_entities", "g64_metalcap", { 66 | Category = "Caps", 67 | Name = "Metal Cap", 68 | Material = "materials/vgui/entities/g64_metalcap.png" 69 | }) -------------------------------------------------------------------------------- /lua/entities/g64_physbox.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.PrintName = "Mario Physbox" 7 | ENT.Author = "ckosmic" 8 | ENT.Spawnable = false 9 | ENT.AdminSpawnable = false 10 | 11 | function ENT:Initialize() 12 | self:SetMoveType( MOVETYPE_NONE ) 13 | self:SetSolid( SOLID_NONE ) 14 | self:SetCollisionBounds(Vector(-16, -16, -5), Vector(16, 16, 55)) 15 | self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER) 16 | 17 | if SERVER then 18 | self:SetModel("models/hunter/misc/sphere075x075.mdl") 19 | self:PhysicsInit( SOLID_BBOX ) 20 | self:PhysWake() 21 | self.PhysicsObject = self:GetPhysicsObject() 22 | end 23 | 24 | self:SetNoDraw(true) 25 | end 26 | 27 | function ENT:Think() 28 | if SERVER then 29 | if not IsValid(self.Mario) then 30 | self:Remove() 31 | else 32 | self:SetPos(self.Mario:GetPos()) 33 | end 34 | 35 | if self.PhysicsObject and self.PhysicsObject:IsValid() then 36 | self.PhysicsObject:SetVelocityInstantaneous(Vector()) 37 | self.PhysicsObject:SetAngleVelocity(Vector()) 38 | else 39 | self.PhysicsObject = self:GetPhysicsObject() 40 | end 41 | else 42 | if not IsValid(self.Mario) then 43 | self.Mario = self:GetNWEntity("Mario") 44 | else 45 | self:SetNetworkOrigin(self.Mario:GetPos()) 46 | end 47 | self.Mario.PhysBox = self 48 | end 49 | end 50 | 51 | function ENT:OnRemove() 52 | end -------------------------------------------------------------------------------- /lua/entities/g64_redcoin.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.Category = "G64" 7 | ENT.PrintName = "Red Coin" 8 | ENT.Author = "ckosmic" 9 | ENT.Spawnable = false 10 | ENT.AdminSpawnable = true 11 | ENT.AdminOnly = false 12 | 13 | ENT.CoinColor = Color(255, 0, 0) 14 | ENT.CoinValue = 2 15 | 16 | RegisterG64Entity(ENT, "g64_redcoin") 17 | 18 | include("entities/g64_coin.lua") 19 | include("includes/g64_utils.lua") 20 | 21 | list.Set("g64_entities", "g64_redcoin", { 22 | Category = "Items", 23 | Name = "Red Coin", 24 | Material = "", 25 | IconGenerator = { 26 | material = g64utils.CoinMat, 27 | u = { 1*0.25, 1*0.25+0.25 }, 28 | v = { 0, 1 }, 29 | tint = Color(255, 0, 0) 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /lua/entities/g64_tptrigger.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.PrintName = "Teleport Trigger" 7 | ENT.Author = "ckosmic" 8 | ENT.Spawnable = false 9 | ENT.AdminSpawnable = false 10 | 11 | function ENT:Initialize() 12 | self:PhysicsFromMesh(self.PhysMesh) 13 | 14 | if SERVER then 15 | self:SetTrigger(true) 16 | end 17 | 18 | self:SetMoveType(MOVETYPE_NONE) 19 | self:SetSolid( SOLID_VPHYSICS ) 20 | self:SetSolidFlags(bit.bor(FSOLID_TRIGGER, FSOLID_CUSTOMRAYTEST, FSOLID_CUSTOMBOXTEST, FSOLID_NOT_SOLID)) 21 | 22 | self:SetNoDraw(true) 23 | end 24 | 25 | function ENT:Think() 26 | if SERVER then 27 | if self.TargetPos == nil or self.TargetAng == nil then 28 | local keyValues = self.OrigTrigger:GetKeyValues() 29 | local tpTarget = ents.FindByName(keyValues.target)[1] 30 | if IsValid(tpTarget) then 31 | self.TargetPos = tpTarget:GetPos() 32 | self.TargetAng = tpTarget:GetAngles() 33 | end 34 | end 35 | end 36 | end 37 | 38 | function ENT:StartTouch(ent) 39 | end 40 | 41 | function ENT:Touch(ent) 42 | if ent:GetClass() == "g64_physbox" and IsValid(ent.Mario) and IsValid(ent.Mario.Owner) and self.Enabled == true then 43 | if self.TargetPos ~= nil and self.TargetAng ~= nil then 44 | net.Start("G64_TELEPORTMARIO") 45 | net.WriteEntity(ent.Mario) 46 | net.WriteVector(self.TargetPos) 47 | net.WriteAngle(self.TargetAng) 48 | net.Send(ent.Mario.Owner) 49 | end 50 | end 51 | end 52 | 53 | function ENT:EndTouch(ent) 54 | end 55 | 56 | function ENT:PassesTriggerFilters( entity ) 57 | return true 58 | end 59 | 60 | function ENT:KeyValue( key, value ) 61 | end 62 | 63 | function ENT:OnRemove() 64 | end -------------------------------------------------------------------------------- /lua/entities/g64_vanishcap.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.Category = "G64" 7 | ENT.PrintName = "Vanish Cap" 8 | ENT.Author = "ckosmic" 9 | ENT.Spawnable = false 10 | ENT.AdminSpawnable = true 11 | ENT.AdminOnly = false 12 | ENT.RenderGroup = RENDERGROUP_TRANSLUCENT 13 | 14 | RegisterG64Entity(ENT, "g64_vanishcap") 15 | 16 | function ENT:SpawnFunction(ply, tr, ClassName) 17 | if not tr.Hit then return end 18 | 19 | local SpawnPos = tr.HitPos + tr.HitNormal * 16 20 | 21 | local ent = ents.Create(ClassName) 22 | ent:SetPos(SpawnPos) 23 | ent:Spawn() 24 | ent:Activate() 25 | 26 | return ent 27 | end 28 | 29 | function ENT:Initialize() 30 | self:SetModel( "models/player/items/humans/top_hat.mdl" ) 31 | self:SetColor( Color( 255, 255, 255 ) ) 32 | self:SetModelScale(2, 0) 33 | 34 | self:SetMoveType( MOVETYPE_VPHYSICS ) 35 | self:SetSolid( SOLID_VPHYSICS ) 36 | 37 | self.Collected = false 38 | 39 | if SERVER then self:PhysicsInit( SOLID_VPHYSICS ) end 40 | 41 | self:PhysWake() 42 | end 43 | 44 | function ENT:DrawTranslucent() 45 | local curBlend = render.GetBlend() 46 | render.OverrideDepthEnable(true, true) 47 | render.SetBlend(0) 48 | render.SetColorMaterial() 49 | self:DrawModel() 50 | render.OverrideDepthEnable(false) 51 | 52 | render.SetBlend(0.5) 53 | self:DrawModel() 54 | render.SetBlend(curBlend) 55 | end 56 | 57 | function ENT:Think() 58 | if CLIENT then 59 | local ply = LocalPlayer() 60 | local marioEnt = ply.MarioEnt 61 | if g64utils.WithinBounds(self:GetPos(), ply:GetNetworkOrigin(), 40) and self.Collected == false then 62 | if IsValid(ply.MarioEnt) and ply.IsMario == true and ply.MarioEnt.hasVanishCap == false then 63 | ply.MarioEnt.EnableVanishCap = true 64 | end 65 | 66 | g64utils.RemoveFromClient(self) 67 | self.Collected = true 68 | end 69 | end 70 | end 71 | 72 | list.Set("g64_entities", "g64_vanishcap", { 73 | Category = "Caps", 74 | Name = "Vanish Cap", 75 | Material = "materials/vgui/entities/g64_vanishcap.png" 76 | }) -------------------------------------------------------------------------------- /lua/entities/g64_wingcap.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.Category = "G64" 7 | ENT.PrintName = "Wing Cap" 8 | ENT.Author = "ckosmic" 9 | ENT.Spawnable = false 10 | ENT.AdminSpawnable = true 11 | ENT.AdminOnly = false 12 | 13 | RegisterG64Entity(ENT, "g64_wingcap") 14 | 15 | function ENT:SpawnFunction(ply, tr, ClassName) 16 | if not tr.Hit then return end 17 | 18 | local SpawnPos = tr.HitPos + tr.HitNormal * 16 19 | 20 | local ent = ents.Create(ClassName) 21 | ent:SetPos(SpawnPos) 22 | ent:Spawn() 23 | ent:Activate() 24 | 25 | return ent 26 | end 27 | 28 | function ENT:Initialize() 29 | self:SetModel( "models/player/items/humans/top_hat.mdl" ) 30 | self:SetColor( Color( 255, 255, 255 ) ) 31 | self:SetModelScale(2, 0) 32 | 33 | self:SetMoveType( MOVETYPE_VPHYSICS ) 34 | self:SetSolid( SOLID_VPHYSICS ) 35 | 36 | self.Collected = false 37 | 38 | if SERVER then self:PhysicsInit( SOLID_VPHYSICS ) end 39 | 40 | self:PhysWake() 41 | end 42 | 43 | function ENT:Draw() 44 | self:DrawModel() 45 | end 46 | 47 | function ENT:Think() 48 | if CLIENT then 49 | local ply = LocalPlayer() 50 | local marioEnt = ply.MarioEnt 51 | if g64utils.WithinBounds(self:GetPos(), ply:GetNetworkOrigin(), 40) and self.Collected == false then 52 | if IsValid(ply.MarioEnt) and ply.IsMario == true and ply.MarioEnt.hasWingCap == false then 53 | ply.MarioEnt.EnableWingCap = true 54 | end 55 | 56 | g64utils.RemoveFromClient(self) 57 | self.Collected = true 58 | end 59 | end 60 | end 61 | 62 | list.Set("g64_entities", "g64_wingcap", { 63 | Category = "Caps", 64 | Name = "Wing Cap", 65 | Material = "materials/vgui/entities/g64_wingcap.png" 66 | }) -------------------------------------------------------------------------------- /lua/entities/g64_yellowcoin.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | ENT.Type = "anim" 4 | ENT.Base = "base_entity" 5 | 6 | ENT.Category = "G64" 7 | ENT.PrintName = "Coin" 8 | ENT.Author = "ckosmic" 9 | ENT.Spawnable = false 10 | ENT.AdminSpawnable = true 11 | ENT.AdminOnly = false 12 | 13 | ENT.CoinColor = Color(255, 255, 0) 14 | ENT.CoinValue = 1 15 | 16 | RegisterG64Entity(ENT, "g64_yellowcoin") 17 | 18 | include("entities/g64_coin.lua") 19 | include("includes/g64_utils.lua") 20 | 21 | list.Set("g64_entities", "g64_yellowcoin", { 22 | Category = "Items", 23 | Name = "Coin", 24 | Material = "", 25 | IconGenerator = { 26 | material = g64utils.CoinMat, 27 | u = { 1*0.25, 1*0.25+0.25 }, 28 | v = { 0, 1 }, 29 | tint = Color(255, 255, 0) 30 | } 31 | }) -------------------------------------------------------------------------------- /lua/includes/g64_config.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | if SERVER then return end 4 | 5 | g64config = {} 6 | g64config.ConVars = {} 7 | 8 | g64config.Config = { 9 | MarioColors = { 10 | {0 , 0 , 255}, 11 | {255, 0 , 0 }, 12 | {254, 193, 121}, 13 | {114, 28 , 14 }, 14 | {255, 255, 255}, 15 | {115, 6 , 0 }, 16 | } 17 | } 18 | 19 | g64config.Save = function() 20 | local json = util.TableToJSON(g64config.Config, true) 21 | file.CreateDir("g64") 22 | file.Write("g64/config.json", json) 23 | end 24 | 25 | g64config.Load = function() 26 | if file.Exists("g64/config.json", "DATA") then 27 | local json = file.Read("g64/config.json", "DATA") 28 | local loaded = util.JSONToTable(json) 29 | local loadedKeys = table.GetKeys(loaded) 30 | local defaultKeys = table.GetKeys(g64config.Config) 31 | local dirty = false 32 | for i = 1, #defaultKeys do 33 | if not table.HasValue(loadedKeys, defaultKeys[i]) then 34 | table.insert(loaded, g64config.Config[defaultKeys[i]]) 35 | dirty = true 36 | end 37 | end 38 | for i = 1, #loadedKeys do 39 | if not table.HasValue(defaultKeys, loadedKeys[i]) then 40 | loaded[loadedKeys[i]] = nil 41 | dirty = true 42 | end 43 | end 44 | if dirty then 45 | g64config.Save() 46 | end 47 | g64config.Config = loaded 48 | else 49 | g64config.Save() 50 | end 51 | return g64config.Config 52 | end -------------------------------------------------------------------------------- /lua/includes/g64_luabsp.lua: -------------------------------------------------------------------------------- 1 | -- luabsp by h3xcat: https://github.com/h3xcat/gmod-luabsp 2 | -- ckosmic: reads displacement info/vertices 3 | -- with help from https://github.com/maesse/CubeHags 4 | 5 | local lib_id = debug.getinfo( 1, "S" ).short_src 6 | luabsp = {} 7 | 8 | -- ----------------------------------------------------------------------------- 9 | -- -- Global Constants -- 10 | -- ----------------------------------------------------------------------------- 11 | HEADER_LUMPS = 64 12 | 13 | LUMP_ENTITIES = 0 -- Map entities 14 | LUMP_PLANES = 1 -- Plane array 15 | LUMP_TEXDATA = 2 -- Index to texture names 16 | LUMP_VERTEXES = 3 -- Vertex array 17 | LUMP_VISIBILITY = 4 -- Compressed visibility bit arrays 18 | LUMP_NODES = 5 -- BSP tree nodes 19 | LUMP_TEXINFO = 6 -- Face texture array 20 | LUMP_FACES = 7 -- Face array 21 | LUMP_LIGHTING = 8 -- Lightmap samples 22 | LUMP_OCCLUSION = 9 -- Occlusion polygons and vertices 23 | LUMP_LEAFS = 10 -- BSP tree leaf nodes 24 | LUMP_FACEIDS = 11 -- Correlates between dfaces and Hammer face IDs. Also used as random seed for detail prop placement. 25 | LUMP_EDGES = 12 -- Edge array 26 | LUMP_SURFEDGES = 13 -- Index of edges 27 | LUMP_MODELS = 14 -- Brush models (geometry of brush entities) 28 | LUMP_WORLDLIGHTS = 15 -- Internal world lights converted from the entity lump 29 | LUMP_LEAFFACES = 16 -- Index to faces in each leaf 30 | LUMP_LEAFBRUSHES = 17 -- Index to brushes in each leaf 31 | LUMP_BRUSHES = 18 -- Brush array 32 | LUMP_BRUSHSIDES = 19 -- Brushside array 33 | LUMP_AREAS = 20 -- Area array 34 | LUMP_AREAPORTALS = 21 -- Portals between areas 35 | LUMP_UNUSED0 = 22 -- Unused 36 | LUMP_UNUSED1 = 23 -- Unused 37 | LUMP_UNUSED2 = 24 -- Unused 38 | LUMP_UNUSED3 = 25 -- Unused 39 | LUMP_DISPINFO = 26 -- Displacement surface array 40 | LUMP_ORIGINALFACES = 27 -- Brush faces array before splitting 41 | LUMP_PHYSDISP = 28 -- Displacement physics collision data 42 | LUMP_PHYSCOLLIDE = 29 -- Physics collision data 43 | LUMP_VERTNORMALS = 30 -- Face plane normals 44 | LUMP_VERTNORMALINDICES = 31 -- Face plane normal index array 45 | LUMP_DISP_LIGHTMAP_ALPHAS = 32 -- Displacement lightmap alphas (unused/empty since Source 2006) 46 | LUMP_DISP_VERTS = 33 -- Vertices of displacement surface meshes 47 | LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS = 34 -- Displacement lightmap sample positions 48 | LUMP_GAME_LUMP = 35 -- Game-specific data lump 49 | LUMP_LEAFWATERDATA = 36 -- Data for leaf nodes that are inside water 50 | LUMP_PRIMITIVES = 37 -- Water polygon data 51 | LUMP_PRIMVERTS = 38 -- Water polygon vertices 52 | LUMP_PRIMINDICES = 39 -- Water polygon vertex index array 53 | LUMP_PAKFILE = 40 -- Embedded uncompressed Zip-format file 54 | LUMP_CLIPPORTALVERTS = 41 -- Clipped portal polygon vertices 55 | LUMP_CUBEMAPS = 42 -- env_cubemap location array 56 | LUMP_TEXDATA_STRING_DATA = 43 -- Texture name data 57 | LUMP_TEXDATA_STRING_TABLE = 44 -- Index array into texdata string data 58 | LUMP_OVERLAYS = 45 -- info_overlay data array 59 | LUMP_LEAFMINDISTTOWATER = 46 -- Distance from leaves to water 60 | LUMP_FACE_MACRO_TEXTURE_INFO = 47 -- Macro texture info for faces 61 | LUMP_DISP_TRIS = 48 -- Displacement surface triangles 62 | LUMP_PHYSCOLLIDESURFACE = 49 -- Compressed win32-specific Havok terrain surface collision data. Deprecated and no longer used. 63 | LUMP_WATEROVERLAYS = 50 -- info_overlay's on water faces? 64 | LUMP_LEAF_AMBIENT_INDEX_HDR = 51 -- Index of LUMP_LEAF_AMBIENT_LIGHTING_HDR 65 | LUMP_LEAF_AMBIENT_INDEX = 52 -- Index of LUMP_LEAF_AMBIENT_LIGHTING 66 | LUMP_LIGHTING_HDR = 53 -- HDR lightmap samples 67 | LUMP_WORLDLIGHTS_HDR = 54 -- Internal HDR world lights converted from the entity lump 68 | LUMP_LEAF_AMBIENT_LIGHTING_HDR = 55 -- HDR related leaf lighting data? 69 | LUMP_LEAF_AMBIENT_LIGHTING = 56 -- HDR related leaf lighting data? 70 | LUMP_XZIPPAKFILE = 57 -- XZip version of pak file for Xbox. Deprecated. 71 | LUMP_FACES_HDR = 58 -- HDR maps may have different face data 72 | LUMP_MAP_FLAGS = 59 -- Extended level-wide flags. Not present in all levels. 73 | LUMP_OVERLAY_FADES = 60 -- Fade distances for overlays 74 | LUMP_OVERLAY_SYSTEM_LEVELS = 61 -- System level settings (min/max CPU & GPU to render this overlay) 75 | LUMP_PHYSLEVEL = 62 -- 76 | LUMP_DISP_MULTIBLEND = 63 -- Displacement multiblend info 77 | 78 | 79 | -- ----------------------------------------------------------------------------- 80 | -- -- Helper functions -- 81 | -- ----------------------------------------------------------------------------- 82 | --[[ 83 | local function signed( val, length ) 84 | local val = val 85 | local lastbit = 2^(length*8 - 1) 86 | if val >= lastbit then 87 | val = val - lastbit*2 88 | end 89 | return val 90 | end 91 | ]] 92 | 93 | local function unsigned( val, length ) 94 | local val = val 95 | if val < 0 then 96 | val = val + 2^(length*8) 97 | end 98 | return val 99 | end 100 | 101 | local function plane_intersect( p1, p2, p3 ) 102 | local A1, B1, C1, D1 = p1.A, p1.B, p1.C, p1.D 103 | local A2, B2, C2, D2 = p2.A, p2.B, p2.C, p2.D 104 | local A3, B3, C3, D3 = p3.A, p3.B, p3.C, p3.D 105 | 106 | 107 | local det = (A1)*( B2*C3 - C2*B3 ) 108 | - (B1)*( A2*C3 - C2*A3 ) 109 | + (C1)*( A2*B3 - B2*A3 ) 110 | 111 | if math.abs(det) < 0.001 then return nil end -- No intersection, planes must be parallel 112 | 113 | local x = (D1)*( B2*C3 - C2*B3 ) 114 | - (B1)*( D2*C3 - C2*D3 ) 115 | + (C1)*( D2*B3 - B2*D3 ) 116 | 117 | local y = (A1)*( D2*C3 - C2*D3 ) 118 | - (D1)*( A2*C3 - C2*A3 ) 119 | + (C1)*( A2*D3 - D2*A3 ) 120 | 121 | local z = (A1)*( B2*D3 - D2*B3 ) 122 | - (B1)*( A2*D3 - D2*A3 ) 123 | + (D1)*( A2*B3 - B2*A3 ) 124 | 125 | return Vector(x,y,z)/det 126 | end 127 | 128 | local function is_point_inside_planes( planes, point ) 129 | for i=1, #planes do 130 | local plane = planes[i] 131 | local t = point.x*plane.A + point.y*plane.B + point.z*plane.C 132 | if t - plane.D > 0.01 then return false end 133 | end 134 | return true 135 | end 136 | 137 | local function vertices_from_planes( planes ) 138 | local verts = {} 139 | 140 | for i=1, #planes do 141 | local N1 = planes[i]; 142 | 143 | for j=i+1, #planes do 144 | local N2 = planes[j] 145 | 146 | for k=j+1, #planes do 147 | local N3 = planes[k] 148 | 149 | local pVert = plane_intersect(N1, N2, N3) 150 | if pVert and is_point_inside_planes(planes,pVert) then 151 | verts[#verts + 1] = pVert 152 | end 153 | end 154 | end 155 | end 156 | 157 | -- Filter out duplicate points 158 | local verts2 = {} 159 | for _, v1 in pairs(verts) do 160 | local exist = false 161 | for __, v2 in pairs(verts2) do 162 | if (v1-v2):LengthSqr() < 0.001 then 163 | exist = true 164 | break 165 | end 166 | end 167 | 168 | if not exist then 169 | verts2[#verts2 + 1] = v1 170 | end 171 | end 172 | 173 | return verts2 174 | end 175 | 176 | local function str2numbers( str ) 177 | local ret = {} 178 | for k, v in pairs( string.Explode( " ", str ) ) do 179 | ret[k] = tonumber(v) 180 | end 181 | return unpack( ret ) 182 | end 183 | 184 | local function find_uv( point, textureVecs, texSizeX, texSizeY ) 185 | local x,y,z = point.x, point.y, point.z 186 | local u = textureVecs[1].x * x + textureVecs[1].y * y + textureVecs[1].z * z + textureVecs[1].offset 187 | local v = textureVecs[2].x * x + textureVecs[2].y * y + textureVecs[2].z * z + textureVecs[2].offset 188 | return u/texSizeX, v/texSizeY 189 | end 190 | 191 | -- ----------------------------------------------------------------------------- 192 | -- ----------------------------------------------------------------------------- 193 | local LuaBSP 194 | do 195 | local entity_datatypes = { 196 | ["origin"] = "Vector", 197 | ["sunnormal"] = "Vector", 198 | ["fogdir"] = "Vector", 199 | ["world_mins"] = "Vector", 200 | ["world_maxs"] = "Vector", 201 | ["angles"] = "Angle", 202 | ["fogcolor"] = "Color", 203 | ["fogcolor2"] = "Color", 204 | ["suncolor"] = "Color", 205 | ["bottomcolor"] = "Color", 206 | ["duskcolor"] = "Color", 207 | ["bottomcolor"] = "Color", 208 | ["_light"] = "Color", 209 | ["_lighthdr"] = "Color", 210 | ["rendercolor"] = "Color", 211 | } 212 | local dispIndexToFaceIndex = {} 213 | local cycles = 512 214 | 215 | local lump_parsers 216 | lump_parsers = { 217 | [LUMP_ENTITIES] = -- Map entities 218 | function(fl, lump_data) 219 | lump_data.data = {} 220 | local keyvals = fl:Read( lump_data.filelen-1 ) -- Ignore last character (NUL) 221 | for v in keyvals:gmatch("({.-})") do 222 | local data = util.KeyValuesToTable( "_"..v ) 223 | --[[ 224 | for k, v in pairs( data ) do 225 | if entity_datatypes[k] == "Vector" then 226 | data[k] = Vector(str2numbers(v)) 227 | elseif entity_datatypes[k] == "Angle" then 228 | data[k] = Angle(str2numbers(v)) 229 | elseif entity_datatypes[k] == "Color" then 230 | data[k] = Color(str2numbers(v)) 231 | end 232 | end]] 233 | lump_data.data[#lump_data.data + 1] = data 234 | end 235 | end, 236 | [LUMP_PLANES] = -- Plane array 237 | function(fl, lump_data) 238 | lump_data.data = {} 239 | lump_data.size = lump_data.filelen / 20 240 | 241 | for i=0, lump_data.size - 1 do 242 | if i % cycles == 0 then coroutine.yield() end 243 | lump_data.data[i] = { 244 | A = fl:ReadFloat(), -- float | normal vector x component 245 | B = fl:ReadFloat(), -- float | normal vector y component 246 | C = fl:ReadFloat(), -- float | normal vector z component 247 | D = fl:ReadFloat(), -- float | distance from origin 248 | type = fl:ReadLong(), -- int | plane axis identifier 249 | } 250 | end 251 | end, 252 | [LUMP_TEXDATA] = -- Index to texture names 253 | function(fl, lump_data) 254 | lump_data.data = {} 255 | lump_data.size = lump_data.filelen / 32 256 | for i=0, lump_data.size - 1 do 257 | if i % cycles == 0 then coroutine.yield() end 258 | lump_data.data[i] = { 259 | reflectivity = Vector( fl:ReadFloat(), fl:ReadFloat(), fl:ReadFloat() ), 260 | nameStringTableID = fl:ReadLong(), 261 | width = fl:ReadLong(), 262 | height = fl:ReadLong(), 263 | view_width = fl:ReadLong(), 264 | view_height = fl:ReadLong(), 265 | } 266 | end 267 | end, 268 | [LUMP_VERTEXES] = -- Vertex array 269 | function(fl, lump_data) 270 | lump_data.data = {} 271 | lump_data.size = lump_data.filelen / 12 272 | for i=0, lump_data.size - 1 do 273 | if i % cycles == 0 then coroutine.yield() end 274 | lump_data.data[i] = Vector( 275 | fl:ReadFloat(), -- float | x 276 | fl:ReadFloat(), -- float | y 277 | fl:ReadFloat() -- float | z 278 | ) 279 | end 280 | end, 281 | [LUMP_VISIBILITY] = -- Compressed visibility bit arrays 282 | function(fl, lump_data) end, 283 | [LUMP_NODES] = -- BSP tree nodes 284 | function(fl, lump_data) end, 285 | [LUMP_TEXINFO] = -- Face texture array 286 | function(fl, lump_data) 287 | lump_data.data = {} 288 | lump_data.size = lump_data.filelen / 72 289 | for i=0, lump_data.size - 1 do 290 | if i % cycles == 0 then coroutine.yield() end 291 | lump_data.data[i] = { 292 | textureVecs = { 293 | { x = fl:ReadFloat(), y = fl:ReadFloat(), z = fl:ReadFloat(), offset = fl:ReadFloat()}, 294 | { x = fl:ReadFloat(), y = fl:ReadFloat(), z = fl:ReadFloat(), offset = fl:ReadFloat()}, 295 | }, 296 | lightmapVecs = { 297 | { x = fl:ReadFloat(), y = fl:ReadFloat(), z = fl:ReadFloat(), offset = fl:ReadFloat()}, 298 | { x = fl:ReadFloat(), y = fl:ReadFloat(), z = fl:ReadFloat(), offset = fl:ReadFloat()}, 299 | }, 300 | flags = fl:ReadLong(), 301 | textdata = fl:ReadLong(), 302 | } 303 | end 304 | end, 305 | [LUMP_FACES] = -- Face array 306 | function(fl, lump_data) 307 | lump_data.data = {} 308 | lump_data.size = lump_data.filelen / 56 309 | for i=0, lump_data.size - 1 do 310 | if i % cycles == 0 then coroutine.yield() end 311 | lump_data.data[i] = { 312 | planenum = unsigned( fl:ReadShort(), 2 ), -- unsigned short | the plane number 313 | side = fl:ReadByte(), -- byte | faces opposite to the node's plane direction 314 | onNode = fl:ReadByte(), -- byte | 1 of on node, 0 if in leaf 315 | firstedge = fl:ReadLong(), -- int | index into surfedges 316 | numedges = fl:ReadShort(), -- short | number of surfedges 317 | texinfo = fl:ReadShort(), -- short | texture info 318 | dispinfo = fl:ReadShort(), -- short | displacement info 319 | surfaceFogVolumeID = fl:ReadShort(), -- short | ? 320 | styles = { -- byte[4] | switchable lighting info 321 | fl:ReadByte(), 322 | fl:ReadByte(), 323 | fl:ReadByte(), 324 | fl:ReadByte(), 325 | }, 326 | lightofs = fl:ReadLong(), -- int | offset into lightmap lump 327 | area = fl:ReadFloat(), -- float | face area in units^2 328 | LightmapTextureMinsInLuxels = { -- int[2] | texture lighting info 329 | fl:ReadLong(), 330 | fl:ReadLong(), 331 | }, 332 | LightmapTextureSizeInLuxels = { -- int[2] | texture lighting info 333 | fl:ReadLong(), 334 | fl:ReadLong(), 335 | }, 336 | origFace = fl:ReadLong(), -- int | original face this was split from 337 | numPrims = fl:ReadUShort(), -- unsigned short | primitives 338 | firstPrimID = fl:ReadUShort(), -- unsigned short 339 | smoothingGroups = fl:ReadULong(), -- unsigned int | lightmap smoothing group 340 | } 341 | if(lump_data.data[i].dispinfo != -1) then 342 | dispIndexToFaceIndex[lump_data.data[i].dispinfo] = i 343 | end 344 | end 345 | end, 346 | [LUMP_LIGHTING] = -- Lightmap samples 347 | function(fl, lump_data) end, 348 | [LUMP_OCCLUSION] = -- Occlusion polygons and vertices 349 | function(fl, lump_data) end, 350 | [LUMP_LEAFS] = -- BSP tree leaf nodes 351 | function(fl, lump_data) end, 352 | [LUMP_FACEIDS] = -- Correlates between dfaces and Hammer face IDs. Also used as random seed for detail prop placement. 353 | function(fl, lump_data) end, 354 | [LUMP_EDGES] = -- Edge array 355 | function(fl, lump_data) 356 | lump_data.data = {} 357 | lump_data.size = lump_data.filelen / 4 358 | for i=0, lump_data.size - 1 do 359 | if i % cycles == 0 then coroutine.yield() end 360 | lump_data.data[i] = { 361 | unsigned( fl:ReadShort(), 2 ), -- unsigned short | vertex indice 1 362 | unsigned( fl:ReadShort(), 2 ), -- unsigned short | vertex indice 2 363 | } 364 | end 365 | end, 366 | [LUMP_SURFEDGES] = -- Index of edges 367 | function(fl, lump_data) 368 | lump_data.data = {} 369 | lump_data.size = lump_data.filelen / 4 370 | for i=0, lump_data.size - 1 do 371 | if i % cycles == 0 then coroutine.yield() end 372 | lump_data.data[i] = fl:ReadLong() 373 | end 374 | end, 375 | [LUMP_MODELS] = -- Brush models (geometry of brush entities) 376 | function(fl, lump_data) end, 377 | [LUMP_WORLDLIGHTS] = -- Internal world lights converted from the entity lump 378 | function(fl, lump_data) end, 379 | [LUMP_LEAFFACES] = -- Index to faces in each leaf 380 | function(fl, lump_data) end, 381 | [LUMP_LEAFBRUSHES] = -- Index to brushes in each leaf 382 | function(fl, lump_data) end, 383 | [LUMP_BRUSHES] = -- Brush array 384 | function(fl, lump_data) 385 | lump_data.data = {} 386 | lump_data.size = lump_data.filelen / 12 387 | for i=0, lump_data.size - 1 do 388 | if i % cycles == 0 then coroutine.yield() end 389 | lump_data.data[i] = { 390 | firstside = fl:ReadLong(), -- int | first brushside 391 | numsides = fl:ReadLong(), -- int | number of brushsides 392 | contents = fl:ReadLong(), -- int | content flags 393 | } 394 | end 395 | end, 396 | [LUMP_BRUSHSIDES] = -- Brushside array 397 | function(fl, lump_data) 398 | lump_data.data = {} 399 | lump_data.size = lump_data.filelen / 8 400 | for i=0, lump_data.size - 1 do 401 | if i % cycles == 0 then coroutine.yield() end 402 | lump_data.data[i] = { 403 | planenum = fl:ReadUShort(), -- unsigned short | facing out of the leaf 404 | texinfo = fl:ReadShort(), -- short | texture info 405 | dispinfo = fl:ReadShort(), -- short | displacement info 406 | bevel = fl:ReadShort(), -- short | is the side a bevel plane? 407 | } 408 | end 409 | end, 410 | [LUMP_AREAS] = -- Area array 411 | function(fl, lump_data) end, 412 | [LUMP_AREAPORTALS] = -- Portals between areas 413 | function(fl, lump_data) end, 414 | [LUMP_UNUSED0] = -- Unused 415 | function(fl, lump_data) end, 416 | [LUMP_UNUSED1] = -- Unused 417 | function(fl, lump_data) end, 418 | [LUMP_UNUSED2] = -- Unused 419 | function(fl, lump_data) end, 420 | [LUMP_UNUSED3] = -- Unused 421 | function(fl, lump_data) end, 422 | [LUMP_DISPINFO] = -- Displacement surface array 423 | function(fl, lump_data) 424 | lump_data.data = {} 425 | lump_data.size = lump_data.filelen / 176 426 | local function ReadCDispSubNeighbor() 427 | return { 428 | span = fl:ReadByte(), 429 | neighborSpan = fl:ReadByte(), 430 | neighbor = fl:ReadUShort(), 431 | unknown = fl:ReadByte(), 432 | neighborOrientation = fl:ReadByte() 433 | } 434 | end 435 | local function ReadCDispCornerNeighbors() 436 | return { 437 | neighbors = { fl:ReadUShort(), fl:ReadUShort(), fl:ReadUShort(), fl:ReadUShort() }, 438 | nNeighbors = fl:ReadByte() 439 | } 440 | end 441 | for i=0, lump_data.size - 1 do 442 | if i % cycles == 0 then coroutine.yield() end 443 | lump_data.data[i] = { 444 | startPosition = Vector(fl:ReadFloat(), fl:ReadFloat(), fl:ReadFloat()), 445 | dispVertStart = fl:ReadLong(), 446 | dispTriStart = fl:ReadLong(), 447 | power = fl:ReadLong(), 448 | flags = fl:ReadByte(), 449 | minTess = fl:Read(3), 450 | smoothingAngle = fl:ReadFloat(), 451 | contents = fl:ReadULong(), 452 | mapFace = fl:ReadUShort(), 453 | lightmapAlphaStart = fl:ReadLong(), 454 | lightmapSamplePositionStart = fl:ReadLong(), 455 | edgeNeighbors = { 456 | { ReadCDispSubNeighbor(), ReadCDispSubNeighbor() }, 457 | { ReadCDispSubNeighbor(), ReadCDispSubNeighbor() }, 458 | { ReadCDispSubNeighbor(), ReadCDispSubNeighbor() }, 459 | { ReadCDispSubNeighbor(), ReadCDispSubNeighbor() } 460 | }, 461 | cornerNeighbors = { 462 | ReadCDispCornerNeighbors(), 463 | ReadCDispCornerNeighbors(), 464 | ReadCDispCornerNeighbors(), 465 | ReadCDispCornerNeighbors() 466 | }, 467 | unknown = fl:Read(6), 468 | allowedVerts = { 469 | fl:ReadULong(), 470 | fl:ReadULong(), 471 | fl:ReadULong(), 472 | fl:ReadULong(), 473 | fl:ReadULong(), 474 | fl:ReadULong(), 475 | fl:ReadULong(), 476 | fl:ReadULong(), 477 | fl:ReadULong(), 478 | fl:ReadULong() 479 | } 480 | } 481 | end 482 | end, 483 | [LUMP_ORIGINALFACES] = -- Brush faces array before splitting 484 | function(fl, lump_data) 485 | lump_parsers[LUMP_FACES]( fl, lump_data ) 486 | end, 487 | [LUMP_PHYSDISP] = -- Displacement physics collision data 488 | function(fl, lump_data) end, 489 | [LUMP_PHYSCOLLIDE] = -- Physics collision data 490 | function(fl, lump_data) end, 491 | [LUMP_VERTNORMALS] = -- Face plane normals 492 | function(fl, lump_data) end, 493 | [LUMP_VERTNORMALINDICES] = -- Face plane normal index array 494 | function(fl, lump_data) end, 495 | [LUMP_DISP_LIGHTMAP_ALPHAS] = -- Displacement lightmap alphas (unused/empty since Source 2006) 496 | function(fl, lump_data) end, 497 | [LUMP_DISP_VERTS] = -- Vertices of displacement surface meshes 498 | function(fl, lump_data) 499 | lump_data.data = {} 500 | lump_data.size = lump_data.filelen / 20 501 | for i=0, lump_data.size - 1 do 502 | if i % cycles == 0 then coroutine.yield() end 503 | lump_data.data[i] = { 504 | vec = Vector(fl:ReadFloat(), fl:ReadFloat(), fl:ReadFloat()), 505 | dist = fl:ReadFloat(), 506 | alpha = fl:ReadFloat() 507 | } 508 | end 509 | end, 510 | [LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS] = -- Displacement lightmap sample positions 511 | function(fl, lump_data) end, 512 | [LUMP_GAME_LUMP] = -- Game-specific data lump 513 | function(fl, lump_data) 514 | lump_data.data = {} 515 | lump_data.size = fl:ReadLong() 516 | for i=1,lump_data.size do 517 | if i % cycles == 0 then coroutine.yield() end 518 | lump_data.data[i] = { 519 | id = fl:Read( 4 ), 520 | flags = fl:ReadShort(), 521 | version = fl:ReadShort(), 522 | fileofs = fl:ReadLong(), 523 | filelen = fl:ReadLong(), 524 | } 525 | end 526 | end, 527 | [LUMP_LEAFWATERDATA] = -- Data for leaf nodes that are inside water 528 | function(fl, lump_data) end, 529 | [LUMP_PRIMITIVES] = -- Water polygon data 530 | function(fl, lump_data) end, 531 | [LUMP_PRIMVERTS] = -- Water polygon vertices 532 | function(fl, lump_data) end, 533 | [LUMP_PRIMINDICES] = -- Water polygon vertex index array 534 | function(fl, lump_data) end, 535 | [LUMP_PAKFILE] = -- Embedded uncompressed Zip-format file 536 | function(fl, lump_data) end, 537 | [LUMP_CLIPPORTALVERTS] = -- Clipped portal polygon vertices 538 | function(fl, lump_data) end, 539 | [LUMP_CUBEMAPS] = -- env_cubemap location array 540 | function(fl, lump_data) 541 | lump_data.data = {} 542 | lump_data.size = lump_data.filelen / 16 543 | 544 | for i=0, lump_data.size - 1 do 545 | if i % cycles == 0 then coroutine.yield() end 546 | local origin = Vector(fl:ReadLong(), fl:ReadLong(), fl:ReadLong()) 547 | local size = fl:ReadLong() 548 | 549 | if size < 1 then size = 6 end -- default size should be 32x32 550 | 551 | lump_data.data[i] = { 552 | origin = origin, 553 | size = 2^(size-1) 554 | } 555 | end 556 | end, 557 | [LUMP_TEXDATA_STRING_DATA] = -- Texture name data 558 | function(fl, lump_data) 559 | lump_data.data = {} 560 | local data = string.Explode( "\0", fl:Read(lump_data.filelen) ) 561 | local offset = 0 562 | for k, v in pairs(data) do 563 | lump_data.data[offset] = v 564 | offset = offset + 1 + #v 565 | end 566 | end, 567 | [LUMP_TEXDATA_STRING_TABLE] = -- Index array into texdata string data 568 | function(fl, lump_data) 569 | lump_data.data = {} 570 | lump_data.size = lump_data.filelen / 4 571 | for i=0, lump_data.size - 1 do 572 | if i % cycles == 0 then coroutine.yield() end 573 | lump_data.data[i] = fl:ReadLong() 574 | end 575 | end, 576 | [LUMP_OVERLAYS] = -- info_overlay data array 577 | function(fl, lump_data) end, 578 | [LUMP_LEAFMINDISTTOWATER] = -- Distance from leaves to water 579 | function(fl, lump_data) end, 580 | [LUMP_FACE_MACRO_TEXTURE_INFO] = -- Macro texture info for faces 581 | function(fl, lump_data) end, 582 | [LUMP_DISP_TRIS] = -- Displacement surface triangles 583 | function(fl, lump_data) end, 584 | [LUMP_PHYSCOLLIDESURFACE] = -- Compressed win32-specific Havok terrain surface collision data. Deprecated and no longer used. 585 | function(fl, lump_data) end, 586 | [LUMP_WATEROVERLAYS] = -- info_overlay's on water faces? 587 | function(fl, lump_data) end, 588 | [LUMP_LEAF_AMBIENT_INDEX_HDR] = -- Index of LUMP_LEAF_AMBIENT_LIGHTING_HDR 589 | function(fl, lump_data) end, 590 | [LUMP_LEAF_AMBIENT_INDEX] = -- Index of LUMP_LEAF_AMBIENT_LIGHTING 591 | function(fl, lump_data) end, 592 | [LUMP_LIGHTING_HDR] = -- HDR lightmap samples 593 | function(fl, lump_data) end, 594 | [LUMP_WORLDLIGHTS_HDR] = -- Internal HDR world lights converted from the entity lump 595 | function(fl, lump_data) end, 596 | [LUMP_LEAF_AMBIENT_LIGHTING_HDR] = -- HDR related leaf lighting data? 597 | function(fl, lump_data) end, 598 | [LUMP_LEAF_AMBIENT_LIGHTING] = -- HDR related leaf lighting data? 599 | function(fl, lump_data) end, 600 | [LUMP_XZIPPAKFILE] = -- XZip version of pak file for Xbox. Deprecated. 601 | function(fl, lump_data) end, 602 | [LUMP_FACES_HDR] = -- HDR maps may have different face data 603 | function(fl, lump_data) end, 604 | [LUMP_MAP_FLAGS] = -- Extended level-wide flags. Not present in all levels. 605 | function(fl, lump_data) end, 606 | [LUMP_OVERLAY_FADES] = -- Fade distances for overlays 607 | function(fl, lump_data) end, 608 | [LUMP_OVERLAY_SYSTEM_LEVELS] = -- System level settings (min/max CPU & GPU to render this overlay) 609 | function(fl, lump_data) end, 610 | [LUMP_PHYSLEVEL] = -- 611 | function(fl, lump_data) end, 612 | [LUMP_DISP_MULTIBLEND] = -- Displacement multiblend info 613 | function(fl, lump_data) end, 614 | } 615 | 616 | LuaBSP = {} 617 | LuaBSP.__index = LuaBSP 618 | 619 | function LuaBSP:GetMapFileHandle( mapname ) 620 | self.mapname = mapname or self.mapname 621 | local filename = "maps/"..self.mapname..".bsp" 622 | local fl = file.Open( filename, "rb", "GAME") 623 | if not fl then error( "[LuaBSP] Unable to open: "..filename ) end 624 | 625 | return fl 626 | end 627 | 628 | function LuaBSP.new( mapname ) 629 | assert( mapname, "[LuaBSP] Invalid map name" ) 630 | 631 | local self = setmetatable({}, LuaBSP) 632 | local filename = "maps/"..mapname..".bsp" 633 | local fl = self:GetMapFileHandle( mapname ) 634 | 635 | local ident = fl:Read( 4 ) -- BSP file identifier 636 | if ident ~= "VBSP" then error( "[LuaBSP] Invalid file header: "..ident ) return end 637 | 638 | self.version = fl:ReadLong() -- BSP file version 639 | self.lumps = {} -- lump directory array 640 | 641 | for i=0, HEADER_LUMPS-1 do 642 | self.lumps[i] = { 643 | fileofs = fl:ReadLong(), -- offset into file (bytes) 644 | filelen = fl:ReadLong(), -- length of lump (bytes) 645 | version = fl:ReadLong(), -- lump format version 646 | fourCC = fl:Read( 4 ), -- lump ident code 647 | } 648 | end 649 | self.map_revision = fl:ReadLong() -- the map's revision (iteration, version) number 650 | 651 | --[[ 652 | for i=0, HEADER_LUMPS-1 do 653 | local lump_data = self.lumps[i] 654 | fl:Seek( lump_data.fileofs ) 655 | lump_parsers[i]( fl, lump_data ) 656 | end 657 | ]] 658 | 659 | fl:Close() 660 | 661 | return self 662 | end 663 | 664 | function LuaBSP:LoadLumps( callback, ... ) 665 | local fl = self:GetMapFileHandle() 666 | local lumpArgs = {...} 667 | 668 | local function LoadLump(index) 669 | local lump = lumpArgs[index] 670 | local lump_data = self.lumps[lump] 671 | fl:Seek( lump_data.fileofs ) 672 | local co 673 | hook.Add("Think", "LoadLumpsThink", function() 674 | if not co then 675 | co = coroutine.create(lump_parsers[lump]) 676 | end 677 | if coroutine.resume(co, fl, lump_data) == false then 678 | hook.Remove("Think", "LoadLumpsThink") 679 | if(index + 1 > #lumpArgs) then 680 | co = nil 681 | fl:Close() 682 | return callback() 683 | else 684 | return LoadLump(index + 1) 685 | end 686 | end 687 | end) 688 | end 689 | 690 | LoadLump(1) 691 | end 692 | 693 | function LuaBSP:LoadDisplacementInfos(callback) 694 | self:LoadLumps( function() 695 | local fl = self:GetMapFileHandle() 696 | local faces = self.lumps[LUMP_FACES] 697 | 698 | local displacement_infos = {} 699 | for _,face_lump in ipairs( faces.data ) do 700 | local dispinfoIndex = face_lump.dispinfo 701 | if(dispinfoIndex != -1) then 702 | local dispInfo = self.lumps[LUMP_DISPINFO]["data"][dispinfoIndex] 703 | table.insert(displacement_infos, dispInfo) 704 | end 705 | end 706 | --for _,origface_lump in ipairs( origFaces.data ) do 707 | -- local dispinfoIndex = origface_lump.dispinfo 708 | -- if(dispinfoIndex != -1) then 709 | -- local dispInfo = self.lumps[LUMP_DISPINFO]["data"][dispinfoIndex] 710 | -- table.insert(displacement_infos, dispInfo) 711 | -- end 712 | --end 713 | --for _,brushside_lump in ipairs( brushSides.data ) do 714 | -- local dispinfoIndex = brushside_lump.dispinfo 715 | -- if(dispinfoIndex != -1) then 716 | -- local dispInfo = self.lumps[LUMP_DISPINFO]["data"][dispinfoIndex] 717 | -- table.insert(displacement_infos, dispInfo) 718 | -- end 719 | --end 720 | self.displacement_infos = displacement_infos 721 | 722 | fl:Close() 723 | return callback() 724 | end, LUMP_DISPINFO, LUMP_FACES ) 725 | end 726 | 727 | function LuaBSP:LoadDisplacementVertices(callback) 728 | self:LoadLumps( function() 729 | self:LoadDisplacementInfos(function() 730 | 731 | local fl = self:GetMapFileHandle() 732 | local worldFaces = self.lumps[LUMP_FACES]["data"] 733 | local worldEdges = self.lumps[LUMP_EDGES]["data"] 734 | local surfEdges = self.lumps[LUMP_SURFEDGES]["data"] 735 | local worldVerts = self.lumps[LUMP_VERTEXES]["data"] 736 | local dispVerts = self.lumps[LUMP_DISP_VERTS]["data"] 737 | 738 | self.displacement_vertices = {} 739 | local displacement_vertices = {} 740 | local curVert = 0 741 | for _,dispinfo in ipairs( self.displacement_infos ) do 742 | local power = dispinfo.power 743 | local PostSpacing = bit.lshift(1, power) + 1 744 | 745 | local nVerts = PostSpacing * PostSpacing 746 | local nTris = bit.lshift(1, power) * bit.lshift(1, power) * 2 747 | local thisDispVerts = {} 748 | for i = 0, nVerts do 749 | thisDispVerts[i] = dispVerts[i + curVert] 750 | end 751 | curVert = curVert + nVerts 752 | 753 | local pointStartIndex = -1 754 | local face = worldFaces[dispinfo.mapFace] 755 | if not face then break end 756 | if(face.numedges <= 4) then 757 | local pointStart = dispinfo.startPosition 758 | 759 | local surfPoints = {} 760 | 761 | for i = 0, face.numedges - 1 do 762 | local eIndex = surfEdges[face.firstedge + i] 763 | if(eIndex < 0) then 764 | surfPoints[i] = worldVerts[worldEdges[-eIndex][2]] 765 | else 766 | surfPoints[i] = worldVerts[worldEdges[eIndex][1]] 767 | end 768 | end 769 | 770 | if(pointStartIndex == -1) then 771 | local minIndex = -1 772 | local minDist = 10000000.0 773 | for i = 0, 3 do 774 | local segment = pointStart - surfPoints[i] 775 | local distSq = segment:LengthSqr() 776 | if(distSq < minDist) then 777 | minDist = distSq 778 | minIndex = i 779 | end 780 | end 781 | 782 | pointStartIndex = minIndex 783 | end 784 | 785 | local tmpPoints = {} 786 | for i = 0, 3 do 787 | tmpPoints[i] = surfPoints[i] 788 | end 789 | for i = 0, 3 do 790 | surfPoints[i] = tmpPoints[(i + pointStartIndex) % 4] 791 | end 792 | 793 | local ooInt = 1.0 / (PostSpacing - 1.0) 794 | local edgeInt = { (surfPoints[1] - surfPoints[0]) * ooInt, (surfPoints[2] - surfPoints[3]) * ooInt } 795 | 796 | local vertexGrid = {} 797 | for i = 0, PostSpacing-1 do 798 | local endPts = { (edgeInt[1] * i) + surfPoints[0], (edgeInt[2] * i) + surfPoints[3] } 799 | local seg = (endPts[2] - endPts[1]) 800 | local segInt = seg * ooInt 801 | vertexGrid[i] = {} 802 | 803 | for j = 0, PostSpacing-1 do 804 | local ndx = i * PostSpacing + j 805 | local vertexInfo = thisDispVerts[ndx] 806 | local vertex = endPts[1] + (segInt * j) 807 | vertex = vertex + vertexInfo.vec * vertexInfo.dist 808 | vertexGrid[i][j] = vertex 809 | end 810 | end 811 | 812 | for x = 0, #vertexGrid-1 do 813 | for y = 0, #vertexGrid[x]-1 do 814 | local ndx = x * (#vertexGrid-1) + y 815 | if(ndx % 2 == 0) then 816 | table.insert(displacement_vertices, vertexGrid[x][y]) 817 | table.insert(displacement_vertices, vertexGrid[x+1][y]) 818 | table.insert(displacement_vertices, vertexGrid[x+1][y+1]) 819 | 820 | table.insert(displacement_vertices, vertexGrid[x][y]) 821 | table.insert(displacement_vertices, vertexGrid[x+1][y+1]) 822 | table.insert(displacement_vertices, vertexGrid[x][y+1]) 823 | else 824 | table.insert(displacement_vertices, vertexGrid[x+1][y]) 825 | table.insert(displacement_vertices, vertexGrid[x][y+1]) 826 | table.insert(displacement_vertices, vertexGrid[x][y]) 827 | 828 | table.insert(displacement_vertices, vertexGrid[x+1][y]) 829 | table.insert(displacement_vertices, vertexGrid[x+1][y+1]) 830 | table.insert(displacement_vertices, vertexGrid[x][y+1]) 831 | end 832 | end 833 | end 834 | end 835 | end 836 | 837 | self.displacement_vertices = displacement_vertices 838 | fl:Close() 839 | return callback() 840 | 841 | end) 842 | end, LUMP_DISP_VERTS, LUMP_EDGES, LUMP_SURFEDGES, LUMP_VERTEXES ) 843 | end 844 | 845 | function LuaBSP:LoadStaticProps(callback) 846 | self:LoadLumps( function() 847 | 848 | local fl = self:GetMapFileHandle() 849 | local lump = self.lumps[LUMP_GAME_LUMP] 850 | 851 | local static_props = {} 852 | for _,game_lump in ipairs( lump.data ) do 853 | local version = game_lump.version 854 | local static_props_entry = { 855 | names = {}, 856 | leaf = {}, 857 | leaf_entries = 0, 858 | entries = {}, 859 | } 860 | 861 | if not (version >= 4 and version < 12) then continue end 862 | 863 | fl:Seek( game_lump.fileofs ) 864 | 865 | local dict_entries = fl:ReadLong() 866 | if dict_entries < 0 or dict_entries >= 9999 then continue end 867 | 868 | for i=1,dict_entries do 869 | static_props_entry.names[i-1] = fl:Read( 128 ):match( "^[^%z]+" ) or "" 870 | end 871 | 872 | local leaf_entries = fl:ReadLong() 873 | if leaf_entries < 0 then continue end 874 | 875 | static_props_entry.leaf_entries = leaf_entries 876 | for i=1,leaf_entries do 877 | static_props_entry.leaf[i] = fl:ReadUShort() 878 | end 879 | 880 | local amount = fl:ReadLong() 881 | if amount < 0 or amount >= ( 8192 * 2 ) then continue end 882 | 883 | for i=1,amount do 884 | local static_prop = {} 885 | static_props_entry.entries[i] = static_prop 886 | 887 | static_prop.Origin = Vector( fl:ReadFloat(), fl:ReadFloat(), fl:ReadFloat() ) 888 | static_prop.Angles = Angle( fl:ReadFloat(), fl:ReadFloat(), fl:ReadFloat() ) 889 | 890 | if version >= 11 then 891 | static_prop.Scale = fl:ReadShort() 892 | end 893 | 894 | local _1,_2 = string.byte(fl:Read(2),1,2) 895 | local proptype = _1 + _2 * 256 896 | 897 | static_prop.PropType = static_props_entry.names[proptype] 898 | if not static_prop.PropType then continue end 899 | 900 | static_prop.FirstLeaf = fl:ReadShort() 901 | static_prop.LeafCount = fl:ReadShort() 902 | static_prop.Solid = fl:ReadByte() 903 | static_prop.Flags = fl:ReadByte() 904 | static_prop.Skin = fl:ReadLong() 905 | if not static_prop.Skin then continue end 906 | 907 | static_prop.FadeMinDist = fl:ReadFloat() 908 | static_prop.FadeMaxDist = fl:ReadFloat() 909 | static_prop.LightingOrigin = Vector( fl:ReadFloat(), fl:ReadFloat(), fl:ReadFloat() ) 910 | 911 | if version >= 5 then 912 | static_prop.ForcedFadeScale = fl:ReadFloat() 913 | end 914 | 915 | if version == 6 or version == 7 then 916 | static_prop.MinDXLevel = fl:ReadShort() 917 | static_prop.MaxDXLevel = fl:ReadShort() 918 | end 919 | 920 | if version >= 8 then 921 | static_prop.MinCPULevel = fl:ReadByte() 922 | static_prop.MaxCPULevel = fl:ReadByte() 923 | static_prop.MinGPULevel = fl:ReadByte() 924 | static_prop.MaxGPULevel = fl:ReadByte() 925 | end 926 | 927 | if version >= 7 then 928 | static_prop.DiffuseModulation = Color( string.byte( fl:Read( 4 ), 1, 4 ) ) 929 | end 930 | 931 | if version >= 10 then 932 | static_prop.unknown = fl:ReadFloat() 933 | end 934 | 935 | if version == 9 then 936 | static_prop.DisableX360 = fl:ReadByte() == 1 937 | end 938 | 939 | end 940 | 941 | table.insert( static_props, static_props_entry ) 942 | end 943 | 944 | self.static_props = static_props 945 | 946 | fl:Close() 947 | return callback() 948 | 949 | end, LUMP_GAME_LUMP ) 950 | end 951 | 952 | function LuaBSP:GetClipBrushes( single_mesh ) 953 | self:LoadLumps( LUMP_BRUSHES, LUMP_BRUSHSIDES, LUMP_PLANES, LUMP_TEXINFO ) 954 | 955 | local brushes = {} 956 | local brush_verts = {} 957 | 958 | for brush_id = 0, #self.lumps[LUMP_BRUSHES]["data"]-1 do 959 | local brush = self.lumps[LUMP_BRUSHES]["data"][brush_id] 960 | local brush_firstside = brush.firstside 961 | local brush_numsides = brush.numsides 962 | local brush_contents = brush.contents 963 | 964 | if bit.band( brush_contents, CONTENTS_PLAYERCLIP ) == 0 then continue end 965 | 966 | local base_color = Vector(1,0,1) 967 | if not single_mesh then 968 | brush_verts = {} 969 | end 970 | 971 | brush.p_bsides = {} 972 | local planes = {} 973 | for i = 0, brush_numsides - 1 do 974 | local brushside_id = (brush_firstside + i) 975 | local brushside = self.lumps[LUMP_BRUSHSIDES]["data"][brushside_id] 976 | 977 | if brushside.bevel ~= 0 then continue end -- bevel != 0 means its used for physics collision, not interested 978 | local plane = self.lumps[LUMP_PLANES]["data"][brushside.planenum] 979 | brush.p_bsides[#brush.p_bsides + 1] = { 980 | brushside = brushside, 981 | plane = plane 982 | } 983 | planes[#planes + 1] = plane 984 | end 985 | 986 | brush.p_points = vertices_from_planes(planes) 987 | brush.p_render_data = {} 988 | for _, bside in pairs(brush.p_bsides) do 989 | local plane = bside.plane 990 | if not plane then continue end 991 | local render_data = { 992 | texinfo = bside.brushside.texinfo, 993 | plane = plane, 994 | points = {}, 995 | } 996 | for __, point in pairs(brush.p_points) do 997 | local t = point.x*plane.A + point.y*plane.B + point.z*plane.C 998 | if math.abs(t-plane.D) > 0.01 then continue end -- Not on a plane 999 | 1000 | render_data.points[#render_data.points + 1] = point 1001 | end 1002 | 1003 | -- sort them in clockwise order 1004 | local norm = Vector(plane.A, plane.B, plane.C) 1005 | local c = render_data.points[1] 1006 | table.sort(render_data.points, function(a, b) 1007 | return norm:Dot((c-a):Cross(b-c)) > 0.001 1008 | end) 1009 | 1010 | render_data.norm = norm 1011 | 1012 | local points = render_data.points 1013 | local norm = render_data.norm 1014 | local dot = math.abs( norm:Dot(Vector(-1,100,100):GetNormalized()) ) 1015 | local color = Color(100+55*dot,100+55*dot,100+55*dot) -- Color( 40357164 / 255 ) 1016 | color.r = color.r * base_color.x 1017 | color.g = color.g * base_color.y 1018 | color.b = color.b * base_color.z 1019 | color.a = 255 1020 | 1021 | local texinfo = self.lumps[LUMP_TEXINFO]["data"][render_data.texinfo] 1022 | 1023 | 1024 | local ref = Vector(0,0,-1) 1025 | if math.abs( norm:Dot( Vector(0,0,1) ) ) == 1 then 1026 | ref = Vector(0,1,0) 1027 | end 1028 | 1029 | local tv1 = norm:Cross( ref ):Cross( norm ):GetNormalized() 1030 | local tv2 = norm:Cross( tv1 ) 1031 | 1032 | local textureVecs = {{x=tv2.x,y=tv2.y,z=tv2.z,offset=0}, 1033 | {x=tv1.x,y=tv1.y,z=tv1.z,offset=0}}-- texinfo.textureVecs 1034 | local u, v 1035 | for j = 1, #points - 2 do 1036 | u1, v1 = find_uv(points[1], textureVecs, 32, 32) 1037 | u2, v2 = find_uv(points[j+1], textureVecs, 32, 32) 1038 | u3, v3 = find_uv(points[j+2], textureVecs, 32, 32) 1039 | brush_verts[#brush_verts + 1] = { pos = points[1]+norm*0 , u = u1, v = v1, color = color } 1040 | brush_verts[#brush_verts + 1] = { pos = points[j+1]+norm*0, u = u2, v = v2, color = color } 1041 | brush_verts[#brush_verts + 1] = { pos = points[j+2]+norm*0, u = u3, v = v3, color = color } 1042 | end 1043 | end 1044 | 1045 | if not single_mesh then 1046 | local obj = Mesh() 1047 | obj:BuildFromTriangles( brush_verts ) 1048 | 1049 | brush.p_mesh = obj 1050 | brushes[#brushes+1] = obj 1051 | end 1052 | end 1053 | 1054 | if single_mesh then 1055 | local obj = Mesh() 1056 | obj:BuildFromTriangles( brush_verts ) 1057 | 1058 | return obj 1059 | end 1060 | 1061 | return brushes 1062 | end 1063 | end 1064 | 1065 | 1066 | -------------------------------------------------------------------------------- 1067 | -------------------------------------------------------------------------------- 1068 | -------------------------------------------------------------------------------- 1069 | 1070 | function luabsp.LoadMap( map_name ) 1071 | return LuaBSP.new( map_name ) 1072 | end 1073 | 1074 | function luabsp.GetLibraryID() 1075 | return lib_id 1076 | end 1077 | 1078 | return luabsp -------------------------------------------------------------------------------- /lua/includes/g64_sprites.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | g64sprites = {} 4 | 5 | g64sprites.Dimensions = { 6 | UI = { 256, 16 }, 7 | Health = { 1024, 64 } 8 | } 9 | g64sprites.UI = { 10 | tex_width = g64sprites.Dimensions.UI[1], 11 | tex_height = g64sprites.Dimensions.UI[2], 12 | num_0 = { 13 | w = 16, 14 | h = 16, 15 | u = 16/g64sprites.Dimensions.UI[1]*0, 16 | v = 16/g64sprites.Dimensions.UI[2]*0, 17 | }, 18 | num_1 = { 19 | w = 16, 20 | h = 16, 21 | u = 16/g64sprites.Dimensions.UI[1]*1, 22 | v = 16/g64sprites.Dimensions.UI[2]*0, 23 | }, 24 | num_2 = { 25 | w = 16, 26 | h = 16, 27 | u = 16/g64sprites.Dimensions.UI[1]*2, 28 | v = 16/g64sprites.Dimensions.UI[2]*0, 29 | }, 30 | num_3 = { 31 | w = 16, 32 | h = 16, 33 | u = 16/g64sprites.Dimensions.UI[1]*3, 34 | v = 16/g64sprites.Dimensions.UI[2]*0, 35 | }, 36 | num_4 = { 37 | w = 16, 38 | h = 16, 39 | u = 16/g64sprites.Dimensions.UI[1]*4, 40 | v = 16/g64sprites.Dimensions.UI[2]*0, 41 | }, 42 | num_5 = { 43 | w = 16, 44 | h = 16, 45 | u = 16/g64sprites.Dimensions.UI[1]*5, 46 | v = 16/g64sprites.Dimensions.UI[2]*0, 47 | }, 48 | num_6 = { 49 | w = 16, 50 | h = 16, 51 | u = 16/g64sprites.Dimensions.UI[1]*6, 52 | v = 16/g64sprites.Dimensions.UI[2]*0, 53 | }, 54 | num_7 = { 55 | w = 16, 56 | h = 16, 57 | u = 16/g64sprites.Dimensions.UI[1]*7, 58 | v = 16/g64sprites.Dimensions.UI[2]*0, 59 | }, 60 | num_8 = { 61 | w = 16, 62 | h = 16, 63 | u = 16/g64sprites.Dimensions.UI[1]*8, 64 | v = 16/g64sprites.Dimensions.UI[2]*0, 65 | }, 66 | num_9 = { 67 | w = 16, 68 | h = 16, 69 | u = 16/g64sprites.Dimensions.UI[1]*9, 70 | v = 16/g64sprites.Dimensions.UI[2]*0, 71 | }, 72 | times = { 73 | w = 16, 74 | h = 16, 75 | u = 16/g64sprites.Dimensions.UI[1]*10, 76 | v = 16/g64sprites.Dimensions.UI[2]*0, 77 | }, 78 | coin = { 79 | w = 16, 80 | h = 16, 81 | u = 16/g64sprites.Dimensions.UI[1]*11, 82 | v = 16/g64sprites.Dimensions.UI[2]*0, 83 | }, 84 | mario_head = { 85 | w = 16, 86 | h = 16, 87 | u = 16/g64sprites.Dimensions.UI[1]*12, 88 | v = 16/g64sprites.Dimensions.UI[2]*0, 89 | }, 90 | star = { 91 | w = 16, 92 | h = 16, 93 | u = 16/g64sprites.Dimensions.UI[1]*13, 94 | v = 16/g64sprites.Dimensions.UI[2]*0, 95 | } 96 | } 97 | 98 | g64sprites.Health = { 99 | tex_width = g64sprites.Dimensions.Health[1], 100 | tex_height = g64sprites.Dimensions.Health[2], 101 | bg_0 = { 102 | w = 32, 103 | h = 64, 104 | u = 64/g64sprites.Dimensions.Health[1]*0, 105 | v = 64/g64sprites.Dimensions.Health[2]*0, 106 | }, 107 | bg_1 = { 108 | w = 32, 109 | h = 64, 110 | u = 64/g64sprites.Dimensions.Health[1]*1, 111 | v = 64/g64sprites.Dimensions.Health[2]*0, 112 | }, 113 | wedge_8 = { 114 | w = 32, 115 | h = 64, 116 | u = 64/g64sprites.Dimensions.Health[1]*2, 117 | v = 64/g64sprites.Dimensions.Health[2]*0, 118 | }, 119 | wedge_7 = { 120 | w = 32, 121 | h = 64, 122 | u = 64/g64sprites.Dimensions.Health[1]*3, 123 | v = 64/g64sprites.Dimensions.Health[2]*0, 124 | }, 125 | wedge_6 = { 126 | w = 32, 127 | h = 64, 128 | u = 64/g64sprites.Dimensions.Health[1]*4, 129 | v = 64/g64sprites.Dimensions.Health[2]*0, 130 | }, 131 | wedge_5 = { 132 | w = 32, 133 | h = 64, 134 | u = 64/g64sprites.Dimensions.Health[1]*5, 135 | v = 64/g64sprites.Dimensions.Health[2]*0, 136 | }, 137 | wedge_4 = { 138 | w = 32, 139 | h = 64, 140 | u = 64/g64sprites.Dimensions.Health[1]*6, 141 | v = 64/g64sprites.Dimensions.Health[2]*0, 142 | }, 143 | wedge_3 = { 144 | w = 32, 145 | h = 64, 146 | u = 64/g64sprites.Dimensions.Health[1]*7, 147 | v = 64/g64sprites.Dimensions.Health[2]*0, 148 | }, 149 | wedge_2 = { 150 | w = 32, 151 | h = 64, 152 | u = 64/g64sprites.Dimensions.Health[1]*8, 153 | v = 64/g64sprites.Dimensions.Health[2]*0, 154 | }, 155 | wedge_1 = { 156 | w = 32, 157 | h = 64, 158 | u = 64/g64sprites.Dimensions.Health[1]*9, 159 | v = 64/g64sprites.Dimensions.Health[2]*0, 160 | }, 161 | one_up = { 162 | w = 32, 163 | h = 64, 164 | u = 64/g64sprites.Dimensions.Health[1]*10, 165 | v = 64/g64sprites.Dimensions.Health[2]*0, 166 | }, 167 | } 168 | 169 | g64sprites.Characters = { 170 | ["0"] = g64sprites.UI.num_0, 171 | ["1"] = g64sprites.UI.num_1, 172 | ["2"] = g64sprites.UI.num_2, 173 | ["3"] = g64sprites.UI.num_3, 174 | ["4"] = g64sprites.UI.num_4, 175 | ["5"] = g64sprites.UI.num_5, 176 | ["6"] = g64sprites.UI.num_6, 177 | ["7"] = g64sprites.UI.num_7, 178 | ["8"] = g64sprites.UI.num_8, 179 | ["9"] = g64sprites.UI.num_9 180 | } -------------------------------------------------------------------------------- /lua/includes/g64_utils.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | MAP_GEO_CACHE_VERSION = 1 4 | 5 | g64utils = {} 6 | 7 | g64utils.MarioHasFlag = function(mask, flag) 8 | if mask == nil or flag == nil then return false end 9 | return (bit.band(mask, flag) != 0) 10 | end 11 | 12 | if CLIENT then 13 | g64utils.MarioRT = GetRenderTargetEx("Mario_Texture", 1024, 64, RT_SIZE_OFFSCREEN, MATERIAL_RT_DEPTH_NONE, 0, 0, IMAGE_FORMAT_RGBA8888) 14 | g64utils.MarioLightingMat = CreateMaterial("g64/libsm64_mario_lighting", "VertexLitGeneric", { 15 | ["$model"] = "1", 16 | ["$basetexture"] = "vgui/white", 17 | ["$receiveflashlight"] = "1", 18 | Proxies = { 19 | ["Clamp"] = { min="0.0", max="1.0", srcVar1="$color2", resultVar="$color2" }, 20 | } 21 | }) 22 | g64utils.MarioVertsMat = CreateMaterial("g64/libsm64_mario_verts", "UnlitGeneric", { 23 | ["$model"] = "1", 24 | ["$basetexture"] = "vgui/white", 25 | ["$vertexcolor"] = "1", 26 | ["$receiveflashlight"] = "1", 27 | }) 28 | g64utils.MarioTexMat = CreateMaterial("g64/libsm64_mario_tex", "VertexLitGeneric", { 29 | ["$model"] = "1", 30 | ["$basetexture"] = g64utils.MarioRT:GetName(), 31 | ["$decal"] = "1", 32 | ["$translucent"] = "1", 33 | ["$receiveflashlight"] = "1", 34 | }) 35 | g64utils.MarioWingsMat = CreateMaterial("g64/libsm64_mario_wings", "VertexLitGeneric", { 36 | ["$model"] = "1", 37 | ["$basetexture"] = g64utils.MarioRT:GetName(), 38 | ["$alphatest"] = "1", 39 | ["$nocull"] = "1", 40 | ["$receiveflashlight"] = "1", 41 | }) 42 | g64utils.DebugMat = CreateMaterial("g64/libsm64_debug", "UnlitGeneric", { 43 | ["$model"] = "1", 44 | ["$basetexture"] = "vgui/white", 45 | ["$decal"] = "1", 46 | ["$vertexcolor"] = "1" 47 | }) 48 | g64utils.WhiteMat = CreateMaterial("g64/libsm64_white", "UnlitGeneric", { 49 | ["$model"] = "1", 50 | ["$basetexture"] = "vgui/white", 51 | ["$translucent"] = "1", 52 | }) 53 | g64utils.MetalMat = Material("debug/env_cubemap_model") 54 | 55 | g64utils.CoinRT = GetRenderTargetEx("Coin_Texture", 128, 32, RT_SIZE_OFFSCREEN, MATERIAL_RT_DEPTH_NONE, 0, 0, IMAGE_FORMAT_RGBA8888) 56 | g64utils.CoinMat = CreateMaterial("g64/libsm64_coin", "UnlitGeneric", { 57 | ["$basetexture"] = g64utils.CoinRT:GetName(), 58 | ["$alphatest"] = "1", 59 | ["$vertexcolor"] = "1" 60 | }) 61 | 62 | g64utils.UIRT = GetRenderTargetEx("UI_Texture", 256, 16, RT_SIZE_OFFSCREEN, MATERIAL_RT_DEPTH_NONE, bit.bor(1, 4, 8), 0, IMAGE_FORMAT_RGBA8888) 63 | g64utils.UIMat = CreateMaterial("g64/libsm64_ui", "UnlitGeneric", { 64 | ["$basetexture"] = g64utils.UIRT:GetName(), 65 | ["$translucent"] = "1", 66 | ["$vertexcolor"] = "1" 67 | }) 68 | 69 | g64utils.HealthRT = GetRenderTargetEx("Health_Texture", 1024, 64, RT_SIZE_OFFSCREEN, MATERIAL_RT_DEPTH_NONE, bit.bor(1, 4, 8), 0, IMAGE_FORMAT_RGBA8888) 70 | g64utils.HealthMat = CreateMaterial("g64/libsm64_health", "UnlitGeneric", { 71 | ["$basetexture"] = g64utils.HealthRT:GetName(), 72 | ["$vertexalpha"] = "1", 73 | ["$vertexcolor"] = "1" 74 | }) 75 | 76 | g64utils.ParticleRT = GetRenderTargetEx("Particle_Texture", 256, 32, RT_SIZE_OFFSCREEN, MATERIAL_RT_DEPTH_NONE, bit.bor(1, 4, 8), 0, IMAGE_FORMAT_RGBA8888) 77 | g64utils.ParticleMat = CreateMaterial("g64/libsm64_particle", "UnlitGeneric", { 78 | ["$basetexture"] = g64utils.ParticleRT:GetName(), 79 | ["$vertexalpha"] = "1", 80 | ["$vertexcolor"] = "1" 81 | }) 82 | g64utils.BubbleMat = CreateMaterial("g64/libsm64_bubble", "UnlitGeneric", { 83 | ["$basetexture"] = g64utils.ParticleRT:GetName(), 84 | ["$vertexalpha"] = "1", 85 | ["$vertexcolor"] = "1" 86 | }) 87 | 88 | -- A mask of just Marios 89 | g64utils.MarioTargetRT = GetRenderTarget("G64_MARIO_TARGET", ScrW(), ScrH()) 90 | g64utils.MarioTargetMat = CreateMaterial("g64/libsm64_mario_target", "UnlitGeneric", { 91 | ["$basetexture"] = g64utils.MarioTargetRT:GetName(), 92 | ["$vertexalpha"] = "1", 93 | ["$alpha"] = "0.5" 94 | }) 95 | 96 | -- What's shown after opaque objects have been rendered 97 | g64utils.FramebufferRT = GetRenderTarget("G64_FB", ScrW(), ScrH()) 98 | g64utils.FramebufferMat = CreateMaterial("g64/libsm64_framebuffer", "UnlitGeneric", { 99 | ["$basetexture"] = g64utils.FramebufferRT:GetName(), 100 | ["$vertexalpha"] = "1", 101 | ["$alpha"] = "1" 102 | }) 103 | 104 | systimetimers.Create("G64_CHECK_FOR_CLEARED_RTS", 1, 0, function() 105 | render.PushRenderTarget(g64utils.MarioRT) 106 | render.CapturePixels() 107 | local r, g, b = render.ReadPixel(44,8) 108 | render.PopRenderTarget() 109 | if r == 0 then 110 | g64utils.LoadTextures() 111 | end 112 | end) 113 | 114 | hook.Add("PostDrawOpaqueRenderables", "G64_COPY_FRAMEBUFFER", function(bDrawingDepth, bDrawingSkybox, isDraw3DSkybox) 115 | render.SetWriteDepthToDestAlpha(false) 116 | render.CopyRenderTargetToTexture(g64utils.FramebufferRT) -- Used for vanish cap translucency 117 | 118 | render.PushRenderTarget(g64utils.MarioTargetRT) 119 | render.OverrideAlphaWriteEnable(true, true) 120 | render.ClearDepth() 121 | render.Clear(0,0,0,0) 122 | render.OverrideAlphaWriteEnable(false) 123 | render.PopRenderTarget() 124 | end) 125 | hook.Add("PostDrawTranslucentRenderables", "G64_OVERLAY_FRAMEBUFFER", function(bDrawingDepth, bDrawingSkybox, isDraw3DSkybox) 126 | -- Overlay a translucent image of opaque entites that have been rendered under Mario 127 | render.SetWriteDepthToDestAlpha(false) 128 | render.PushRenderTarget(g64utils.MarioTargetRT) 129 | cam.Start2D() 130 | render.OverrideBlend(true, BLEND_DST_COLOR, BLEND_SRC_ALPHA, BLENDFUNC_MIN) 131 | render.DrawTextureToScreen(g64utils.FramebufferRT) 132 | render.OverrideBlend(false) 133 | cam.End2D() 134 | render.PopRenderTarget() 135 | render.SetWriteDepthToDestAlpha(true) 136 | 137 | render.SetMaterial(g64utils.MarioTargetMat) 138 | render.DrawScreenQuad() 139 | end) 140 | hook.Remove("HUDPaint", "G64_PDPFDPFPDF") 141 | 142 | g64utils.IsChatOpen = false 143 | hook.Add("StartChat", "G64_ON_CHAT_OPEN", function(isTeamChat) 144 | g64utils.IsChatOpen = true 145 | end) 146 | hook.Add("FinishChat", "G64_ON_CHAT_CLOSE", function() 147 | g64utils.IsChatOpen = false 148 | end) 149 | hook.Add("OnScreenSizeChanged", "G64_SCREEN_SIZE_CHANGED", function(ow, oh) 150 | timer.Create("G64_DELAY_RELOAD_TEX", 0, 1, g64utils.LoadTextures) 151 | end) 152 | --hook.Add("HUDPaint", "G64_PDPFDPFPDF", function() 153 | -- local rt = g64utils.MarioRT 154 | -- render.DrawTextureToScreenRect(rt, 0, 0, rt:Width(), rt:Height()) 155 | --end) 156 | 157 | g64utils.Inputs = {} 158 | g64utils.Inputs[1] = Vector() 159 | g64utils.Inputs[2] = false 160 | g64utils.Inputs[3] = false 161 | g64utils.Inputs[4] = false 162 | g64utils.Inputs[5] = false 163 | g64utils.GetInputTable = function() 164 | local inputs = g64utils.Inputs 165 | if input.IsButtonDown(GetConVar("g64_forward"):GetInt()) then 166 | inputs[1].z = -1 167 | elseif input.IsButtonDown(GetConVar("g64_back"):GetInt()) then 168 | inputs[1].z = 1 169 | else 170 | inputs[1].z = 0 171 | end 172 | if input.IsButtonDown(GetConVar("g64_moveleft"):GetInt()) then 173 | inputs[1].x = -1 174 | elseif input.IsButtonDown(GetConVar("g64_moveright"):GetInt()) then 175 | inputs[1].x = 1 176 | else 177 | inputs[1].x = 0 178 | end 179 | -- Normalize joystick inputs 180 | local mag = math.sqrt((inputs[1].x * inputs[1].x) + (inputs[1].z * inputs[1].z)) 181 | if mag > 0 then 182 | inputs[1].x = inputs[1].x / mag 183 | inputs[1].z = inputs[1].z / mag 184 | end 185 | 186 | if input.IsButtonDown(GetConVar("g64_jump"):GetInt()) then 187 | inputs[2] = true 188 | else 189 | inputs[2] = false 190 | end 191 | 192 | if input.IsButtonDown(GetConVar("g64_attack"):GetInt()) then 193 | inputs[3] = true 194 | else 195 | inputs[3] = false 196 | end 197 | 198 | if input.IsButtonDown(GetConVar("g64_duck"):GetInt()) then 199 | inputs[4] = true 200 | else 201 | inputs[4] = false 202 | end 203 | 204 | if input.IsButtonDown(GetConVar("g64_pickup"):GetInt()) or libsm64.GetGamepadButton("bButton") == true then 205 | inputs[5] = true 206 | inputs[3] = true 207 | else 208 | inputs[5] = false 209 | end 210 | 211 | return g64utils.Inputs 212 | end 213 | g64utils.GetZeroInputTable = function() 214 | local inputs = g64utils.Inputs 215 | inputs[1].z = 0 216 | inputs[1].x = 0 217 | inputs[2] = false 218 | inputs[3] = false 219 | inputs[4] = false 220 | 221 | return g64utils.Inputs 222 | end 223 | 224 | g64utils.WriteMapCache = function(filename, map, disp) 225 | if not file.Exists("g64/cache", "DATA") then 226 | file.CreateDir("g64/cache") 227 | end 228 | local filename = "g64/cache/" .. game:GetMap() .. "_cache.dat" 229 | local f = file.Open(filename, "wb", "DATA") 230 | 231 | -- File header 232 | f:WriteULong(MAP_GEO_CACHE_VERSION) 233 | f:WriteShort(libsm64.XDelta) 234 | f:WriteShort(libsm64.YDelta) 235 | f:WriteShort(libsm64.WorldMin.x) 236 | f:WriteShort(libsm64.WorldMin.y) 237 | f:WriteShort(libsm64.WorldMin.z) 238 | f:WriteShort(libsm64.WorldMax.x) 239 | f:WriteShort(libsm64.WorldMax.y) 240 | f:WriteShort(libsm64.WorldMax.z) 241 | f:WriteUShort(libsm64.XChunks) 242 | f:WriteUShort(libsm64.YChunks) 243 | f:WriteUShort(libsm64.XDispChunks) 244 | f:WriteUShort(libsm64.YDispChunks) 245 | 246 | -- Map geometry data 247 | for x=1, libsm64.XChunks, 1 do 248 | for y=1, libsm64.YChunks, 1 do 249 | local chunk = map[x][y] 250 | f:WriteULong(#chunk) 251 | for i=1, #chunk, 1 do 252 | local vert = chunk[i] 253 | f:WriteFloat(vert.x) 254 | f:WriteFloat(vert.y) 255 | f:WriteFloat(vert.z) 256 | end 257 | end 258 | end 259 | for x=1, libsm64.XDispChunks, 1 do 260 | for y=1, libsm64.YDispChunks, 1 do 261 | local chunk = disp[x][y] 262 | f:WriteULong(#chunk) 263 | for i=1, #chunk, 1 do 264 | local vert = chunk[i] 265 | f:WriteFloat(vert.x) 266 | f:WriteFloat(vert.y) 267 | f:WriteFloat(vert.z) 268 | end 269 | end 270 | end 271 | f:Close() 272 | end 273 | g64utils.LoadMapCache = function(filename) 274 | if not file.Exists(filename, "DATA") then return false end 275 | 276 | if libsm64.LoadMapCache(filename, MAP_GEO_CACHE_VERSION) == false then return false end 277 | libsm64.MapLoaded = true 278 | 279 | return true 280 | end 281 | 282 | g64utils.IsSpawnMenuOpen = function() 283 | if g_SpawnMenu:IsValid() and g_SpawnMenu:IsVisible() then 284 | return true 285 | end 286 | return false 287 | end 288 | 289 | g64utils.CreateTexture = function(textureData, rt, content_width) 290 | if textureData == nil then return end 291 | 292 | local TEX_WIDTH = rt:Width() 293 | local TEX_HEIGHT = rt:Height() 294 | local CONTENT_WIDTH = content_width 295 | local oldW = ScrW() 296 | local oldH = ScrH() 297 | local oldRT = render.GetRenderTarget() 298 | 299 | render.SetRenderTarget(rt) 300 | render.SetViewPort(0, 0, TEX_WIDTH, TEX_HEIGHT) 301 | render.Clear(0, 0, 0, 0) 302 | cam.Start2D() 303 | for i = 1, #textureData do 304 | surface.SetDrawColor(textureData[i][1], textureData[i][2], textureData[i][3], textureData[i][4]) 305 | surface.DrawRect(i%CONTENT_WIDTH, math.floor(i/CONTENT_WIDTH), 1, 1) 306 | end 307 | cam.End2D() 308 | render.SetRenderTarget(oldRT) 309 | render.SetViewPort(0, 0, oldW, oldH) 310 | end 311 | 312 | g64utils.WithinBounds = function(v1, v2, dist) 313 | local distSqr = dist * dist 314 | return v1:DistToSqr(v2) < distSqr 315 | end 316 | 317 | g64utils.RemoveFromClient = function(ent) 318 | net.Start("G64_REMOVEFROMCLIENT") 319 | net.WriteEntity(ent) 320 | net.SendToServer() 321 | end 322 | 323 | g64utils.GlobalTextureData = { 324 | Mario = nil, 325 | Coin = nil, 326 | UI = nil, 327 | Health = nil, 328 | Particle = nil 329 | } 330 | 331 | g64utils.LoadTextures = function() 332 | g64utils.CreateTexture(g64utils.GlobalTextureData.Mario, g64utils.MarioRT, 704) 333 | g64utils.CreateTexture(g64utils.GlobalTextureData.Coin, g64utils.CoinRT, 128) 334 | g64utils.CreateTexture(g64utils.GlobalTextureData.UI, g64utils.UIRT, 224) 335 | g64utils.CreateTexture(g64utils.GlobalTextureData.Health, g64utils.HealthRT, 704) 336 | g64utils.CreateTexture(g64utils.GlobalTextureData.Particle, g64utils.ParticleRT, 32) 337 | 338 | local matrix = Matrix() 339 | matrix:Scale(Vector(0.125, 1, 1)) 340 | g64utils.BubbleMat:SetMatrix("$basetexturetransform", matrix) 341 | end 342 | 343 | g64utils.GlobalInit = function() 344 | local romPath = GetConVar("g64_rompath"):GetString() 345 | if romPath == nil or romPath == "" then 346 | chat.AddText(Color(255,100,100), "[G64] ROM path is empty. Please specify a valid ROM path in the G64 settings.") 347 | return false 348 | end 349 | 350 | if not libsm64.IsGlobalInit() then 351 | g64utils.GlobalTextureData.Mario, 352 | g64utils.GlobalTextureData.Coin, 353 | g64utils.GlobalTextureData.UI, 354 | g64utils.GlobalTextureData.Health, 355 | g64utils.GlobalTextureData.Particle = libsm64.GlobalInit(romPath) 356 | if g64utils.GlobalTextureData.Mario == false then 357 | chat.AddText(Color(255, 100, 100), "[G64] Error loading ROM at `", romPath, "`. Please check if the file exists.") 358 | return false 359 | else 360 | g64utils.LoadTextures() 361 | return true 362 | end 363 | end 364 | end 365 | 366 | g64utils.FacingToForward = function(facing) 367 | return Vector(math.sin(facing), math.cos(math.pi*2 - facing), 0) 368 | end 369 | end 370 | 371 | hook.Call("G64UtilsInitialized") -------------------------------------------------------------------------------- /lua/includes/modules/systimetimers.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | SysTimeTimers b1.0 3 | 4 | Functions: 5 | - systimetimers.Adjust( string timerName, number timerDelay, number timerRepeat, function timerFunction, boolean pauseOnRun ) 6 | - .Check() - Does nothing, just like timer.Check ;( 7 | - .Create( string timerName, number timerDelay, number timerRepeat, function timerFunction, boolean pauseOnRun ) 8 | - .Destroy( string timerName ) 9 | - .Exists( string timerName ) 10 | - .GetQueue() - This contains all the timers with all their statuses and whatnot, don't modify these values unless you know what you're doing! 11 | - .Pause( string timerName ) 12 | - .Remove( string timerName ) 13 | - .RepsLeft( string timerName ) 14 | - .Resume( string timerName ) 15 | - .Simple( string timerName, function timerFunction ) 16 | - .Start( string timerName ) 17 | - .Stop( string timerName ) 18 | - .TimeLeft( string timerName ) 19 | - .Toggle( string timerName ) 20 | 21 | todo: 22 | - Better error handling 23 | - (M) make in C++ 24 | 25 | ]] 26 | 27 | AddCSLuaFile() -- ;( 28 | module("systimetimers", package.seeall) 29 | 30 | if SERVER then 31 | CreateConVar("stt_ignore_hibernation_warning", 0, bit.bor(FCVAR_ARCHIVE), "If set to 1, will not show a warning about hibernation on timer creation", 0, 1) 32 | end 33 | 34 | -- own 35 | 36 | systimetimers.Queue = { 37 | 38 | } 39 | 40 | function systimetimers.GetQueue() 41 | return systimetimers.Queue or {} 42 | end 43 | 44 | function systimetimers.Resume(timerName) 45 | if not timerName then ErrorNoHaltWithStack("[SysTimeTimers] You didn't specify a timer name!") return false end 46 | if not systimetimers.Queue[timerName] then ErrorNoHaltWithStack(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return false end 47 | 48 | if systimetimers.Queue[timerName]["Paused"] == false then 49 | return false -- Already running 50 | end 51 | 52 | systimetimers.Queue[timerName]["Paused"] = false 53 | 54 | return true 55 | end 56 | 57 | -- timer.* 58 | 59 | function systimetimers.Adjust(timerName, timerDelay, timerRepeat, timerFunction, pauseOnRun) 60 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 61 | if not systimetimers.Queue[timerName] then error(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return end 62 | 63 | timerDelay = timerDelay or systimetimers.Queue[timerName]["RunEvery"] 64 | timerRepeat = timerRepeat or systimetimers.Queue[timerName]["RunAmount"] 65 | timerFunction = timerFunction or systimetimers.Queue[timerName]["Func"] 66 | pauseOnRun = pauseOnRun or systimetimers.Queue[timerName]["Paused"] 67 | 68 | systimetimers.Create(timerName, timerDelay, timerRepeat, timerFunction, pauseOnRun) 69 | end 70 | 71 | function systimetimers.Check() -- Yes, when i said i will "Add all of the functions from timer.*", i seriously meant that. 72 | return 73 | end 74 | 75 | function systimetimers.Create(timerName, timerDelay, timerRepeat, timerFunction, pauseOnRun) 76 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 77 | if not timerDelay then error("[SysTimeTimers] You didn't specify a timer delay!") return end 78 | if not timerRepeat then error("[SysTimeTimers] You didn't specify a timer repeat amount (0 = Infinite)!") return end 79 | if not timerFunction then error("[SysTimeTimers] You didn't specify a timer function!") return end 80 | 81 | if timerRepeat <= 0 then timerRepeat = math.huge end 82 | 83 | systimetimers.Queue[timerName] = { 84 | ["RunEvery"] = math.Clamp(timerDelay, 0.01, math.huge), 85 | ["LastRun"] = SysTime(), 86 | ["RunAmount"] = timerRepeat, 87 | ["RunAmountTotal"] = 0, 88 | ["Paused"] = pauseOnRun or false, 89 | ["Func"] = timerFunction 90 | } 91 | 92 | if SERVER then 93 | if (GetConVar_Internal("stt_ignore_hibernation_warning"):GetString() ~= "1") and (GetConVar_Internal("sv_hibernate_think"):GetString() ~= "1") then 94 | ErrorNoHalt("[SysTimeTimers - WARN] Please ensure \"sv_hibernate_think\" is set to \"1\" as timers will not progress when the server is empty, you can also use stt_ignore_hibernation_warning 1 to disable this warning!") 95 | end 96 | end 97 | end 98 | 99 | function systimetimers.Destroy(timerName) 100 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 101 | if not systimetimers.Queue[timerName] then error(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return end 102 | 103 | table.Empty(systimetimers.Queue[timerName]) 104 | systimetimers.Queue[timerName] = nil 105 | collectgarbage("collect") 106 | end 107 | 108 | function systimetimers.Exists(timerName) 109 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 110 | return systimetimers.Queue[timerName] and true or false 111 | end 112 | 113 | function systimetimers.Pause(timerName) 114 | if not timerName then ErrorNoHaltWithStack("[SysTimeTimers] You didn't specify a timer name!") return false end 115 | if not systimetimers.Queue[timerName] then ErrorNoHaltWithStack(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return false end 116 | 117 | if systimetimers.Queue[timerName]["Paused"] == true then 118 | return false -- Already paused 119 | end 120 | 121 | systimetimers.Queue[timerName]["Paused"] = true 122 | 123 | return true 124 | end 125 | 126 | systimetimers.Remove = systimetimers.Destroy 127 | 128 | function systimetimers.RepsLeft(timerName) 129 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 130 | if not systimetimers.Queue[timerName] then error(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return end 131 | 132 | return systimetimers.Queue[timerName]["RunAmount"] - systimetimers.Queue[timerName]["RunAmountTotal"] 133 | end 134 | 135 | function systimetimers.Simple(timerDelay, timerFunction) 136 | if not timerDelay then error("[SysTimeTimers] You didn't specify a timer delay!") return end 137 | if not timerFunction then error("[SysTimeTimers] You didn't specify a timer function!") return end 138 | 139 | systimetimers.Create("_stt_simple_"..tostring(SysTime())..tostring(math.random()), timerDelay, 1, timerFunction, false) 140 | end 141 | 142 | function systimetimers.Start(timerName) 143 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 144 | 145 | if systimetimers.Queue[timerName] then 146 | systimetimers.Queue[timerName]["LastRun"] = SysTime() 147 | systimetimers.Queue[timerName]["RunAmountTotal"] = 0 148 | systimetimers.Queue[timerName]["Paused"] = false 149 | end 150 | 151 | return systimetimers.Queue[timerName] and true or false 152 | end 153 | 154 | function systimetimers.Stop(timerName) 155 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 156 | if not systimetimers.Queue[timerName] then ErrorNoHaltWithStack(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return false end 157 | if (systimetimers.Queue[timerName]["RunAmountTotal"] == 0) and (systimetimers.Queue[timerName]["Paused"] == true) then 158 | return false -- Already stopped 159 | end 160 | 161 | systimetimers.Queue[timerName]["LastRun"] = SysTime() 162 | systimetimers.Queue[timerName]["RunAmountTotal"] = 0 163 | systimetimers.Queue[timerName]["Paused"] = true 164 | 165 | return true 166 | end 167 | 168 | function systimetimers.TimeLeft(timerName) 169 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 170 | if not systimetimers.Queue[timerName] then error(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return end 171 | 172 | local timeleft_ = (systimetimers.Queue[timerName]["LastRun"] + systimetimers.Queue[timerName]["RunEvery"]) - SysTime() 173 | if systimetimers.Queue[timerName]["Paused"] == true then 174 | timeleft_ = -timeleft_ 175 | end 176 | 177 | return timeleft_ 178 | end 179 | 180 | function systimetimers.Toggle(timerName) 181 | if not timerName then error("[SysTimeTimers] You didn't specify a timer name!") return end 182 | if not systimetimers.Queue[timerName] then error(string.format("[SysTimeTimers] There is no timer named \"%s\"", tostring(timerName))) return end 183 | 184 | systimetimers.Queue[timerName]["Paused"] = (not systimetimers.Queue[timerName]["Paused"]) 185 | end 186 | 187 | local function systimetimers_doTimers() 188 | for k, v in pairs(systimetimers.Queue) do 189 | if not v["Paused"] == true then 190 | local nextRun = v["LastRun"] + v["RunEvery"] 191 | if SysTime() >= nextRun then 192 | v["LastRun"] = SysTime() 193 | v["RunAmountTotal"] = v["RunAmountTotal"] + 1 194 | 195 | local t_s, t_o = pcall(function() 196 | v["Func"]() 197 | end) 198 | 199 | if t_s ~= true then 200 | systimetimers.Destroy(k) 201 | ErrorNoHaltWithStack(string.format("SysTimeTimers Error: %s", tostring(t_o))) 202 | return 203 | end 204 | 205 | if v["RunAmountTotal"] >= v["RunAmount"] then 206 | systimetimers.Destroy(k) 207 | end 208 | end 209 | end 210 | end 211 | end 212 | 213 | hook.Add("Think", "_systimers_doTimers_", systimetimers_doTimers) 214 | 215 | concommand.Add("stt_dumptimers", function() 216 | print("SysTimeTimers:\n") 217 | PrintTable(systimetimers.GetQueue()) 218 | end, nil, "Shows all the timers along with their information") 219 | -------------------------------------------------------------------------------- /lua/weapons/gmod_tool/stools/g64surfacechanger.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile() 2 | 3 | include("includes/g64_types.lua") 4 | 5 | TOOL.Category = "G64" 6 | TOOL.Name = "#tool.g64surfacechanger.name" 7 | 8 | TOOL.Information = { { name = "left" } } 9 | 10 | TOOL.ClientConVar[ "g64surfacetype" ] = g64types.SM64SurfaceType.SURFACE_DEFAULT 11 | TOOL.ClientConVar[ "g64terraintype" ] = g64types.SM64TerrainType.TERRAIN_STONE 12 | 13 | local function SetSurfaceInfo( ply, ent, data ) 14 | if data.SurfaceType then ent.G64SurfaceType = data.SurfaceType end 15 | if data.TerrainType then ent.G64TerrainType = data.TerrainType end 16 | 17 | if SERVER then 18 | duplicator.StoreEntityModifier( ent, "g64_surfaceinfo", data ) 19 | 20 | local filter = RecipientFilter() 21 | filter:AddAllPlayers() 22 | net.Start("G64_CHANGESURFACEINFO") 23 | net.WriteEntity(ent) 24 | net.WriteInt(data.SurfaceType, 16) 25 | net.WriteUInt(data.TerrainType, 16) 26 | net.Send(filter) 27 | end 28 | end 29 | duplicator.RegisterEntityModifier( "g64_surfaceinfo", SetSurfaceInfo ) 30 | 31 | function TOOL:LeftClick( trace ) 32 | local ent = trace.Entity 33 | if IsValid( ent ) and (ent:IsPlayer() or ent == Entity(0)) then return end 34 | if SERVER and not util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) then return end 35 | if CLIENT then return true end 36 | 37 | local surf = self:GetClientNumber( "g64surfacetype", g64types.SM64SurfaceType.SURFACE_DEFAULT ) 38 | local terr = self:GetClientNumber( "g64terraintype", g64types.SM64TerrainType.TERRAIN_STONE ) 39 | 40 | SetSurfaceInfo( self:GetOwner(), ent, { SurfaceType = surf, TerrainType = terr } ) 41 | return true 42 | end 43 | 44 | function TOOL.BuildCPanel( CPanel ) 45 | 46 | CPanel:AddControl( "Header", { Description = "#tool.g64surfacechanger.desc" } ) 47 | 48 | CPanel:AddControl( "ListBox", { Label = "#tool.g64surfacechanger.surf", Options = list.Get( "SurfaceTypes" ) } ) 49 | CPanel:AddControl( "ListBox", { Label = "#tool.g64surfacechanger.terr", Options = list.Get( "TerrainTypes" ) } ) 50 | 51 | end 52 | 53 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.stone", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_STONE } ) 54 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.grass", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_GRASS } ) 55 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.snow", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_SNOW } ) 56 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.sand", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_SAND } ) 57 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.spooky", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_SPOOKY } ) 58 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.water", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_WATER } ) 59 | list.Set( "TerrainTypes", "#tool.g64surfacechanger.slide", { g64surfacechanger_g64terraintype = g64types.SM64TerrainType.TERRAIN_SLIDE } ) 60 | 61 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.default", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_DEFAULT } ) 62 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.burning", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_BURNING } ) 63 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.hangable", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_HANGABLE } ) 64 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.slow", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_SLOW } ) 65 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.very_slippery", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_VERY_SLIPPERY } ) 66 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.slippery", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_SLIPPERY } ) 67 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.not_slippery", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_NOT_SLIPPERY } ) 68 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.shallow_quicksand", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_SHALLOW_QUICKSAND } ) 69 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.quicksand", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_QUICKSAND } ) 70 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.deep_quicksand", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_DEEP_QUICKSAND } ) 71 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.instant_quicksand", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_INSTANT_QUICKSAND } ) 72 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.ice", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_ICE } ) 73 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.hard", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_HARD } ) 74 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.hard_slippery", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_HARD_SLIPPERY } ) 75 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.hard_very_slippery", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_HARD_VERY_SLIPPERY } ) 76 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.hard_not_slippery", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_HARD_NOT_SLIPPERY } ) 77 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.vertical_wind", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_VERTICAL_WIND } ) 78 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.horizontal_wind", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_HORIZONTAL_WIND } ) 79 | list.Set( "SurfaceTypes", "#tool.g64surfacechanger.noise_default", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_NOISE_DEFAULT } ) 80 | --list.Set( "SurfaceTypes", "#tool.g64surfacechanger.vanish_cap_walls", { g64surfacechanger_g64surfacetype = g64types.SM64SurfaceType.SURFACE_VANISH_CAP_WALLS } ) -------------------------------------------------------------------------------- /materials/vgui/entities/g64_blankicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_blankicon.png -------------------------------------------------------------------------------- /materials/vgui/entities/g64_blankicon.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "vgui/entities/g64_blankicon" 4 | "$vertexcolor" 1 5 | "$vertexalpha" 1 6 | "$nolod" 1 7 | } 8 | -------------------------------------------------------------------------------- /materials/vgui/entities/g64_blankicon.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_blankicon.vtf -------------------------------------------------------------------------------- /materials/vgui/entities/g64_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_mario.png -------------------------------------------------------------------------------- /materials/vgui/entities/g64_mario.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_mario.psd -------------------------------------------------------------------------------- /materials/vgui/entities/g64_mario.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "vgui/entities/g64_mario" 4 | "$vertexcolor" 1 5 | "$vertexalpha" 1 6 | "$nolod" 1 7 | } 8 | -------------------------------------------------------------------------------- /materials/vgui/entities/g64_mario.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_mario.vtf -------------------------------------------------------------------------------- /materials/vgui/entities/g64_metalcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_metalcap.png -------------------------------------------------------------------------------- /materials/vgui/entities/g64_metalcap.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_metalcap.psd -------------------------------------------------------------------------------- /materials/vgui/entities/g64_metalcap.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "vgui/entities/g64_metalcap" 4 | "$vertexcolor" 1 5 | "$vertexalpha" 1 6 | "$nolod" 1 7 | } 8 | -------------------------------------------------------------------------------- /materials/vgui/entities/g64_metalcap.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_metalcap.vtf -------------------------------------------------------------------------------- /materials/vgui/entities/g64_vanishcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_vanishcap.png -------------------------------------------------------------------------------- /materials/vgui/entities/g64_vanishcap.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_vanishcap.psd -------------------------------------------------------------------------------- /materials/vgui/entities/g64_vanishcap.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "vgui/entities/g64_vanishcap" 4 | "$vertexcolor" 1 5 | "$vertexalpha" 1 6 | "$nolod" 1 7 | } 8 | -------------------------------------------------------------------------------- /materials/vgui/entities/g64_vanishcap.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_vanishcap.vtf -------------------------------------------------------------------------------- /materials/vgui/entities/g64_wingcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_wingcap.png -------------------------------------------------------------------------------- /materials/vgui/entities/g64_wingcap.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_wingcap.psd -------------------------------------------------------------------------------- /materials/vgui/entities/g64_wingcap.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "vgui/entities/g64_wingcap" 4 | "$vertexcolor" 1 5 | "$vertexalpha" 1 6 | "$nolod" 1 7 | } 8 | -------------------------------------------------------------------------------- /materials/vgui/entities/g64_wingcap.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/entities/g64_wingcap.vtf -------------------------------------------------------------------------------- /materials/vgui/radial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/radial.png -------------------------------------------------------------------------------- /materials/vgui/radial.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "vgui/radial" 4 | "$alphatest" 1 5 | "$allowalphatocoverage" 1 6 | "$alpha" 0.9 7 | } 8 | -------------------------------------------------------------------------------- /materials/vgui/radial.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/materials/vgui/radial.vtf -------------------------------------------------------------------------------- /particles/sm64.pcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckosmic/g64/6de9c9eab3e4985524549f756276223a2b5e1554/particles/sm64.pcf --------------------------------------------------------------------------------