From bafd8e0ecf89e0958ebf1ee36025e3575deed630 Mon Sep 17 00:00:00 2001 From: _bryan Date: Mon, 16 Jan 2023 22:00:58 +0100 Subject: [PATCH] first --- .gitignore | 2 + assets/master.fgd | 589 ++++++++++++++++++++++++ assets/meshes/maps/autosave/test.1.map | 50 ++ assets/meshes/maps/test.map | 20 + assets/models/arrangements/arrange1.glb | Bin 0 -> 7280 bytes assets/models/missing.glb | Bin 0 -> 6692 bytes assets/textures/generic_bricks.png | Bin 0 -> 695 bytes assets/textures/generic_noise.png | Bin 0 -> 4464 bytes assets/textures/generic_tiles.png | Bin 0 -> 631 bytes assets/textures/missing.png | Bin 0 -> 22784 bytes source/__main__.py | 55 +++ source/map/__init__.py | 0 source/map/csg.py | 11 + source/map/file.py | 124 +++++ 14 files changed, 851 insertions(+) create mode 100644 .gitignore create mode 100644 assets/master.fgd create mode 100644 assets/meshes/maps/autosave/test.1.map create mode 100644 assets/meshes/maps/test.map create mode 100644 assets/models/arrangements/arrange1.glb create mode 100644 assets/models/missing.glb create mode 100644 assets/textures/generic_bricks.png create mode 100644 assets/textures/generic_noise.png create mode 100644 assets/textures/generic_tiles.png create mode 100644 assets/textures/missing.png create mode 100644 source/__main__.py create mode 100644 source/map/__init__.py create mode 100644 source/map/csg.py create mode 100644 source/map/file.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..282320c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +raw/ \ No newline at end of file diff --git a/assets/master.fgd b/assets/master.fgd new file mode 100644 index 0000000..34525c3 --- /dev/null +++ b/assets/master.fgd @@ -0,0 +1,589 @@ +// +// Quake game definition file (.fgd) +// for Worldcraft 1.6 and above +// +// written by autolycus / autolycus@planetquake.com +// email me with improvements and suggestions +// + +// Modified by CZG : grawert@online.no : http://www.planetquake.com/greyvoid/ +// further modified by various authors + +// +// worldspawn +// + +@SolidClass = worldspawn : "World entity" +[ + message(string) : "Text on entering the world" + worldtype(choices) : "Ambience" : 0 = + [ + 0 : "Medieval" + 1 : "Metal (runic)" + 2 : "Base" + ] + sounds(integer) : "CD track to play" : 0 + light(integer) : "Ambient light" + _sunlight(integer) : "Sunlight" + _sun_mangle(string) : "Sun mangle (Yaw pitch roll)" +] + +// +// base marker definitions +// + +@baseclass = Angle [ angle(integer) : "Direction" ] + +@baseclass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not on Easy" : 0 + 512 : "Not on Normal" : 0 + 1024 : "Not on Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + ] +] + +@baseclass = Targetname [ targetname(target_source) : "Name" ] +@baseclass = Target [ + target(target_destination) : "Target" + killtarget(target_destination) : "Killtarget" +] + + + +// +// player starts, deathmatch, coop, teleport +// + +@baseclass base(Appearflags) size(-16 -16 -24, 16 16 32) + color(0 255 0) model({ "path": ":progs/player.mdl" }) = PlayerClass [] + +@PointClass base(PlayerClass) = info_player_start : "Player 1 start" [] +@PointClass base(PlayerClass) = info_player_coop : "Player cooperative start" [] +@PointClass base(PlayerClass) = info_player_start2 : "Player episode return point" [] +@PointClass base(PlayerClass) = info_player_deathmatch : "Deathmatch start" [] +@PointClass base(PlayerClass) = testplayerstart : "Testing player start" [] +@PointClass size(-32 -32 0, 32 32 64) base(PlayerClass, Targetname) = info_teleport_destination : "Teleporter destination" [] +@PointClass color(200 150 150) = info_null : "info_null (spotlight target)" +[ + targetname(target_source) : "Name" +] + +@PointClass base(Appearflags, Target, Targetname) color(200 150 150) = info_notnull : "Wildcard entity" // I love you +[ + use(string) : "self.use" + think(string) : "self.think" + nextthink(integer) : "nextthink" + noise(string) : "noise" + touch(string) : "self.touch" +] +@PointClass base(Appearflags) = info_intermission : "Intermission camera" +[ + mangle(string) : "Camera angle (Pitch Yaw Roll)" +] + +// +// items +// +@baseclass base(Appearflags, Target, Targetname) = Item +[ + message(string) : "Message" + target(string) : "Target" + killtarget(string) : "Killtarget" + delay(integer) : "Delay" +] +@baseclass size(0 0 0, 32 32 56) color(80 0 200) base(Item) = Ammo +[ + spawnflags(flags) = + [ + 1 : "Large box" : 0 + ] +] + +@PointClass + base(Ammo) + model( + {{ + spawnflags & 1 -> ":maps/b_batt1.bsp", + ":maps/b_batt0.bsp" + }} + ) = + item_cells : "Thunderbolt ammo" [] + +@PointClass + base(Ammo) + model( + {{ + spawnflags & 1 -> ":maps/b_rock1.bsp", + ":maps/b_rock0.bsp" + }} + ) = + item_rockets : "Rockets" [] + +@PointClass + base(Ammo) + model( + {{ + spawnflags & 1 -> ":maps/b_shell1.bsp", + ":maps/b_shell0.bsp" + }} + ) = item_shells : "Shells" [] + +@PointClass + base(Ammo) + model( + {{ + spawnflags & 1 -> ":maps/b_nail1.bsp", + ":maps/b_nail0.bsp" + }} + ) = item_spikes : "Nailgun/Perforator ammo" [] + +@PointClass + size(0 0 0, 32 32 56) + base(Appearflags) + model( + {{ + spawnflags & 2 -> ":maps/b_bh100.bsp", + spawnflags & 1 -> ":maps/b_bh10.bsp", + ":maps/b_bh25.bsp" + }} + ) = + item_health : "Health pack" +[ + spawnflags(flags) = + [ + 1 : "Rotten" : 0 + 2 : "Megahealth" : 0 + ] +] + +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/suit.mdl" }) = + item_artifact_envirosuit : "Environmental protection suit" [] +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/quaddama.mdl" }) = + item_artifact_super_damage : "Quad damage" [] +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/invulner.mdl" }) = + item_artifact_invulnerability : "Pentagram of Protection" [] +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/invisibl.mdl" }) = + item_artifact_invisibility : "Ring of Shadows" [] + +@PointClass size(-16 -16 0, 16 16 56) base(Item, Appearflags) model({ "path": ":progs/armor.mdl", "skin": 2 }) = + item_armorInv : "Red armor (200%)" [] +@PointClass size(-16 -16 0, 16 16 56) base(Item, Appearflags) model({ "path": ":progs/armor.mdl", "skin": 1 }) = + item_armor2 : "Yellow armor (150%)" [] +@PointClass size(-16 -16 0, 16 16 56) base(Item, Appearflags) model({ "path": ":progs/armor.mdl" }) = + item_armor1 : "Green armor (100%)" [] +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/w_s_key.mdl" }) = + item_key1 : "Silver key" [] +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/w_g_key.mdl" }) = + item_key2 : "Gold key" [] +@PointClass size(-16 -16 -24, 16 16 32) base(Item, Appearflags) model({ "path": ":progs/end1.mdl" }) = + item_sigil : "Sigil" +[ + spawnflags(Flags) = + [ + 1 : "Episode 1" : 1 + 2 : "Episode 2" : 0 + 4 : "Episode 3" : 0 + 8 : "Episode 4" : 0 + ] +] + +// +// weapons +// + +@baseclass size(-16 -16 0, 16 16 56) color(0 0 200) base(Item, Appearflags) = Weapon [] + +@PointClass base(Weapon) model({ "path": ":progs/g_shot.mdl" }) = weapon_supershotgun : "Double-barrelled shotgun" [] +@PointClass base(Weapon) model({ "path": ":progs/g_nail.mdl" }) = weapon_nailgun : "Nailgun" [] +@PointClass base(Weapon) model({ "path": ":progs/g_nail2.mdl" }) = weapon_supernailgun : "Super nailgun" [] +@PointClass base(Weapon) model({ "path": ":progs/g_rock.mdl" }) = weapon_grenadelauncher : "Grenade launcher" [] +@PointClass base(Weapon) model({ "path": ":progs/g_rock2.mdl" }) = weapon_rocketlauncher : "Rocket launcher" [] +@PointClass base(Weapon) model({ "path": ":progs/g_light.mdl" }) = weapon_lightning : "Thunderbolt" [] + +// +// monsters +// + +@baseclass base(Angle, Appearflags, Target, Targetname) color(220 0 0) = Monster +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + ] +] + +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/soldier.mdl" }) = monster_army : "Grunt" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 40) model({ "path": ":progs/dog.mdl" }) = monster_dog : "Nasty Doggie" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/ogre.mdl" }) = monster_ogre : "Ogre" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/ogre.mdl" }) = monster_ogre_marksman : "Ogre marksman" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/knight.mdl" }) = monster_knight : "Knight" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/hknight.mdl" }) = monster_hell_knight : "Hell knight" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/wizard.mdl" }) = monster_wizard : "Scrag" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/demon.mdl" }) = monster_demon1 : "Fiend" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/shambler.mdl" }) = monster_shambler : "Shambler" [] +@PointClass base(Monster) size(-128 -128 -24, 128 128 256) model({ "path": ":progs/boss.mdl" }) = monster_boss : "Chthon" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/enforcer.mdl" }) = monster_enforcer : "Enforcer" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/shalrath.mdl" }) = monster_shalrath : "Vore" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 24) model({ "path": ":progs/tarbaby.mdl" }) = monster_tarbaby : "Spawn" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 24) model({ "path": ":progs/fish.mdl" }) = monster_fish : "Rotfish" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 32) model({ "path": ":progs/oldone.mdl" }) = monster_oldone : "Shub-Niggurath" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 32) model({ "path": ":progs/zombie.mdl" }) = monster_zombie : "Zombie" +[ + spawnflags(Flags) = + [ + 1 : "Crucified" : 0 + 2 : "Ambush" : 0 + ] +] + +// +// lights +// + +@baseclass color(255 255 40) = Light [ + light(integer) : "Brightness" : 300 + wait(integer) : "Fade distance multiplier" : 1 + delay(choices) : "Attenuation" = + [ + 0 : "Linear falloff (Default)" + 1 : "Inverse distance falloff" + 2 : "Inverse distance squared" + 3 : "No falloff" + 4 : "Local minlight" + 5 : "Inverse distance squared B" + ] + mangle(string) : "Spotlight angle" + style(Choices) : "Appearance" : 0 = + [ + 0 : "Normal" + 10: "Fluorescent flicker" + 2 : "Slow, strong pulse" + 11: "Slow pulse, noblack" + 5 : "Gentle pulse" + 1 : "Flicker A" + 6 : "Flicker B" + 3 : "Candle A" + 7 : "Candle B" + 8 : "Candle C" + 4 : "Fast strobe" + 9 : "Slow strobe" + ] +] + +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname) = + light : "Invisible light source" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname) = + light_fluoro : "Fluorescent light" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname) = + light_fluorospark : "Sparking fluorescent light" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Appearflags, Light, Target, Targetname) model({ "path": "progs/s_light.spr" }) = + light_globe : "Globe light" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-8 -8 -12, 8 8 20) base(Appearflags, Light, Target, Targetname) model({ "path": ":progs/flame2.mdl" }) = + light_flame_large_yellow : "Large yellow flame" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-4 -4 -12, 4 4 20) base(Appearflags, Light, Target, Targetname) model({ "path": ":progs/flame2.mdl" }) = + light_flame_small_yellow : "Small yellow flame" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-4 -4 -12, 4 4 20) base(Appearflags, Light, Target, Targetname) model({ "path": ":progs/flame2.mdl" }) = + light_flame_small_white : "Small white flame" + [ + spawnflags(Flags) = [ 1 : "Start off" : 0 ] + ] +@PointClass size(-4 -4 -12, 4 4 20) base(Appearflags, Light, Target, Targetname) model({ "path": ":progs/flame.mdl" }) = + light_torch_small_walltorch : "Small walltorch" [] + +// +// misc +// + +@SolidClass base(Appearflags) = func_illusionary : "Static nonsolid model" [] + +@PointClass base(Appearflags) color(0 150 220) model({ "path": ":progs/s_bubble.spr" }) = air_bubbles : "Air bubbles" [] +@PointClass base(Appearflags, Targetname) = + event_lightning : "Chthon's lightning" [] +@PointClass base(Appearflags) model({ "path": ":progs/lavaball.mdl" }) = misc_fireball : "Small fireball" + [ speed(integer) : "Speed" : 40 ] +@PointClass base(Appearflags) size(0 0 0, 32 32 64) model({ "path": ":maps/b_explob.bsp" }) = misc_explobox : "Large exploding container" [] +@PointClass base(Appearflags) size(0 0 0, 32 32 32) model({ "path": ":maps/b_exbox2.bsp" }) = misc_explobox2 : "Small exploding container" [] +@PointClass base(Appearflags) size(-8 -8 -8, 8 8 8) model({ "path": ":progs/teleport.mdl" }) = misc_teleporttrain : "Flying teleporter destination" +[ + target(string) : "First stop target" + targetname(target_source) : "Name" +] +@PointClass base(Appearflags, Targetname) color(220 150 150) = trap_spikeshooter : "Triggered shooter" +[ + spawnflags(Flags) = + [ + 1 : "Spike" : 0 + 2 : "Laser" : 0 + ] +] +@PointClass base(Appearflags) color(220 150 150) = trap_shooter : "Continuous shooter" +[ + nextthink(integer) : "Delay before first spike" + wait(integer) : "Delay between spikes" + spawnflags(Flags) = + [ + 1 : "Spike" : 0 + 2 : "Laser" : 0 + ] +] + +@SolidClass = func_group : "Group of brushes for in-editor use" [] +@SolidClass = func_detail : "Group of brushes for certain compilers" [] +@SolidClass = func_detail_illusionary : "func_detail variant with no collision (players / monsters / gunfire) and doesn't split world faces." [] +@SolidClass = func_detail_wall : "func_detail variant that doesn't split world faces." [] + +// +// ambient sounds +// + +@PointClass base(Appearflags) color(150 0 150) = ambient_drip : "Dripping sound" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_drone : "Engine/machinery sound" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_comp_hum : "Computer background sounds" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_flouro_buzz : "Fluorescent buzzing sound" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_light_buzz : "Buzzing sound from light" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_suck_wind : "Wind sound" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_swamp1 : "Frogs croaking" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_swamp2 : "Frogs croaking B" [] +@PointClass base(Appearflags) color(150 0 150) = ambient_thunder : "Thunder sound" [] + +// +// moving things +// + + +@SolidClass base(Angle, Appearflags, Targetname, Target) = func_door : "Basic door" +[ + speed(integer) : "Speed" : 100 + sounds(choices) : "Sound" : 0 = + [ + 0: "Silent" + 1: "Stone" + 2: "Machine" + 3: "Stone Chain" + 4: "Screechy Metal" + ] + wait(string) : "Wait before close" : "3" + lip(integer) : "Lip" : 8 + dmg(integer) : "Damage inflicted when blocked" : 2 + message(string) : "Message if touched" + health(integer) : "Health (shootable)" : 0 + spawnflags(flags) = + [ + 1 : "Starts Open" : 0 + 4 : "Don't link" : 0 + 8 : "Gold Key required" : 0 + 16: "Silver Key required" : 0 + 32: "Toggle" : 0 + ] +] + +@SolidClass base(Appearflags, Targetname, Target) = func_door_secret : "Secret door" +[ + angle(integer) : "Direction of second move" + t_width(integer) : "First move length" + t_length(integer) : "Second move length" + dmg(integer) : "Damage when blocked" : 2 + wait(string) : "Wait before close" : "2" + sounds(choices) : "Sounds" : 3 = + [ + 1: "Medieval" + 2: "Metal" + 3: "Base" + ] + message(string) : "Message" + spawnflags(flags) = + [ + 1 : "Open once" : 0 + 2 : "Move left first" : 0 + 4 : "Move down first" : 0 + 8 : "Not shootable" : 0 + 16 : "Always shootable" : 0 + ] +] + +@SolidClass base(Appearflags, Targetname) = func_wall : "Wall, starts animation when triggered (if supporting texture)" [] + + +@SolidClass base(Angle, Appearflags, Targetname) = func_button : "Button" +[ + speed(integer) : "Speed" : 40 + lip(integer) : "Lip" : 4 + target(target_source) : "Target" + health(integer) : "Health (shootable)" + sounds(choices) : "Sounds" = + [ + 0 : "Steam metal" + 1 : "Wooden clunk" + 2 : "Metallic clink" + 3 : "In-out" + ] + wait(string) : "Wait before reset" : "1" + delay(string) : "Delay before trigger" + message(string) : "Message" +] + +@SolidClass base(Appearflags, Targetname) = func_train : "Moving platform" +[ + sounds(choices) : "Sound" : 1 = + [ + 0: "Silent" + 1: "Ratchet Metal" + ] + speed(integer) : "Speed (units per second)" : 64 + target(target_source) : "Target to start at" + dmg(integer) : "Damage on block" : 2 +] + +@PointClass base(Appearflags, Targetname) size(16 16 16) color(0 255 255) = + path_corner : "Waypoint for platforms and monsters" +[ + target(target_source) : "Next target" + wait(integer) : "Wait" : 0 +] + +@SolidClass base(Appearflags, Targetname) = func_plat : "Elevator" +[ + spawnflags(Flags) = + [ + 1 : "Low trigger volume" : 0 + ] + speed(integer) : "Speed" : 150 + height(integer) : "Travel altitude (can be negative)" : 0 + sounds(choices) : "Sound" : 1 = + [ + 0: "None" + 1: "Base fast" + 2: "Chain Slow" + ] +] + +@SolidClass base(Appearflags) = func_episodegate : "Episode Gate" +[ + spawnflags(Flags) = + [ + 1 : "Episode 1" : 1 + 2 : "Episode 2" : 0 + 4 : "Episode 3" : 0 + 8 : "Episode 4" : 0 + ] +] + +@SolidClass base(Appearflags) = func_bossgate : "Boss gate" [] + +// +// triggers +// + +@baseclass base(Appearflags, Target, Targetname) = Trigger +[ + sounds(choices) : "Sound style" : 0 = + [ + 0 : "None" + 1 : "Secret sound" + 2 : "Beep beep" + 3 : "Large switch" + ] + delay(string) : "Delay before trigger" : "0" + message(string) : "Message" +] + +@SolidClass base(Trigger) = trigger_changelevel : "Trigger: Change level" +[ + map(string) : "Next map" + target(target_destination) : "Target" + spawnflags(flags) = + [ + 1: "No intermission" : 0 + ] +] + +@SolidClass base(Trigger) = trigger_once : "Trigger: Activate once" +[ + health(integer) : "Health (shootable)" + spawnflags(flags) = [ 1: "Not touchable" : 0 ] +] +@SolidClass base(Trigger) = trigger_multiple : "Trigger: Activate multiple" +[ + wait(string) : "Wait before reset" : "0.2" + health(integer) : "Health (shootable)" + spawnflags(flags) = [ 1: "Not touchable" : 0 ] +] +@SolidClass base(Trigger) = trigger_onlyregistered : "Trigger: Registered only" +[ + spawnflags(flags) = [ 1: "Not touchable" : 0 ] +] +@SolidClass base(Trigger) = trigger_secret : "Trigger: Secret" +[ + sounds(choices) : "Sound" : 1 = + [ + 1 : "Secret sound" + 2 : "Beep beep" + ] + spawnflags(flags) = [ 1: "Not touchable" : 0 ] +] + +@SolidClass base(Appearflags, Target, Targetname) = trigger_teleport : "Trigger: Teleporter" +[ + spawnflags(Flags) = + [ + 1 : "Player only" : 0 + 2 : "Silent" : 0 + ] +] + +@SolidClass base(Appearflags) = trigger_setskill : "Trigger: Set skill" +[ + message(choices) : "Skill to change to" : 1 = + [ + 0 : "Easy" + 1 : "Medium" + 2 : "Hard" + 3 : "Nightmare!" + ] +] +@PointClass base(Trigger) = trigger_relay : "Trigger: Relay" +[ +] +@SolidClass base(Angle, Appearflags, Targetname) = trigger_monsterjump : "Trigger: Monster jump" +[ + speed(integer) : "Jump Speed" : 200 + height(integer) : "Jump Height" : 200 +] +@PointClass base(Appearflags, Target, Targetname) = trigger_counter : "Trigger: Counter" +[ + spawnflags(flags) = [ 1: "No Message" : 0 ] + count(integer) : "Count before trigger" : 2 + delay (integer) : "Delay" + message(string) : "Message" +] +@SolidClass base(Angle, Appearflags, Targetname) = trigger_push : "Trigger: Push" +[ + spawnflags(flags) = [ 1: "Push once" : 0 ] + speed(integer) : "Speed" : 1000 +] +@SolidClass base(Appearflags, Targetname) = trigger_hurt : "Trigger: Hurt" +[ + dmg(integer) : "Damage per second" : 5 +] +@PointClass size(16 16 16) = misc_noisemaker : "Debug entity: continuously plays enforcer sounds" [] +@PointClass size(16 16 16) = viewthing : "Debug entity: fake player model" [] \ No newline at end of file diff --git a/assets/meshes/maps/autosave/test.1.map b/assets/meshes/maps/autosave/test.1.map new file mode 100644 index 0000000..f6e3c25 --- /dev/null +++ b/assets/meshes/maps/autosave/test.1.map @@ -0,0 +1,50 @@ +// Game: Generic +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures" +"_tb_def" "external:master.fgd" +"integer" "10" +"floating" "10.248" +"string" "sfdoijsdf" +// brush 0 +{ +( 0 0 16 ) ( 0 -128 16 ) ( 0 -128 -16 ) generic_tiles 0 0 45 1 1 +( 0 -128 16 ) ( 128 -128 16 ) ( 128 -128 -16 ) generic_tiles 0 0 45 1 1 +( 128 -128 -16 ) ( 128 0 -16 ) ( 0 0 -16 ) generic_tiles 0 0 45 1 1 +( 0 0 16 ) ( 128 0 16 ) ( 128 -128 16 ) generic_tiles 0 0 45 1 1 +( 128 0 -16 ) ( 128 0 16 ) ( 0 0 16 ) generic_tiles 0 0 45 1 1 +( 128 -128 16 ) ( 128 0 16 ) ( 128 0 -16 ) generic_tiles 0 0 45 1 1 +} +// brush 1 +{ +( -384 384 0 ) ( -384 384 64 ) ( -384 -64 0 ) generic_tiles 0 0 45 1 1 +( -384 384 64 ) ( -285.39994983020347 52.87499999999663 64 ) ( -384 -64 0 ) generic_tiles 35.14084 11.834999 45 1 1 +( -285.39994983020347 52.87499999999663 64 ) ( -184.606925748656 -41.49999999956605 64 ) ( -384 -64 0 ) generic_tiles 35.14084 11.834999 45 1 1 +( -184.606925748656 -41.49999999956605 64 ) ( 0 -64 64 ) ( -384 -64 0 ) generic_tiles 0 1.4594574 45 1 1 +( -384 -64 0 ) ( 0 -64 64 ) ( 0 -64 0 ) generic_tiles 0 0 45 1 1 +( 0 -64 0 ) ( 0 384 0 ) ( -384 384 0 ) generic_tiles 0 0 45 1 1 +( -384 384 64 ) ( 0 384 64 ) ( 0 -64 64 ) generic_tiles 0 0 45 1 1 +( 0 384 0 ) ( 0 384 64 ) ( -384 384 64 ) generic_tiles 0 0 45 1 1 +( 0 -64 64 ) ( 0 384 64 ) ( 0 384 0 ) generic_tiles 0 0 45 1 1 +} +} +// entity 1 +{ +"classname" "air_bubbles" +"origin" "-136 168 72" +} +// entity 2 +{ +"classname" "func_detail" +// brush 0 +{ +( 0 -128 0 ) ( 0 -127 0 ) ( 0 -128 1 ) generic_tiles 0 0 45 1 1 +( 0 -128 0 ) ( 0 -128 1 ) ( 1 -128 0 ) generic_tiles 0 0 45 1 1 +( 0 -128 0 ) ( 1 -128 0 ) ( 0 -127 0 ) generic_tiles 0 0 45 1 1 +( 64 0 64 ) ( 64 1 64 ) ( 65 0 64 ) generic_tiles 0 0 45 1 1 +( 64 0 64 ) ( 65 0 64 ) ( 64 0 65 ) generic_tiles 0 0 45 1 1 +( 64 0 64 ) ( 64 0 65 ) ( 64 1 64 ) generic_tiles 0 0 45 1 1 +} +} diff --git a/assets/meshes/maps/test.map b/assets/meshes/maps/test.map new file mode 100644 index 0000000..2076835 --- /dev/null +++ b/assets/meshes/maps/test.map @@ -0,0 +1,20 @@ +// Game: Generic +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures" +"_tb_def" "external:master.fgd" +"integer" "10" +"floating" "10.248" +"string" "sfdoijsdf" +// brush 0 +{ +( -64 160 0 ) ( -64 161 0 ) ( -64 160 1 ) __TB_empty 0 -16 0 1 1 +( -64 160 0 ) ( -64 160 1 ) ( -63 160 0 ) __TB_empty 0 -16 0 1 1 +( -64 160 0 ) ( -63 160 0 ) ( -64 161 0 ) __TB_empty 0 0 0 1 1 +( -32 192 16 ) ( -32 193 16 ) ( -31 192 16 ) __TB_empty 0 0 0 1 1 +( -32 192 16 ) ( -31 192 16 ) ( -32 192 17 ) __TB_empty 0 -16 0 1 1 +( -32 192 16 ) ( -32 192 17 ) ( -32 193 16 ) __TB_empty 0 -16 0 1 1 +} +} diff --git a/assets/models/arrangements/arrange1.glb b/assets/models/arrangements/arrange1.glb new file mode 100644 index 0000000000000000000000000000000000000000..db60b6b0f1db358767b31664e4fd79b398c91b2d GIT binary patch literal 7280 zcmeHKO>9)x6+Qu6Ol<5x3MA#n&V%rm!OWZSjDMQOZ)`9zHl7GjS}7&XV8&*o@eCRd zZc`VPWvWDNDpt)Rb)=}-wYw&jTFpaQu<5RgWY<*}mAar(rL6k%eRt-}ocY1ns@Ubq z_nhzipL^fE&u^CUSEsj$$gM*nf9@8!cqKi*=4Dn^vSn|4&0ESAvZYM9Sn|fb*_)+e zp|~=*gpk3>e70~STN<1>n;u+^4-F3`qF%&X&6ZYj#R8mTLs9Qe#9LWF0&hH8Lo43+ z8*5%6vkaYg#n~cWp?D)pL;TvEYYl15Th6ZBbfGo>ls`0;&E<22C1h5!kBDkIn5Xka zblNb+tns^(e8Zu@}<hVtDPU)65 zf=#SdzcQ7YOI>cOk0-fN{TS?xy@|H$4duq-+PlNKcwF*Ec>CVCNA&3D#@-s??bSy* zRo}|qVDmO=e-!VT#@@7^o5$@9&hz7vHx}2vH$IAQKE8c({Ep|gu{(aU{pjFnH%`92 zX6}kzf4iKW%NCZ(c#XzK@ocC_FD|-wJGw1rN=tmr$A`y~cpI(Na<#?A5_s-5)+O6) zbX(=*@D^(Ot+oBAJ7uQz_(rXdV$*EvzRyFl+1~vzybYSdhuu>!)i>O@w(7~`R;stH zeQcO#z*OI8?PIKEn~(WXUQiRhQShY1SRFB77&fIXawL1Q1Vtwwv zO6};I^PY%Cqxdg0_|CH;lQZ-9!nqsPW&qAf*>cq@uNWU<)lV2bvFbx$D=VhHV*C`- zu0G_dCs#eO)gxEHdNrNH^i@4E>`o6I^Ek{H#ne}fUNP+J8Vg+$MvTitpBkoJ^EeC} zeQ4KO4kK3(oP6-^{gV&wrH*5gQ$Fq{b?@Gv{`pTs>d7gedhlz++)I&DrvGJUyO$!T zeAL5^|i-vinsPob5kr606kcEHvTsSmRoXg56iF{$r`)Q8!R zOufj$eA{Ika`l1s!T%ZAD+fUj%D3cz?32TwhvkrbQ})XM=ztuNXJwB(5Bj`3hl;$v zoE&!pgTty^*Td#8&QRT-SoIS|PptY77&3>;uef6L^jCcd3>$~@R}5a)!`I^Vz_~kJ z6Ao*7`15_hLA%B}3>ydS+JnQWC-U&6k^4V>FrE6x{tGE`%5ScX+^0-lm>meIC#RhI z>dk;MIc55v{n=nhe{%Yf(@swNCx5sW&`wS}Iqk~-IJM;JDF5;ot1dtJ#lNn)ICAE@ z_^(A*kDT#bLv`rdD1D7}PkL~Nw&MnF$4%t&idm{_x{){U{EM z-r^AY3Y;;Vzv95?Ee@-G0d*GFWT&^7K9KAFis{n{qdxOG|5mL2)GMAa{;k;hC=THd zzj{B4VXx~grhmowE2d8;jC|{`anRm`L#K9i)@zt{-G7G>&q2FBM~9J%gF5;Jn3}(i z!PaUFtbovC8BYhc(&i)Ta|iFZKMy>Vv-OdScawz*bgF zeZ}}WeBz6NO8EDm{OR|9doOs)@c;I|A5fn^HCCaXeqv z(dB8iQ%^hdz6Ji_+OH-oXMW0RpZxrYla*Wh$6x)s!u*!gPMQ6XGtat_X{XFSZJhd3 zPdoeUWT&2X=B1teTdwuh&c10^uJ+R({MM~s`QD|E+&Yzi|Cb*-S$X$AKXU%c8OOZJ z8An+;<0va<9A)L~@4f$=2)Tdn7|#Bv=YCL6KXR36r_6n#A30_23uSW3+!xEae#*+l z4ZXL@snk1O^{Ad{r^k7=L;aMi&B~frIejd4GVX&8wKe51_BQ{TP2*bat+M(lZ?!ww ztW*7zZ{%-%te;(r)!SM&*5XI{n?2bu{}bFFTi5p7giW7zy>067v^mv7_C^#vIR9haEAgm2XZXhOb&FWa;7GU&@Pj2eUT zD(I_n5i2+7sC7A{qLey!@OY%RRkO6D} literal 0 HcmV?d00001 diff --git a/assets/models/missing.glb b/assets/models/missing.glb new file mode 100644 index 0000000000000000000000000000000000000000..a9e749e450fb1cbdd500fd8e96270321a528f273 GIT binary patch literal 6692 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 literal 0 HcmV?d00001 diff --git a/assets/textures/generic_noise.png b/assets/textures/generic_noise.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb6d01b05baa342e562f8e5832f23b4acf4be58 GIT binary patch literal 4464 zcmV-$5s&VPP)0004nX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmP!xqvQ>7x64(%Y~kfAzR5EbbtRV;#q(pG5I!Q`cX(4-+r zad8w}3l9D)RvlcNb#-tR1i>E=R~IKm7b)?+q|hS93y=44-aUu+?gNBYjj3keB%o@R zkx3@Rd|_1#yuybNf(RonF;h=v7jy8euY2mIx{L8F@4i24NGX~O@QK88OgAjz4dU5N zOXs{#9AOnnAwDObFzABBk6f2se&bwrSm2ovBbS*cju4CG9+rEURScDQhB&II8s!Ul zmle)ioYh)`b?(Vu7%XZlS+3I>MG{L$Aq^2S8mOWM3o+U?QcPs%JmKLVar|j=$>gen zkz)aMsE`~#_#gb9ty!9$a+87yp#R0TKgNK-F3@h;_V=-Ew@(27GjOGK{q+_Q|0KQH z)uKm0XdAe=?rQQLaJd5vKk1SoIg+22P$~iMXY@@4Abbl9uDNsToa6KX$kD8pZ-9eC zV7yG(>mKhO=$+fYJ)Qae0FuaZw2GCqNdN!<32;bRa{vG?BLDy{BLR4&KXw2B00(qQ zO+^Ri0S^o_HjrJhu>b%78FWQhbVF}#ZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b z4_Qe>K~!koecIV}cvaa{5(xwX0c4i{ z`Okm0ZL6y4bUH1|@_N0hsw#@2D2lQytE$?zZCRGGEH9VKJkQIrR8`e9&A#u)aXcQ6 zwr%Hm9){sKj-n{mbzRr>d_Mcux~|oq&v6`0)7bqL`+M8ExA( zO>-Q_wrzD?v+DVL)^*LQs;bJej8)BX9931-b-gT0(=?~ksj8~y^Vu|wN4u`;`+l0H zaU9#W^^T$_x~_XZpXc+rEX&jBG|zKg*ZaQreQ(=kSw5f7%jHrOg||E&kK;JJ{&YGq zy{_wdo`3!NbsWdCEbF>*L|xZS)2!?2b-vDks;c_FFN)&zdNpNPTG76%s+y+ha=EPQ z%76Cen@sWIvMigX*|zOC4ld`jbzQe@^GarI+t#-2wr#iD?fHBP;Bg$saqz2vSi~#p zx@HyY>$;w%>DRAc;=itIQ54IvbX`~N`@XJg(=>Hmvw**YqPnizwq2IRLT%d~$FcAG zJkLz&`<}m$(Ik&DWZwcV*^%9L`S$rjA5R#bZ`TP6(`F#HV z{rh}A!}`AO_xpVq2G6`+FTrV==I7_fQu91tE*I&?aZu3reX}gfaU5OOZQCX&;Dt2U zJq!a+Ow%OGkK>r<+4h2p7=lA=)3a?2fJN5!=iALMDeghS@ zZDZm9NcIfD*Xwm0$7G~@Sl9LSdfjd}`?sKw3KTbq*uL*z3=7M$0CV`}&8i{-c|LO5 z(y9q(gP9!it*+~aVHk!1JW_i0eOD7X$O;y}Uaz6~ec$=GX&R4N6Up$bnER_uCd=!( zZlE^5Md$Wc{`tIKuWj4*eIJHF?Dl=H>sp;k^^sd;Sz6@rcw8$aL&%b~pPjUj$ab2^=xrm0x}d_JX}cp-|cBGu-3Ue}ci?T}-TMo|>c=Tmy| z>#twG7;T@)D4|fHeL#!W3f}m5nx@z5#ml5b^XDTVZ(k}miinh@J({LbfFRzw^E?9; ztozgR`5cA;6YwiONOc3SWm)Ws&ha6`{MAp4e7RiuzCWMOELNCpBa)=5>-zP2@#3;9 z(=V(n!j7e2FAwdqJTd1}uis-8<6(j;n_Yh@kQQoj1m!Uu^QmoBsP4#UbxtQ z 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 literal 0 HcmV?d00001 diff --git a/assets/textures/missing.png b/assets/textures/missing.png new file mode 100644 index 0000000000000000000000000000000000000000..dc8573bc8230122e874f55212e84344ec54cf399 GIT binary patch literal 22784 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 o$|@>RLc+o$twyrZ9=tU+$36